diff --git a/.DS_Store b/.DS_Store index 079ab741e1..12bc7971a4 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Firmware/BlinkM.cpp b/Firmware/BlinkM.cpp index de604ecd35..73c101e0be 100755 --- a/Firmware/BlinkM.cpp +++ b/Firmware/BlinkM.cpp @@ -6,23 +6,23 @@ #ifdef BLINKM #if (ARDUINO >= 100) - # include "Arduino.h" +# include "Arduino.h" #else - # include "WProgram.h" +# 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(); + 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(); } #endif //BLINKM diff --git a/Firmware/BlinkM.h b/Firmware/BlinkM.h index 5136828782..732000c7cb 100755 --- a/Firmware/BlinkM.h +++ b/Firmware/BlinkM.h @@ -3,9 +3,9 @@ Library header file for BlinkM library */ #if (ARDUINO >= 100) - # include "Arduino.h" +# include "Arduino.h" #else - # include "WProgram.h" +# include "WProgram.h" #endif #include "Wire.h" diff --git a/Firmware/Configuration.h b/Firmware/Configuration.h index 5d56e975bd..279da4aa75 100644 --- a/Firmware/Configuration.h +++ b/Firmware/Configuration.h @@ -7,8 +7,8 @@ #define STR(x) STR_HELPER(x) // Firmware version -#define FW_VERSION "5.0.2-TZB" -#define FW_COMMIT_NR 2234 +#define FW_VERSION "5.0.3-TZB" +#define FW_COMMIT_NR 2235 // FW_VERSION_UNKNOWN means this is an unofficial build. // The firmware should only be checked into github with this symbol. #define FW_DEV_VERSION FW_VERSION_UNKNOWN @@ -19,7 +19,7 @@ // The debug build may be a bit slower than the non-debug build, therefore the debug build should // not be shipped to a customer. #define FW_VERSION_DEBUG 6 -// This is a development build. A development build is either built from an unofficial git repository, +// This is a development build. A development build is either built from an unofficial git repository, // or from an unofficial branch, or it does not have a label set. Only the build server should set this build type. #define FW_VERSION_DEVEL 5 // This is an alpha release. Only the build server should set this build type. @@ -128,18 +128,18 @@ #define BANG_MAX 255 // limits current to nozzle while in bang-bang mode; 255=full current #define PID_MAX BANG_MAX // 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 SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay - #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 PID_MAX //limit for the integral term - #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 +//#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 SLOW_PWM_HEATERS // PWM with very low frequency (roughly 0.125Hz=8s) and minimum state time of approximately 1s useful for heaters driven by a relay +#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 PID_MAX //limit for the integral term +#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 - + // MakerGear // #define DEFAULT_Kp 7.0 @@ -175,15 +175,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. @@ -215,22 +215,22 @@ your extruder heater takes 2 minutes to hit the target on heating. #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 +// 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 +#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. @@ -243,7 +243,7 @@ your extruder heater takes 2 minutes to hit the target on heating. // Disable max endstops for compatibility with endstop checking routine #if defined(COREXY) && !defined(DISABLE_MAX_ENDSTOPS) - #define DISABLE_MAX_ENDSTOPS +#define DISABLE_MAX_ENDSTOPS #endif // For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1 @@ -276,7 +276,7 @@ your extruder heater takes 2 minutes to hit the target on heating. #define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS) -#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) +#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS) #define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS) #define Z_HEIGHT_HIDE_LIVE_ADJUST_MENU 2.0f @@ -300,58 +300,58 @@ your extruder heater takes 2 minutes to hit the target on heating. // 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 +#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 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 +// 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 +#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 +#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 // AUTO_BED_LEVELING_GRID - // these are the offsets to the probe relative to the extruder tip (Hotend - Probe) - // X and Y offsets must be integers - #define X_PROBE_OFFSET_FROM_EXTRUDER -25 - #define Y_PROBE_OFFSET_FROM_EXTRUDER -29 - #define Z_PROBE_OFFSET_FROM_EXTRUDER -12.35 +// these are the offsets to the probe relative to the extruder tip (Hotend - Probe) +// X and Y offsets must be integers +#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 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 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 +#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 - //#define Z_PROBE_SLED // turn on if you have a z-probe mounted on a sled like those designed by Charles Bell - //#define SLED_DOCKING_OFFSET 5 // the extra distance the X axis must travel to pickup the sled. 0 should be fine but you can push it further if you'd like. +//#define Z_PROBE_SLED // turn on if you have a z-probe mounted on a sled like those designed by Charles Bell +//#define SLED_DOCKING_OFFSET 5 // the extra distance the X axis must travel to pickup the sled. 0 should be fine but you can push it further if you'd like. - //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. +//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 @@ -359,43 +359,43 @@ your extruder heater takes 2 minutes to hit the target on heating. //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 - - #ifdef AUTO_BED_LEVELING_GRID // Check if Probe_Offset * Grid Points is greater than Probing Range - #if X_PROBE_OFFSET_FROM_EXTRUDER < 0 - #if (-(X_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION)) - #error "The X axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" - #endif - #else - #if ((X_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION)) - #error "The X axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" - #endif - #endif - #if Y_PROBE_OFFSET_FROM_EXTRUDER < 0 - #if (-(Y_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION)) - #error "The Y axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" - #endif - #else - #if ((Y_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION)) - #error "The Y axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" - #endif - #endif - - - #endif - +//#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 + +#ifdef AUTO_BED_LEVELING_GRID // Check if Probe_Offset * Grid Points is greater than Probing Range +#if X_PROBE_OFFSET_FROM_EXTRUDER < 0 +#if (-(X_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION)) +#error "The X axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" +#endif +#else +#if ((X_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (RIGHT_PROBE_BED_POSITION - LEFT_PROBE_BED_POSITION)) +#error "The X axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" +#endif +#endif +#if Y_PROBE_OFFSET_FROM_EXTRUDER < 0 +#if (-(Y_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION)) +#error "The Y axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" +#endif +#else +#if ((Y_PROBE_OFFSET_FROM_EXTRUDER * AUTO_BED_LEVELING_GRID_POINTS) >= (BACK_PROBE_BED_POSITION - FRONT_PROBE_BED_POSITION)) +#error "The Y axis probing range is not enough to fit all the points defined in AUTO_BED_LEVELING_GRID_POINTS" +#endif +#endif + + +#endif + #endif // ENABLE_AUTO_BED_LEVELING @@ -426,9 +426,9 @@ your extruder heater takes 2 minutes to hit the target on heating. // 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 +#define CUSTOM_M_CODE_SET_Z_PROBE_OFFSET 851 +#define Z_PROBE_OFFSET_RANGE_MIN -15 +#define Z_PROBE_OFFSET_RANGE_MAX -5 #endif @@ -515,24 +515,24 @@ your extruder heater takes 2 minutes to hit the target on heating. // (unsigned char*)EEPROM_CALIBRATION_STATUS enum CalibrationStatus { - // Freshly assembled, needs to peform a self-test and the XYZ calibration. - CALIBRATION_STATUS_ASSEMBLED = 255, + // Freshly assembled, needs to peform a self-test and the XYZ calibration. + CALIBRATION_STATUS_ASSEMBLED = 255, - // For the wizard: self test has been performed, now the XYZ calibration is needed. - CALIBRATION_STATUS_XYZ_CALIBRATION = 250, + // For the wizard: self test has been performed, now the XYZ calibration is needed. + CALIBRATION_STATUS_XYZ_CALIBRATION = 250, - // For the wizard: factory assembled, needs to run Z calibration. - CALIBRATION_STATUS_Z_CALIBRATION = 240, + // For the wizard: factory assembled, needs to run Z calibration. + CALIBRATION_STATUS_Z_CALIBRATION = 240, - // The XYZ calibration has been performed, now it remains to run the V2Calibration.gcode. - CALIBRATION_STATUS_LIVE_ADJUST = 230, + // The XYZ calibration has been performed, now it remains to run the V2Calibration.gcode. + CALIBRATION_STATUS_LIVE_ADJUST = 230, // Calibrated, ready to print. CALIBRATION_STATUS_CALIBRATED = 1, // Legacy: resetted by issuing a G86 G-code. // This value can only be expected after an upgrade from the initial MK2 firmware releases. - // Currently the G86 sets the calibration status to + // Currently the G86 sets the calibration status to CALIBRATION_STATUS_UNKNOWN = 0, }; diff --git a/Firmware/ConfigurationStore.cpp b/Firmware/ConfigurationStore.cpp index 2aafdd4430..f86fb16687 100755 --- a/Firmware/ConfigurationStore.cpp +++ b/Firmware/ConfigurationStore.cpp @@ -27,10 +27,10 @@ static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const c #endif //DEBUG_EEPROM_WRITE { #ifdef DEBUG_EEPROM_WRITE - printf_P(PSTR("EEPROM_WRITE_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name); + printf_P(PSTR("EEPROM_WRITE_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name); #endif //DEBUG_EEPROM_WRITE - while (size--) - { + while (size--) + { eeprom_update_byte(pos, *value); if (eeprom_read_byte(pos) != *value) { @@ -38,9 +38,9 @@ static bool EEPROM_writeData(uint8_t* pos, uint8_t* value, uint8_t size, const c return false; } - pos++; - value++; - } + pos++; + value++; + } return true; } @@ -51,7 +51,7 @@ static void EEPROM_readData(uint8_t* pos, uint8_t* value, uint8_t size, const ch #endif //DEBUG_EEPROM_READ { #ifdef DEBUG_EEPROM_READ - printf_P(PSTR("EEPROM_READ_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name); + printf_P(PSTR("EEPROM_READ_VAR addr=0x%04x size=0x%02hhx name=%s\n"), pos, size, name); #endif //DEBUG_EEPROM_READ while(size--) { @@ -66,102 +66,102 @@ static void EEPROM_readData(uint8_t* pos, uint8_t* value, uint8_t size, const ch #ifdef EEPROM_SETTINGS void Config_StoreSettings() { - strcpy(cs.version,"000"); //!< invalidate data first @TODO use erase to save one erase cycle - - if (EEPROM_writeData(reinterpret_cast(EEPROM_M500_base),reinterpret_cast(&cs),sizeof(cs),0), "cs, invalid version") - { - strcpy(cs.version,EEPROM_VERSION); //!< validate data if write succeed - EEPROM_writeData(reinterpret_cast(EEPROM_M500_base->version), reinterpret_cast(cs.version), sizeof(cs.version), "cs.version valid"); - } - - SERIAL_ECHO_START; - SERIAL_ECHOLNPGM("Settings Stored"); + strcpy(cs.version,"000"); //!< invalidate data first @TODO use erase to save one erase cycle + + if (EEPROM_writeData(reinterpret_cast(EEPROM_M500_base),reinterpret_cast(&cs),sizeof(cs),0), "cs, invalid version") + { + strcpy(cs.version,EEPROM_VERSION); //!< validate data if write succeed + EEPROM_writeData(reinterpret_cast(EEPROM_M500_base->version), reinterpret_cast(cs.version), sizeof(cs.version), "cs.version valid"); + } + + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("Settings Stored"); } #endif //EEPROM_SETTINGS #ifndef DISABLE_M503 void Config_PrintSettings(uint8_t level) -{ // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown +{ // Always have this function, even with EEPROM_SETTINGS disabled, the current values will be shown #ifdef TMC2130 - printf_P(PSTR( - "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n" - "%SMaximum feedrates - normal (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" - "%SMaximum feedrates - stealth (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" - "%SMaximum acceleration - normal (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n" - "%SMaximum acceleration - stealth (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n" - "%SAcceleration: S=acceleration, T=retract acceleration\n%S M204 S%.2f T%.2f\n" - "%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n" - "%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n" - ), - echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS], - echomagic, echomagic, cs.max_feedrate_normal[X_AXIS], cs.max_feedrate_normal[Y_AXIS], cs.max_feedrate_normal[Z_AXIS], cs.max_feedrate_normal[E_AXIS], - echomagic, echomagic, cs.max_feedrate_silent[X_AXIS], cs.max_feedrate_silent[Y_AXIS], cs.max_feedrate_silent[Z_AXIS], cs.max_feedrate_silent[E_AXIS], - echomagic, echomagic, cs.max_acceleration_units_per_sq_second_normal[X_AXIS], cs.max_acceleration_units_per_sq_second_normal[Y_AXIS], cs.max_acceleration_units_per_sq_second_normal[Z_AXIS], cs.max_acceleration_units_per_sq_second_normal[E_AXIS], - echomagic, echomagic, cs.max_acceleration_units_per_sq_second_silent[X_AXIS], cs.max_acceleration_units_per_sq_second_silent[Y_AXIS], cs.max_acceleration_units_per_sq_second_silent[Z_AXIS], cs.max_acceleration_units_per_sq_second_silent[E_AXIS], - echomagic, echomagic, cs.acceleration, cs.retract_acceleration, - echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS], - echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS] + printf_P(PSTR( + "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n" + "%SMaximum feedrates - normal (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" + "%SMaximum feedrates - stealth (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" + "%SMaximum acceleration - normal (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n" + "%SMaximum acceleration - stealth (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n" + "%SAcceleration: S=acceleration, T=retract acceleration\n%S M204 S%.2f T%.2f\n" + "%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n" + "%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n" + ), + echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS], + echomagic, echomagic, cs.max_feedrate_normal[X_AXIS], cs.max_feedrate_normal[Y_AXIS], cs.max_feedrate_normal[Z_AXIS], cs.max_feedrate_normal[E_AXIS], + echomagic, echomagic, cs.max_feedrate_silent[X_AXIS], cs.max_feedrate_silent[Y_AXIS], cs.max_feedrate_silent[Z_AXIS], cs.max_feedrate_silent[E_AXIS], + echomagic, echomagic, cs.max_acceleration_units_per_sq_second_normal[X_AXIS], cs.max_acceleration_units_per_sq_second_normal[Y_AXIS], cs.max_acceleration_units_per_sq_second_normal[Z_AXIS], cs.max_acceleration_units_per_sq_second_normal[E_AXIS], + echomagic, echomagic, cs.max_acceleration_units_per_sq_second_silent[X_AXIS], cs.max_acceleration_units_per_sq_second_silent[Y_AXIS], cs.max_acceleration_units_per_sq_second_silent[Z_AXIS], cs.max_acceleration_units_per_sq_second_silent[E_AXIS], + echomagic, echomagic, cs.acceleration, cs.retract_acceleration, + echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS], + echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS] #else //TMC2130 - printf_P(PSTR( - "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n" - "%SMaximum feedrates (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" - "%SMaximum acceleration (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n" - "%SAcceleration: S=acceleration, T=retract acceleration\n%S M204 S%.2f T%.2f\n" - "%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n" - "%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n" - ), - echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS], - echomagic, echomagic, max_feedrate[X_AXIS], max_feedrate[Y_AXIS], max_feedrate[Z_AXIS], max_feedrate[E_AXIS], - echomagic, echomagic, max_acceleration_units_per_sq_second[X_AXIS], max_acceleration_units_per_sq_second[Y_AXIS], max_acceleration_units_per_sq_second[Z_AXIS], max_acceleration_units_per_sq_second[E_AXIS], - echomagic, echomagic, cs.acceleration, cs.retract_acceleration, - echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS], - echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS] + printf_P(PSTR( + "%SSteps per unit:\n%S M92 X%.2f Y%.2f Z%.2f E%.2f\n" + "%SMaximum feedrates (mm/s):\n%S M203 X%.2f Y%.2f Z%.2f E%.2f\n" + "%SMaximum acceleration (mm/s2):\n%S M201 X%lu Y%lu Z%lu E%lu\n" + "%SAcceleration: S=acceleration, T=retract acceleration\n%S M204 S%.2f T%.2f\n" + "%SAdvanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)\n%S M205 S%.2f T%.2f B%.2f X%.2f Y%.2f Z%.2f E%.2f\n" + "%SHome offset (mm):\n%S M206 X%.2f Y%.2f Z%.2f\n" + ), + echomagic, echomagic, cs.axis_steps_per_unit[X_AXIS], cs.axis_steps_per_unit[Y_AXIS], cs.axis_steps_per_unit[Z_AXIS], cs.axis_steps_per_unit[E_AXIS], + echomagic, echomagic, max_feedrate[X_AXIS], max_feedrate[Y_AXIS], max_feedrate[Z_AXIS], max_feedrate[E_AXIS], + echomagic, echomagic, max_acceleration_units_per_sq_second[X_AXIS], max_acceleration_units_per_sq_second[Y_AXIS], max_acceleration_units_per_sq_second[Z_AXIS], max_acceleration_units_per_sq_second[E_AXIS], + echomagic, echomagic, cs.acceleration, cs.retract_acceleration, + echomagic, echomagic, cs.minimumfeedrate, cs.mintravelfeedrate, cs.minsegmenttime, cs.max_jerk[X_AXIS], cs.max_jerk[Y_AXIS], cs.max_jerk[Z_AXIS], cs.max_jerk[E_AXIS], + echomagic, echomagic, cs.add_homing[X_AXIS], cs.add_homing[Y_AXIS], cs.add_homing[Z_AXIS] #endif //TMC2130 - ); + ); #ifdef PIDTEMP - printf_P(PSTR("%SPID settings:\n%S M301 P%.2f I%.2f D%.2f\n"), - echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd)); + printf_P(PSTR("%SPID settings:\n%S M301 P%.2f I%.2f D%.2f\n"), + echomagic, echomagic, cs.Kp, unscalePID_i(cs.Ki), unscalePID_d(cs.Kd)); #endif #ifdef PIDTEMPBED - printf_P(PSTR("%SPID heatbed settings:\n%S M304 P%.2f I%.2f D%.2f\n"), - echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd)); + printf_P(PSTR("%SPID heatbed settings:\n%S M304 P%.2f I%.2f D%.2f\n"), + echomagic, echomagic, cs.bedKp, unscalePID_i(cs.bedKi), unscalePID_d(cs.bedKd)); #endif #ifdef FWRETRACT - printf_P(PSTR( - "%SRetract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)\n%S M207 S%.2f F%.2f Z%.2f\n" - "%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S M208 S%.2f F%.2f\n" - "%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S M209 S%d\n" - ), - echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift, - echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60, - echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0) - ); + printf_P(PSTR( + "%SRetract: S=Length (mm) F:Speed (mm/m) Z: ZLift (mm)\n%S M207 S%.2f F%.2f Z%.2f\n" + "%SRecover: S=Extra length (mm) F:Speed (mm/m)\n%S M208 S%.2f F%.2f\n" + "%SAuto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries\n%S M209 S%d\n" + ), + echomagic, echomagic, cs.retract_length, cs.retract_feedrate*60, cs.retract_zlift, + echomagic, echomagic, cs.retract_recover_length, cs.retract_recover_feedrate*60, + echomagic, echomagic, (cs.autoretract_enabled ? 1 : 0) + ); #if EXTRUDERS > 1 - printf_P(PSTR("%SMulti-extruder settings:\n%S Swap retract length (mm): %.2f\n%S Swap rec. addl. length (mm): %.2f\n"), - echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap); + printf_P(PSTR("%SMulti-extruder settings:\n%S Swap retract length (mm): %.2f\n%S Swap rec. addl. length (mm): %.2f\n"), + echomagic, echomagic, retract_length_swap, echomagic, retract_recover_length_swap); #endif - if (cs.volumetric_enabled) { - printf_P(PSTR("%SFilament settings:\n%S M200 D%.2f\n"), - echomagic, echomagic, cs.filament_size[0]); + if (cs.volumetric_enabled) { + printf_P(PSTR("%SFilament settings:\n%S M200 D%.2f\n"), + echomagic, echomagic, cs.filament_size[0]); #if EXTRUDERS > 1 - printf_P(PSTR("%S M200 T1 D%.2f\n"), - echomagic, echomagic, cs.filament_size[1]); + printf_P(PSTR("%S M200 T1 D%.2f\n"), + echomagic, echomagic, cs.filament_size[1]); #if EXTRUDERS > 2 - printf_P(PSTR("%S M200 T1 D%.2f\n"), - echomagic, echomagic, cs.filament_size[2]); + printf_P(PSTR("%S M200 T1 D%.2f\n"), + echomagic, echomagic, cs.filament_size[2]); #endif #endif } else { printf_P(PSTR("%SFilament settings: Disabled\n"), echomagic); } #endif - if (level >= 10) { + if (level >= 10) { #ifdef LIN_ADVANCE - printf_P(PSTR("%SLinear advance settings:\n M900 K%.2f E/D = %.2f\n"), - echomagic, extruder_advance_k, advance_ed_ratio); + printf_P(PSTR("%SLinear advance settings:\n M900 K%.2f E/D = %.2f\n"), + echomagic, extruder_advance_k, advance_ed_ratio); #endif //LIN_ADVANCE - } + } } #endif @@ -170,17 +170,17 @@ void Config_PrintSettings(uint8_t level) static_assert (EXTRUDERS == 1, "ConfigurationStore M500_conf not implemented for more extruders, fix filament_size array size."); static_assert (NUM_AXIS == 4, "ConfigurationStore M500_conf not implemented for more axis." - "Fix axis_steps_per_unit max_feedrate_normal max_acceleration_units_per_sq_second_normal max_jerk max_feedrate_silent" - " max_acceleration_units_per_sq_second_silent array size."); + "Fix axis_steps_per_unit max_feedrate_normal max_acceleration_units_per_sq_second_normal max_jerk max_feedrate_silent" + " max_acceleration_units_per_sq_second_silent array size."); #ifdef ENABLE_AUTO_BED_LEVELING static_assert (false, "zprobe_zoffset was not initialized in printers in field to -(Z_PROBE_OFFSET_FROM_EXTRUDER), so it contains" - "0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf"); + "0.0, if this is not acceptable, increment EEPROM_VERSION to force use default_conf"); #endif static_assert (sizeof(M500_conf) == 188, "sizeof(M500_conf) has changed, ensure that EEPROM_VERSION has been incremented, " - "or if you added members in the end of struct, ensure that historically uninitialized values will be initialized." - "If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM," - "leave as it is to keep fast code, or reorder struct members to pack more tightly."); + "or if you added members in the end of struct, ensure that historically uninitialized values will be initialized." + "If this is caused by change to more then 8bit processor, decide whether make this struct packed to save EEPROM," + "leave as it is to keep fast code, or reorder struct members to pack more tightly."); static const M500_conf default_conf PROGMEM = { @@ -210,11 +210,11 @@ static const M500_conf default_conf PROGMEM = RETRACT_RECOVER_LENGTH, RETRACT_RECOVER_FEEDRATE, false, - {DEFAULT_NOMINAL_FILAMENT_DIA, + { DEFAULT_NOMINAL_FILAMENT_DIA, #if EXTRUDERS > 1 - DEFAULT_NOMINAL_FILAMENT_DIA, + DEFAULT_NOMINAL_FILAMENT_DIA, #if EXTRUDERS > 2 - DEFAULT_NOMINAL_FILAMENT_DIA, + DEFAULT_NOMINAL_FILAMENT_DIA, #endif #endif }, @@ -227,7 +227,7 @@ static const M500_conf default_conf PROGMEM = //! @retval false Failed. Default settings has been retrieved, because of older version or corrupted data. bool Config_RetrieveSettings() { - bool previous_settings_retrieved = true; + bool previous_settings_retrieved = true; char ver[4]=EEPROM_VERSION; EEPROM_readData(reinterpret_cast(EEPROM_M500_base->version), reinterpret_cast(cs.version), sizeof(cs.version), "cs.version"); //read stored version // SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << cs.version << "]"); @@ -236,13 +236,13 @@ bool Config_RetrieveSettings() EEPROM_readData(reinterpret_cast(EEPROM_M500_base), reinterpret_cast(&cs), sizeof(cs), "cs"); - - if (cs.max_jerk[X_AXIS] > DEFAULT_XJERK) cs.max_jerk[X_AXIS] = DEFAULT_XJERK; - if (cs.max_jerk[Y_AXIS] > DEFAULT_YJERK) cs.max_jerk[Y_AXIS] = DEFAULT_YJERK; + + if (cs.max_jerk[X_AXIS] > DEFAULT_XJERK) cs.max_jerk[X_AXIS] = DEFAULT_XJERK; + if (cs.max_jerk[Y_AXIS] > DEFAULT_YJERK) cs.max_jerk[Y_AXIS] = DEFAULT_YJERK; calculate_extruder_multipliers(); - //if max_feedrate_silent and max_acceleration_units_per_sq_second_silent were never stored to eeprom, use default values: + //if max_feedrate_silent and max_acceleration_units_per_sq_second_silent were never stored to eeprom, use default values: { const uint32_t erased = 0xffffffff; bool initialized = false; @@ -258,47 +258,47 @@ bool Config_RetrieveSettings() { memcpy_P(&cs.max_feedrate_silent,&default_conf.max_feedrate_silent, sizeof(cs.max_feedrate_silent)); memcpy_P(&cs.max_acceleration_units_per_sq_second_silent,&default_conf.max_acceleration_units_per_sq_second_silent, - sizeof(cs.max_acceleration_units_per_sq_second_silent)); + sizeof(cs.max_acceleration_units_per_sq_second_silent)); } } #ifdef TMC2130 - for (uint8_t j = X_AXIS; j <= Y_AXIS; j++) - { - if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY) - cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY; - if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY) - cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY; - if (cs.max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY) - cs.max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY; - if (cs.max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY) - cs.max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY; - } + for (uint8_t j = X_AXIS; j <= Y_AXIS; j++) + { + if (cs.max_feedrate_normal[j] > NORMAL_MAX_FEEDRATE_XY) + cs.max_feedrate_normal[j] = NORMAL_MAX_FEEDRATE_XY; + if (cs.max_feedrate_silent[j] > SILENT_MAX_FEEDRATE_XY) + cs.max_feedrate_silent[j] = SILENT_MAX_FEEDRATE_XY; + if (cs.max_acceleration_units_per_sq_second_normal[j] > NORMAL_MAX_ACCEL_XY) + cs.max_acceleration_units_per_sq_second_normal[j] = NORMAL_MAX_ACCEL_XY; + if (cs.max_acceleration_units_per_sq_second_silent[j] > SILENT_MAX_ACCEL_XY) + cs.max_acceleration_units_per_sq_second_silent[j] = SILENT_MAX_ACCEL_XY; + } #endif //TMC2130 - reset_acceleration_rates(); + reset_acceleration_rates(); - // Call updatePID (similar to when we have processed M301) - updatePID(); + // Call updatePID (similar to when we have processed M301) + updatePID(); SERIAL_ECHO_START; SERIAL_ECHOLNPGM("Stored settings retrieved"); } else { Config_ResetDefault(); - //Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now. - //In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used. - if (eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[0]))) != 0xFF || - eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[1]))) != 0xFF || - eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[2]))) != 0xFF) - { - previous_settings_retrieved = false; - } + //Return false to inform user that eeprom version was changed and firmware is using default hardcoded settings now. + //In case that storing to eeprom was not used yet, do not inform user that hardcoded settings are used. + if (eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[0]))) != 0xFF || + eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[1]))) != 0xFF || + eeprom_read_byte(reinterpret_cast(&(EEPROM_M500_base->version[2]))) != 0xFF) + { + previous_settings_retrieved = false; + } } - #ifdef EEPROM_CHITCHAT - Config_PrintSettings(); - #endif - return previous_settings_retrieved; +#ifdef EEPROM_CHITCHAT + Config_PrintSettings(); +#endif + return previous_settings_retrieved; } #endif @@ -306,9 +306,9 @@ void Config_ResetDefault() { memcpy_P(&cs,&default_conf, sizeof(cs)); - // steps per sq second need to be updated to agree with the units per sq second + // steps per sq second need to be updated to agree with the units per sq second reset_acceleration_rates(); - + #ifdef PIDTEMP updatePID(); #ifdef PID_ADD_EXTRUSION_RATE @@ -316,9 +316,9 @@ void Config_ResetDefault() #endif//PID_ADD_EXTRUSION_RATE #endif//PIDTEMP - calculate_extruder_multipliers(); + calculate_extruder_multipliers(); -SERIAL_ECHO_START; -SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded"); + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded"); } diff --git a/Firmware/ConfigurationStore.h b/Firmware/ConfigurationStore.h index aa20136958..102be6eac9 100755 --- a/Firmware/ConfigurationStore.h +++ b/Firmware/ConfigurationStore.h @@ -54,11 +54,20 @@ void Config_StoreSettings(); bool Config_RetrieveSettings(); #else FORCE_INLINE void Config_StoreSettings() {} -FORCE_INLINE void Config_RetrieveSettings() { Config_ResetDefault(); Config_PrintSettings(); } +FORCE_INLINE void Config_RetrieveSettings() { + Config_ResetDefault(); + Config_PrintSettings(); +} #endif -inline uint8_t calibration_status() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS); } -inline void calibration_status_store(uint8_t status) { eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS, status); } -inline bool calibration_status_pinda() { return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA); } +inline uint8_t calibration_status() { + return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS); +} +inline void calibration_status_store(uint8_t status) { + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS, status); +} +inline bool calibration_status_pinda() { + return eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA); +} #endif//CONFIG_STORE_H diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 951302877b..0606e2b2d8 100755 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -6,7 +6,7 @@ //=========================================================================== #ifdef BED_LIMIT_SWITCHING - #define BED_HYSTERESIS 2 //only disable heating if T>target+BED_HYSTERESIS and enable heating if T>target-BED_HYSTERESIS +#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 @@ -19,12 +19,12 @@ //#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 +// 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 @@ -37,7 +37,7 @@ // on an Ultimaker, some initial testing worked with M109 S215 B260 F1 in the start.gcode //#define AUTOTEMP #ifdef AUTOTEMP - #define AUTOTEMP_OLDWEIGHT 0.98 +#define AUTOTEMP_OLDWEIGHT 0.98 #endif //Show Temperature ADC value @@ -83,46 +83,46 @@ //// AUTOSET LOCATIONS OF LIMIT SWITCHES //// Added by ZetaPhoenix 09-15-2012 #ifdef MANUAL_HOME_POSITIONS // Use manual limit switch locations - #define X_HOME_POS MANUAL_X_HOME_POS - #define Y_HOME_POS MANUAL_Y_HOME_POS - #define Z_HOME_POS MANUAL_Z_HOME_POS +#define X_HOME_POS MANUAL_X_HOME_POS +#define Y_HOME_POS MANUAL_Y_HOME_POS +#define Z_HOME_POS MANUAL_Z_HOME_POS #else //Set min/max homing switch positions based upon homing direction and min/max travel limits - //X axis - #if X_HOME_DIR == -1 - #ifdef BED_CENTER_AT_0_0 - #define X_HOME_POS X_MAX_LENGTH * -0.5 - #else - #define X_HOME_POS X_MIN_POS - #endif //BED_CENTER_AT_0_0 - #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 - #define Y_HOME_POS Y_MAX_LENGTH * -0.5 - #else - #define Y_HOME_POS Y_MIN_POS - #endif //BED_CENTER_AT_0_0 - #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 - #define Z_HOME_POS Z_MAX_POS - #endif //Z_HOME_DIR == -1 +//X axis +#if X_HOME_DIR == -1 +#ifdef BED_CENTER_AT_0_0 +#define X_HOME_POS X_MAX_LENGTH * -0.5 +#else +#define X_HOME_POS X_MIN_POS +#endif //BED_CENTER_AT_0_0 +#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 +#define Y_HOME_POS Y_MAX_LENGTH * -0.5 +#else +#define Y_HOME_POS Y_MIN_POS +#endif //BED_CENTER_AT_0_0 +#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 +#define Z_HOME_POS Z_MAX_POS +#endif //Z_HOME_DIR == -1 #endif //End auto min/max positions //END AUTOSET LOCATIONS OF LIMIT SWITCHES -ZP @@ -135,8 +135,8 @@ //#define Z_DUAL_STEPPER_DRIVERS #ifdef Z_DUAL_STEPPER_DRIVERS - #undef EXTRUDERS - #define EXTRUDERS 1 +#undef EXTRUDERS +#define EXTRUDERS 1 #endif // Same again but for Y Axis. @@ -146,12 +146,12 @@ #define INVERT_Y2_VS_Y_DIR 1 #ifdef Y_DUAL_STEPPER_DRIVERS - #undef EXTRUDERS - #define EXTRUDERS 1 +#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" +#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: @@ -235,28 +235,28 @@ * - SDSORT_CACHE_NAMES will retain the sorted file listing in RAM. (Expensive!) * - SDSORT_DYNAMIC_RAM only uses RAM when the SD menu is visible. (Use with caution!) */ - #define SDCARD_SORT_ALPHA //Alphabetical sorting of SD files menu - - // SD Card Sorting options - // In current firmware Prusa Firmware version, - // SDSORT_CACHE_NAMES and SDSORT_DYNAMIC_RAM is not supported and must be set to 0. - #ifdef SDCARD_SORT_ALPHA - #define SD_SORT_TIME 0 - #define SD_SORT_ALPHA 1 - #define SD_SORT_NONE 2 - - #define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256). - #define FOLDER_SORTING -1 // -1=above 0=none 1=below - #define SDSORT_GCODE 0 // Allow turning sorting on/off with LCD and M34 g-code. - #define SDSORT_USES_RAM 0 // Pre-allocate a static array for faster pre-sorting. - #define SDSORT_USES_STACK 0 // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) - #define SDSORT_CACHE_NAMES 0 // Keep sorted items in RAM longer for speedy performance. Most expensive option. - #define SDSORT_DYNAMIC_RAM 0 // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use! - #endif - - #if defined(SDCARD_SORT_ALPHA) - #define HAS_FOLDER_SORTING (FOLDER_SORTING || SDSORT_GCODE) - #endif +#define SDCARD_SORT_ALPHA //Alphabetical sorting of SD files menu + +// SD Card Sorting options +// In current firmware Prusa Firmware version, +// SDSORT_CACHE_NAMES and SDSORT_DYNAMIC_RAM is not supported and must be set to 0. +#ifdef SDCARD_SORT_ALPHA +#define SD_SORT_TIME 0 +#define SD_SORT_ALPHA 1 +#define SD_SORT_NONE 2 + +#define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256). +#define FOLDER_SORTING -1 // -1=above 0=none 1=below +#define SDSORT_GCODE 0 // Allow turning sorting on/off with LCD and M34 g-code. +#define SDSORT_USES_RAM 0 // Pre-allocate a static array for faster pre-sorting. +#define SDSORT_USES_STACK 0 // Prefer the stack for pre-sorting to give back some SRAM. (Negated by next 2 options.) +#define SDSORT_CACHE_NAMES 0 // Keep sorted items in RAM longer for speedy performance. Most expensive option. +#define SDSORT_DYNAMIC_RAM 0 // Use dynamic allocation (within SD menus). Least expensive option. Set SDSORT_LIMIT before use! +#endif + +#if defined(SDCARD_SORT_ALPHA) +#define HAS_FOLDER_SORTING (FOLDER_SORTING || SDSORT_GCODE) +#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 @@ -266,13 +266,13 @@ // 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 0 //1 for inverse movements in Z - #define BABYSTEP_Z_MULTIPLICATOR 2 //faster z movements +#define BABYSTEP_XY //not only z, but also XY in the menu. more clutter, more functions +#define BABYSTEP_INVERT_Z 0 //1 for inverse movements in Z +#define BABYSTEP_Z_MULTIPLICATOR 2 //faster z movements - #ifdef COREXY - #error BABYSTEPPING not implemented for COREXY yet. - #endif +#ifdef COREXY +#error BABYSTEPPING not implemented for COREXY yet. +#endif #endif /** @@ -285,34 +285,34 @@ #define LIN_ADVANCE #ifdef LIN_ADVANCE - #define LIN_ADVANCE_K 0 //Try around 45 for PLA, around 25 for ABS. - - /** - * Some Slicers produce Gcode with randomly jumping extrusion widths occasionally. - * For example within a 0.4mm perimeter it may produce a single segment of 0.05mm width. - * While this is harmless for normal printing (the fluid nature of the filament will - * close this very, very tiny gap), it throws off the LIN_ADVANCE pressure adaption. - * - * For this case LIN_ADVANCE_E_D_RATIO can be used to set the extrusion:distance ratio - * to a fixed value. Note that using a fixed ratio will lead to wrong nozzle pressures - * if the slicer is using variable widths or layer heights within one print! - * - * This option sets the default E:D ratio at startup. Use `M900` to override this value. - * - * Example: `M900 W0.4 H0.2 D1.75`, where: - * - W is the extrusion width in mm - * - H is the layer height in mm - * - D is the filament diameter in mm - * - * Example: `M900 R0.0458` to set the ratio directly. - * - * Set to 0 to auto-detect the ratio based on given Gcode G1 print moves. - * - * Slic3r (including Prusa Slic3r) produces Gcode compatible with the automatic mode. - * Cura (as of this writing) may produce Gcode incompatible with the automatic mode. - */ +#define LIN_ADVANCE_K 0 //Try around 45 for PLA, around 25 for ABS. + +/** + * Some Slicers produce Gcode with randomly jumping extrusion widths occasionally. + * For example within a 0.4mm perimeter it may produce a single segment of 0.05mm width. + * While this is harmless for normal printing (the fluid nature of the filament will + * close this very, very tiny gap), it throws off the LIN_ADVANCE pressure adaption. + * + * For this case LIN_ADVANCE_E_D_RATIO can be used to set the extrusion:distance ratio + * to a fixed value. Note that using a fixed ratio will lead to wrong nozzle pressures + * if the slicer is using variable widths or layer heights within one print! + * + * This option sets the default E:D ratio at startup. Use `M900` to override this value. + * + * Example: `M900 W0.4 H0.2 D1.75`, where: + * - W is the extrusion width in mm + * - H is the layer height in mm + * - D is the filament diameter in mm + * + * Example: `M900 R0.0458` to set the ratio directly. + * + * Set to 0 to auto-detect the ratio based on given Gcode G1 print moves. + * + * Slic3r (including Prusa Slic3r) produces Gcode compatible with the automatic mode. + * Cura (as of this writing) may produce Gcode incompatible with the automatic mode. + */ #define LIN_ADVANCE_E_D_RATIO 0 // The calculated ratio (or 0) according to the formula W * H / ((D / 2) ^ 2 * PI) - // Example: 0.4 * 0.2 / ((1.75 / 2) ^ 2 * PI) = 0.033260135 +// Example: 0.4 * 0.2 / ((1.75 / 2) ^ 2 * PI) = 0.033260135 #endif // Arc interpretation settings: @@ -331,17 +331,17 @@ const unsigned int dropsegments=5; //everything with less than this number of st // Power Signal Control Definitions // By default use ATX definition #ifndef POWER_SUPPLY - #define POWER_SUPPLY 1 +#define POWER_SUPPLY 1 #endif // 1 = ATX #if (POWER_SUPPLY == 1) - #define PS_ON_AWAKE LOW - #define PS_ON_ASLEEP HIGH +#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 +#define PS_ON_AWAKE HIGH +#define PS_ON_ASLEEP LOW #endif // Control heater 0 and heater 1 in parallel. @@ -354,9 +354,9 @@ const unsigned int dropsegments=5; //everything with less than this number of st // 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 +#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 +#define BLOCK_BUFFER_SIZE 16 // maximize block buffer #endif @@ -377,23 +377,23 @@ const unsigned int dropsegments=5; //everything with less than this number of st #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_LENGTH_SWAP 13 //default swap retract length (positive mm), for extruder change - #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_LENGTH_SWAP 0 //default additional swap recover length (mm, added to retract length when recovering from extruder change) - #define RETRACT_RECOVER_FEEDRATE 8 //default feedrate for recovering from retraction (mm/s) +#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_LENGTH_SWAP 13 //default swap retract length (positive mm), for extruder change +#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_LENGTH_SWAP 0 //default additional swap recover length (mm, added to retract length when recovering from extruder change) +#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 FILAMENTCHANGEENABLE - #ifdef EXTRUDER_RUNOUT_PREVENT - #error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENTCHANGE - #endif +#ifdef EXTRUDER_RUNOUT_PREVENT +#error EXTRUDER_RUNOUT_PREVENT currently incompatible with FILAMENTCHANGE +#endif #endif //=========================================================================== @@ -401,65 +401,65 @@ const unsigned int dropsegments=5; //everything with less than this number of st //=========================================================================== #if EXTRUDERS > 1 && defined TEMP_SENSOR_1_AS_REDUNDANT - #error "You cannot use TEMP_SENSOR_1_AS_REDUNDANT if EXTRUDERS > 1" +#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" +#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 +#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 +#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 +#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 +#define THERMISTORBED TEMP_SENSOR_BED +#define BED_USES_THERMISTOR #endif #if TEMP_SENSOR_PINDA > 0 - #define THERMISTORPINDA TEMP_SENSOR_PINDA +#define THERMISTORPINDA TEMP_SENSOR_PINDA #endif #if TEMP_SENSOR_AMBIENT > 0 - #define THERMISTORAMBIENT TEMP_SENSOR_AMBIENT +#define THERMISTORAMBIENT TEMP_SENSOR_AMBIENT #endif #if TEMP_SENSOR_0 == -1 - #define HEATER_0_USES_AD595 +#define HEATER_0_USES_AD595 #endif #if TEMP_SENSOR_1 == -1 - #define HEATER_1_USES_AD595 +#define HEATER_1_USES_AD595 #endif #if TEMP_SENSOR_2 == -1 - #define HEATER_2_USES_AD595 +#define HEATER_2_USES_AD595 #endif #if TEMP_SENSOR_BED == -1 - #define BED_USES_AD595 +#define BED_USES_AD595 #endif #if TEMP_SENSOR_0 == -2 - #define HEATER_0_USES_MAX6675 +#define HEATER_0_USES_MAX6675 #endif #if TEMP_SENSOR_0 == 0 - #undef HEATER_0_MINTEMP - #undef HEATER_0_MAXTEMP +#undef HEATER_0_MINTEMP +#undef HEATER_0_MAXTEMP #endif #if TEMP_SENSOR_1 == 0 - #undef HEATER_1_MINTEMP - #undef HEATER_1_MAXTEMP +#undef HEATER_1_MINTEMP +#undef HEATER_1_MAXTEMP #endif #if TEMP_SENSOR_2 == 0 - #undef HEATER_2_MINTEMP - #undef HEATER_2_MAXTEMP +#undef HEATER_2_MINTEMP +#undef HEATER_2_MAXTEMP #endif #if TEMP_SENSOR_BED == 0 - #undef BED_MINTEMP - #undef BED_MAXTEMP +#undef BED_MINTEMP +#undef BED_MAXTEMP #endif diff --git a/Firmware/Dcodes.cpp b/Firmware/Dcodes.cpp index a21e322004..bd7eaf7724 100755 --- a/Firmware/Dcodes.cpp +++ b/Firmware/Dcodes.cpp @@ -10,134 +10,140 @@ inline void print_hex_nibble(uint8_t val) { - putchar((val > 9)?(val - 10 + 'a'):(val + '0')); + putchar((val > 9)?(val - 10 + 'a'):(val + '0')); } void print_hex_byte(uint8_t val) { - print_hex_nibble(val >> 4); - print_hex_nibble(val & 15); + print_hex_nibble(val >> 4); + print_hex_nibble(val & 15); } void print_hex_word(uint16_t val) { - print_hex_byte(val >> 8); - print_hex_byte(val & 255); + print_hex_byte(val >> 8); + print_hex_byte(val & 255); } void print_eeprom(uint16_t address, uint16_t count, uint8_t countperline = 16) { - while (count) - { - print_hex_word(address); - putchar(' '); - uint8_t count_line = countperline; - while (count && count_line) - { - putchar(' '); - print_hex_byte(eeprom_read_byte((uint8_t*)address++)); - count_line--; - count--; - } - putchar('\n'); - } + while (count) + { + print_hex_word(address); + putchar(' '); + uint8_t count_line = countperline; + while (count && count_line) + { + putchar(' '); + print_hex_byte(eeprom_read_byte((uint8_t*)address++)); + count_line--; + count--; + } + putchar('\n'); + } } int parse_hex(char* hex, uint8_t* data, int count) { - int parsed = 0; - while (*hex) - { - if (count && (parsed >= count)) break; - char c = *(hex++); - if (c == ' ') continue; - if (c == '\n') break; - uint8_t val = 0x00; - if ((c >= '0') && (c <= '9')) val |= ((c - '0') << 4); - else if ((c >= 'a') && (c <= 'f')) val |= ((c - 'a' + 10) << 4); - else return -parsed; - c = *(hex++); - if ((c >= '0') && (c <= '9')) val |= (c - '0'); - else if ((c >= 'a') && (c <= 'f')) val |= (c - 'a' + 10); - else return -parsed; - data[parsed] = val; - parsed++; - } - return parsed; + int parsed = 0; + while (*hex) + { + if (count && (parsed >= count)) break; + char c = *(hex++); + if (c == ' ') continue; + if (c == '\n') break; + uint8_t val = 0x00; + if ((c >= '0') && (c <= '9')) val |= ((c - '0') << 4); + else if ((c >= 'a') && (c <= 'f')) val |= ((c - 'a' + 10) << 4); + else return -parsed; + c = *(hex++); + if ((c >= '0') && (c <= '9')) val |= (c - '0'); + else if ((c >= 'a') && (c <= 'f')) val |= (c - 'a' + 10); + else return -parsed; + data[parsed] = val; + parsed++; + } + return parsed; } void print_mem(uint32_t address, uint16_t count, uint8_t type, uint8_t countperline = 16) { - while (count) - { - if (type == 2) - print_hex_nibble(address >> 16); - print_hex_word(address); - putchar(' '); - uint8_t count_line = countperline; - while (count && count_line) - { - uint8_t data = 0; - switch (type) - { - case 0: data = *((uint8_t*)address++); break; - case 1: data = eeprom_read_byte((uint8_t*)address++); break; - case 2: data = pgm_read_byte_far((uint8_t*)address++); break; - } - putchar(' '); - print_hex_byte(data); - count_line--; - count--; - } - putchar('\n'); - } + while (count) + { + if (type == 2) + print_hex_nibble(address >> 16); + print_hex_word(address); + putchar(' '); + uint8_t count_line = countperline; + while (count && count_line) + { + uint8_t data = 0; + switch (type) + { + case 0: + data = *((uint8_t*)address++); + break; + case 1: + data = eeprom_read_byte((uint8_t*)address++); + break; + case 2: + data = pgm_read_byte_far((uint8_t*)address++); + break; + } + putchar(' '); + print_hex_byte(data); + count_line--; + count--; + } + putchar('\n'); + } } #ifdef DEBUG_DCODE3 #define EEPROM_SIZE 0x1000 void dcode_3() { - DBG(_N("D3 - Read/Write EEPROM\n")); - uint16_t address = 0x0000; //default 0x0000 - uint16_t count = EEPROM_SIZE; //default 0x1000 (entire eeprom) - if (code_seen('A')) // Address (0x0000-0x0fff) - address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value(); - if (code_seen('C')) // Count (0x0001-0x1000) - count = (int)code_value(); - address &= 0x1fff; - if (count > EEPROM_SIZE) count = EEPROM_SIZE; - if ((address + count) > EEPROM_SIZE) count = EEPROM_SIZE - address; - if (code_seen('X')) // Data - { - uint8_t data[16]; - count = parse_hex(strchr_pointer + 1, data, 16); - if (count > 0) - { - for (uint16_t i = 0; i < count; i++) - eeprom_write_byte((uint8_t*)(address + i), data[i]); - printf_P(_N("%d bytes written to EEPROM at address 0x%04x"), count, address); - putchar('\n'); - } - else - count = 0; - } - print_mem(address, count, 1); -/* while (count) - { - print_hex_word(address); - putchar(' '); - uint8_t countperline = 16; - while (count && countperline) - { - uint8_t data = eeprom_read_byte((uint8_t*)address++); - putchar(' '); - print_hex_byte(data); - countperline--; - count--; - } - putchar('\n'); - }*/ + DBG(_N("D3 - Read/Write EEPROM\n")); + uint16_t address = 0x0000; //default 0x0000 + uint16_t count = EEPROM_SIZE; //default 0x1000 (entire eeprom) + if (code_seen('A')) // Address (0x0000-0x0fff) + address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value(); + if (code_seen('C')) // Count (0x0001-0x1000) + count = (int)code_value(); + address &= 0x1fff; + if (count > EEPROM_SIZE) count = EEPROM_SIZE; + if ((address + count) > EEPROM_SIZE) count = EEPROM_SIZE - address; + if (code_seen('X')) // Data + { + uint8_t data[16]; + count = parse_hex(strchr_pointer + 1, data, 16); + if (count > 0) + { + for (uint16_t i = 0; i < count; i++) + eeprom_write_byte((uint8_t*)(address + i), data[i]); + printf_P(_N("%d bytes written to EEPROM at address 0x%04x"), count, address); + putchar('\n'); + } + else + count = 0; + } + print_mem(address, count, 1); + /* while (count) + { + print_hex_word(address); + putchar(' '); + uint8_t countperline = 16; + while (count && countperline) + { + uint8_t data = eeprom_read_byte((uint8_t*)address++); + putchar(' '); + print_hex_byte(data); + countperline--; + count--; + } + putchar('\n'); + }*/ } #endif //DEBUG_DCODE3 @@ -176,109 +182,109 @@ extern float axis_steps_per_unit[NUM_AXIS]; void dcode__1() { - printf("D-1 - Endless loop\n"); - cli(); - while (1); + printf("D-1 - Endless loop\n"); + cli(); + while (1); } void dcode_0() { - if (*(strchr_pointer + 1) == 0) return; - LOG("D0 - Reset\n"); - if (code_seen('B')) //bootloader - { - cli(); - wdt_enable(WDTO_15MS); - while(1); - } - else //reset - { + if (*(strchr_pointer + 1) == 0) return; + LOG("D0 - Reset\n"); + if (code_seen('B')) //bootloader + { + cli(); + wdt_enable(WDTO_15MS); + while(1); + } + else //reset + { #ifndef _NO_ASM - asm volatile("jmp 0x00000"); + asm volatile("jmp 0x00000"); #endif //_NO_ASM - } + } } void dcode_1() { - LOG("D1 - Clear EEPROM and RESET\n"); - cli(); - for (int i = 0; i < 8192; i++) - eeprom_write_byte((unsigned char*)i, (unsigned char)0xff); - wdt_enable(WDTO_15MS); - while(1); + LOG("D1 - Clear EEPROM and RESET\n"); + cli(); + for (int i = 0; i < 8192; i++) + eeprom_write_byte((unsigned char*)i, (unsigned char)0xff); + wdt_enable(WDTO_15MS); + while(1); } void dcode_2() { - LOG("D2 - Read/Write RAM\n"); - uint16_t address = 0x0000; //default 0x0000 - uint16_t count = 0x2000; //default 0x2000 (entire ram) - if (code_seen('A')) // Address (0x0000-0x1fff) - address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value(); - if (code_seen('C')) // Count (0x0001-0x2000) - count = (int)code_value(); - address &= 0x1fff; - if (count > 0x2000) count = 0x2000; - if ((address + count) > 0x2000) count = 0x2000 - address; - if (code_seen('X')) // Data - { - uint8_t data[16]; - count = parse_hex(strchr_pointer + 1, data, 16); - if (count > 0) - { - for (int i = 0; i < count; i++) - *((uint8_t*)(address + i)) = data[i]; - LOG("%d bytes written to RAM at address %04x", count, address); - } - else - count = 0; - } - print_mem(address, count, 0); -/* while (count) - { - print_hex_word(address); - putchar(' '); - uint8_t countperline = 16; - while (count && countperline) - { - uint8_t data = *((uint8_t*)address++); - putchar(' '); - print_hex_byte(data); - countperline--; - count--; - } - putchar('\n'); - }*/ + LOG("D2 - Read/Write RAM\n"); + uint16_t address = 0x0000; //default 0x0000 + uint16_t count = 0x2000; //default 0x2000 (entire ram) + if (code_seen('A')) // Address (0x0000-0x1fff) + address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value(); + if (code_seen('C')) // Count (0x0001-0x2000) + count = (int)code_value(); + address &= 0x1fff; + if (count > 0x2000) count = 0x2000; + if ((address + count) > 0x2000) count = 0x2000 - address; + if (code_seen('X')) // Data + { + uint8_t data[16]; + count = parse_hex(strchr_pointer + 1, data, 16); + if (count > 0) + { + for (int i = 0; i < count; i++) + *((uint8_t*)(address + i)) = data[i]; + LOG("%d bytes written to RAM at address %04x", count, address); + } + else + count = 0; + } + print_mem(address, count, 0); + /* while (count) + { + print_hex_word(address); + putchar(' '); + uint8_t countperline = 16; + while (count && countperline) + { + uint8_t data = *((uint8_t*)address++); + putchar(' '); + print_hex_byte(data); + countperline--; + count--; + } + putchar('\n'); + }*/ } void dcode_4() { - LOG("D4 - Read/Write PIN\n"); - if (code_seen('P')) // Pin (0-255) - { - int pin = (int)code_value(); - if ((pin >= 0) && (pin <= 255)) - { - if (code_seen('F')) // Function in/out (0/1) - { - int fnc = (int)code_value(); - if (fnc == 0) pinMode(pin, INPUT); - else if (fnc == 1) pinMode(pin, OUTPUT); - } - if (code_seen('V')) // Value (0/1) - { - int val = (int)code_value(); - if (val == 0) digitalWrite(pin, LOW); - else if (val == 1) digitalWrite(pin, HIGH); - } - else - { - int val = (digitalRead(pin) != LOW)?1:0; - printf("PIN%d=%d", pin, val); - } - } - } + LOG("D4 - Read/Write PIN\n"); + if (code_seen('P')) // Pin (0-255) + { + int pin = (int)code_value(); + if ((pin >= 0) && (pin <= 255)) + { + if (code_seen('F')) // Function in/out (0/1) + { + int fnc = (int)code_value(); + if (fnc == 0) pinMode(pin, INPUT); + else if (fnc == 1) pinMode(pin, OUTPUT); + } + if (code_seen('V')) // Value (0/1) + { + int val = (int)code_value(); + if (val == 0) digitalWrite(pin, LOW); + else if (val == 1) digitalWrite(pin, HIGH); + } + else + { + int val = (digitalRead(pin) != LOW)?1:0; + printf("PIN%d=%d", pin, val); + } + } + } } #endif //DEBUG_DCODES @@ -286,62 +292,62 @@ void dcode_4() void dcode_5() { - printf_P(PSTR("D5 - Read/Write FLASH\n")); - uint32_t address = 0x0000; //default 0x0000 - uint16_t count = 0x0400; //default 0x0400 (1kb block) - if (code_seen('A')) // Address (0x00000-0x3ffff) - address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value(); - if (code_seen('C')) // Count (0x0001-0x2000) - count = (int)code_value(); - address &= 0x3ffff; - if (count > 0x2000) count = 0x2000; - if ((address + count) > 0x40000) count = 0x40000 - address; - bool bErase = false; - bool bCopy = false; - if (code_seen('E')) //Erase - bErase = true; - uint8_t data[16]; - if (code_seen('X')) // Data - { - count = parse_hex(strchr_pointer + 1, data, 16); - if (count > 0) bCopy = true; - } - if (bErase || bCopy) - { - if (bErase) - { - printf_P(PSTR("%d bytes of FLASH at address %05x will be erased\n"), count, address); - } - if (bCopy) - { - printf_P(PSTR("%d bytes will be written to FLASH at address %05x\n"), count, address); - } - cli(); - boot_app_magic = 0x55aa55aa; - boot_app_flags = (bErase?(BOOT_APP_FLG_ERASE):0) | (bCopy?(BOOT_APP_FLG_COPY):0); - boot_copy_size = (uint16_t)count; - boot_dst_addr = (uint32_t)address; - boot_src_addr = (uint32_t)(&data); - bootapp_print_vars(); - wdt_enable(WDTO_15MS); - while(1); - } - while (count) - { - print_hex_nibble(address >> 16); - print_hex_word(address); - putchar(' '); - uint8_t countperline = 16; - while (count && countperline) - { - uint8_t data = pgm_read_byte_far((uint8_t*)address++); - putchar(' '); - print_hex_byte(data); - countperline--; - count--; - } - putchar('\n'); - } + printf_P(PSTR("D5 - Read/Write FLASH\n")); + uint32_t address = 0x0000; //default 0x0000 + uint16_t count = 0x0400; //default 0x0400 (1kb block) + if (code_seen('A')) // Address (0x00000-0x3ffff) + address = (strchr_pointer[1] == 'x')?strtol(strchr_pointer + 2, 0, 16):(int)code_value(); + if (code_seen('C')) // Count (0x0001-0x2000) + count = (int)code_value(); + address &= 0x3ffff; + if (count > 0x2000) count = 0x2000; + if ((address + count) > 0x40000) count = 0x40000 - address; + bool bErase = false; + bool bCopy = false; + if (code_seen('E')) //Erase + bErase = true; + uint8_t data[16]; + if (code_seen('X')) // Data + { + count = parse_hex(strchr_pointer + 1, data, 16); + if (count > 0) bCopy = true; + } + if (bErase || bCopy) + { + if (bErase) + { + printf_P(PSTR("%d bytes of FLASH at address %05x will be erased\n"), count, address); + } + if (bCopy) + { + printf_P(PSTR("%d bytes will be written to FLASH at address %05x\n"), count, address); + } + cli(); + boot_app_magic = 0x55aa55aa; + boot_app_flags = (bErase?(BOOT_APP_FLG_ERASE):0) | (bCopy?(BOOT_APP_FLG_COPY):0); + boot_copy_size = (uint16_t)count; + boot_dst_addr = (uint32_t)address; + boot_src_addr = (uint32_t)(&data); + bootapp_print_vars(); + wdt_enable(WDTO_15MS); + while(1); + } + while (count) + { + print_hex_nibble(address >> 16); + print_hex_word(address); + putchar(' '); + uint8_t countperline = 16; + while (count && countperline) + { + uint8_t data = pgm_read_byte_far((uint8_t*)address++); + putchar(' '); + print_hex_byte(data); + countperline--; + count--; + } + putchar('\n'); + } } #endif //DEBUG_DCODE5 @@ -349,78 +355,85 @@ void dcode_5() void dcode_6() { - LOG("D6 - Read/Write external FLASH\n"); + LOG("D6 - Read/Write external FLASH\n"); } void dcode_7() { - LOG("D7 - Read/Write Bootloader\n"); -/* - cli(); - boot_app_magic = 0x55aa55aa; - boot_app_flags = BOOT_APP_FLG_ERASE | BOOT_APP_FLG_COPY | BOOT_APP_FLG_FLASH; - boot_copy_size = (uint16_t)0xc00; - boot_src_addr = (uint32_t)0x0003e400; - boot_dst_addr = (uint32_t)0x0003f400; - wdt_enable(WDTO_15MS); - while(1); -*/ + LOG("D7 - Read/Write Bootloader\n"); + /* + cli(); + boot_app_magic = 0x55aa55aa; + boot_app_flags = BOOT_APP_FLG_ERASE | BOOT_APP_FLG_COPY | BOOT_APP_FLG_FLASH; + boot_copy_size = (uint16_t)0xc00; + boot_src_addr = (uint32_t)0x0003e400; + boot_dst_addr = (uint32_t)0x0003f400; + wdt_enable(WDTO_15MS); + while(1); + */ } void dcode_8() { - printf_P(PSTR("D8 - Read/Write PINDA\n")); - uint8_t cal_status = calibration_status_pinda(); - float temp_pinda = current_temperature_pinda; - float offset_z = temp_compensation_pinda_thermistor_offset(temp_pinda); - if ((strchr_pointer[1+1] == '?') || (strchr_pointer[1+1] == 0)) - { - printf_P(PSTR("cal_status=%d\n"), cal_status?1:0); - for (uint8_t i = 0; i < 6; i++) - { - uint16_t offs = 0; - if (i > 0) offs = eeprom_read_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + (i - 1)); - float foffs = ((float)offs) / axis_steps_per_unit[Z_AXIS]; - offs = 1000 * foffs; - printf_P(PSTR("temp_pinda=%dC temp_shift=%dum\n"), 35 + i * 5, offs); - } - } - else if (strchr_pointer[1+1] == '!') - { - cal_status = 1; - eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, cal_status); - eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 0, 8); //40C - 20um - 8usteps - eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 1, 24); //45C - 60um - 24usteps - eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 2, 48); //50C - 120um - 48usteps - eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 3, 80); //55C - 200um - 80usteps - eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 4, 120); //60C - 300um - 120usteps - } - else - { - if (code_seen('P')) // Pinda temperature [C] - temp_pinda = code_value(); - offset_z = temp_compensation_pinda_thermistor_offset(temp_pinda); - if (code_seen('Z')) // Z Offset [mm] - { - offset_z = code_value(); - } - } - printf_P(PSTR("temp_pinda=%d offset_z=%d.%03d\n"), (int)temp_pinda, (int)offset_z, ((int)(1000 * offset_z) % 1000)); + printf_P(PSTR("D8 - Read/Write PINDA\n")); + uint8_t cal_status = calibration_status_pinda(); + float temp_pinda = current_temperature_pinda; + float offset_z = temp_compensation_pinda_thermistor_offset(temp_pinda); + if ((strchr_pointer[1+1] == '?') || (strchr_pointer[1+1] == 0)) + { + printf_P(PSTR("cal_status=%d\n"), cal_status?1:0); + for (uint8_t i = 0; i < 6; i++) + { + uint16_t offs = 0; + if (i > 0) offs = eeprom_read_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + (i - 1)); + float foffs = ((float)offs) / axis_steps_per_unit[Z_AXIS]; + offs = 1000 * foffs; + printf_P(PSTR("temp_pinda=%dC temp_shift=%dum\n"), 35 + i * 5, offs); + } + } + else if (strchr_pointer[1+1] == '!') + { + cal_status = 1; + eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, cal_status); + eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 0, 8); //40C - 20um - 8usteps + eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 1, 24); //45C - 60um - 24usteps + eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 2, 48); //50C - 120um - 48usteps + eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 3, 80); //55C - 200um - 80usteps + eeprom_write_word(((uint16_t*)EEPROM_PROBE_TEMP_SHIFT) + 4, 120); //60C - 300um - 120usteps + } + else + { + if (code_seen('P')) // Pinda temperature [C] + temp_pinda = code_value(); + offset_z = temp_compensation_pinda_thermistor_offset(temp_pinda); + if (code_seen('Z')) // Z Offset [mm] + { + offset_z = code_value(); + } + } + printf_P(PSTR("temp_pinda=%d offset_z=%d.%03d\n"), (int)temp_pinda, (int)offset_z, ((int)(1000 * offset_z) % 1000)); } const char* dcode_9_ADC_name(uint8_t i) { - switch (i) - { - case 0: return PSTR("TEMP_HEATER0"); - case 1: return PSTR("TEMP_HEATER1"); - case 2: return PSTR("TEMP_BED"); - case 3: return PSTR("TEMP_PINDA"); - case 4: return PSTR("VOLT_PWR"); - case 5: return PSTR("TEMP_AMBIENT"); - case 6: return PSTR("VOLT_BED"); - } - return 0; + switch (i) + { + case 0: + return PSTR("TEMP_HEATER0"); + case 1: + return PSTR("TEMP_HEATER1"); + case 2: + return PSTR("TEMP_BED"); + case 3: + return PSTR("TEMP_PINDA"); + case 4: + return PSTR("VOLT_PWR"); + case 5: + return PSTR("TEMP_AMBIENT"); + case 6: + return PSTR("VOLT_BED"); + } + return 0; } extern int current_temperature_raw[EXTRUDERS]; @@ -441,59 +454,66 @@ extern int current_voltage_raw_bed; uint16_t dcode_9_ADC_val(uint8_t i) { - switch (i) - { - case 0: return current_temperature_raw[0]; - case 1: return 0; - case 2: return current_temperature_bed_raw; - case 3: return current_temperature_raw_pinda; + switch (i) + { + case 0: + return current_temperature_raw[0]; + case 1: + return 0; + case 2: + return current_temperature_bed_raw; + case 3: + return current_temperature_raw_pinda; #ifdef VOLT_PWR_PIN - case 4: return current_voltage_raw_pwr; + case 4: + return current_voltage_raw_pwr; #endif //VOLT_PWR_PIN #ifdef AMBIENT_THERMISTOR - case 5: return current_temperature_raw_ambient; + case 5: + return current_temperature_raw_ambient; #endif //AMBIENT_THERMISTOR #ifdef VOLT_BED_PIN - case 6: return current_voltage_raw_bed; + case 6: + return current_voltage_raw_bed; #endif //VOLT_BED_PIN - } - return 0; + } + return 0; } void dcode_9() { - printf_P(PSTR("D9 - Read/Write ADC\n")); - if ((strchr_pointer[1+1] == '?') || (strchr_pointer[1+1] == 0)) - { - for (uint8_t i = 0; i < ADC_CHAN_CNT; i++) - printf_P(PSTR("\tADC%d=%4d\t(%S)\n"), i, dcode_9_ADC_val(i) >> 4, dcode_9_ADC_name(i)); - } - else - { - uint8_t index = 0xff; - if (code_seen('I')) // index (index of used channel, not avr channel index) - index = code_value(); - if (index < ADC_CHAN_CNT) - { - if (code_seen('V')) // value to be written as simulated - { - adc_sim_mask |= (1 << index); - adc_values[index] = (((int)code_value()) << 4); - printf_P(PSTR("ADC%d=%4d\n"), index, adc_values[index] >> 4); - } - } - } + printf_P(PSTR("D9 - Read/Write ADC\n")); + if ((strchr_pointer[1+1] == '?') || (strchr_pointer[1+1] == 0)) + { + for (uint8_t i = 0; i < ADC_CHAN_CNT; i++) + printf_P(PSTR("\tADC%d=%4d\t(%S)\n"), i, dcode_9_ADC_val(i) >> 4, dcode_9_ADC_name(i)); + } + else + { + uint8_t index = 0xff; + if (code_seen('I')) // index (index of used channel, not avr channel index) + index = code_value(); + if (index < ADC_CHAN_CNT) + { + if (code_seen('V')) // value to be written as simulated + { + adc_sim_mask |= (1 << index); + adc_values[index] = (((int)code_value()) << 4); + printf_P(PSTR("ADC%d=%4d\n"), index, adc_values[index] >> 4); + } + } + } } void dcode_10() -{//Tell the printer that XYZ calibration went OK - LOG("D10 - XYZ calibration = OK\n"); - calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST); +{ //Tell the printer that XYZ calibration went OK + LOG("D10 - XYZ calibration = OK\n"); + calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST); } void dcode_12() -{//Time - LOG("D12 - Time\n"); +{ //Time + LOG("D12 - Time\n"); } @@ -536,143 +556,155 @@ extern void st_synchronize(); */ void dcode_2130() { - printf_P(PSTR("D2130 - TMC2130\n")); - uint8_t axis = 0xff; - switch (strchr_pointer[1+4]) - { - case 'X': axis = X_AXIS; break; - case 'Y': axis = Y_AXIS; break; - case 'Z': axis = Z_AXIS; break; - case 'E': axis = E_AXIS; break; - } - if (axis != 0xff) - { - char ch_axis = strchr_pointer[1+4]; - if (strchr_pointer[1+5] == '0') { tmc2130_set_pwr(axis, 0); } - else if (strchr_pointer[1+5] == '1') { tmc2130_set_pwr(axis, 1); } - else if (strchr_pointer[1+5] == '+') - { - if (strchr_pointer[1+6] == 0) - { - tmc2130_set_dir(axis, 0); - tmc2130_do_step(axis); - } - else - { - uint8_t steps = atoi(strchr_pointer + 1 + 6); - tmc2130_do_steps(axis, steps, 0, 1000); - } - } - else if (strchr_pointer[1+5] == '-') - { - if (strchr_pointer[1+6] == 0) - { - tmc2130_set_dir(axis, 1); - tmc2130_do_step(axis); - } - else - { - uint8_t steps = atoi(strchr_pointer + 1 + 6); - tmc2130_do_steps(axis, steps, 1, 1000); - } - } - else if (strchr_pointer[1+5] == '?') - { - if (strcmp(strchr_pointer + 7, "mres") == 0) printf_P(PSTR("%c mres=%d\n"), ch_axis, tmc2130_mres[axis]); - else if (strcmp(strchr_pointer + 7, "step") == 0) printf_P(PSTR("%c step=%d\n"), ch_axis, tmc2130_rd_MSCNT(axis) >> tmc2130_mres[axis]); - else if (strcmp(strchr_pointer + 7, "mscnt") == 0) printf_P(PSTR("%c MSCNT=%d\n"), ch_axis, tmc2130_rd_MSCNT(axis)); - else if (strcmp(strchr_pointer + 7, "mscuract") == 0) - { - uint32_t val = tmc2130_rd_MSCURACT(axis); - int curA = (val & 0xff); - int curB = ((val >> 16) & 0xff); - if ((val << 7) & 0x8000) curA -= 256; - if ((val >> 9) & 0x8000) curB -= 256; - printf_P(PSTR("%c MSCURACT=0x%08lx A=%d B=%d\n"), ch_axis, val, curA, curB); - } - else if (strcmp(strchr_pointer + 7, "wave") == 0) - { - tmc2130_get_wave(axis, 0, stdout); - } - } - else if (strchr_pointer[1+5] == '!') - { - if (strncmp(strchr_pointer + 7, "step", 4) == 0) - { - uint8_t step = atoi(strchr_pointer + 11); - uint16_t res = tmc2130_get_res(axis); - tmc2130_goto_step(axis, step & (4*res - 1), 2, 1000, res); - } - else if (strncmp(strchr_pointer + 7, "mres", 4) == 0) - { - uint8_t mres = strchr_pointer[11] - '0'; - if ((mres >= 0) && (mres <= 8)) - { - st_synchronize(); - uint16_t res = tmc2130_get_res(axis); - uint16_t res_new = tmc2130_mres2usteps(mres); - tmc2130_set_res(axis, res_new); - if (res_new > res) - axis_steps_per_unit[axis] *= (res_new / res); - else - axis_steps_per_unit[axis] /= (res / res_new); - } - } - else if (strncmp(strchr_pointer + 7, "wave", 4) == 0) - { - uint8_t fac1000 = atoi(strchr_pointer + 11) & 0xffff; - if (fac1000 < TMC2130_WAVE_FAC1000_MIN) fac1000 = 0; - if (fac1000 > TMC2130_WAVE_FAC1000_MAX) fac1000 = TMC2130_WAVE_FAC1000_MAX; - tmc2130_set_wave(axis, 247, fac1000); - tmc2130_wave_fac[axis] = fac1000; - } - } - else if (strchr_pointer[1+5] == '@') - { - tmc2130_home_calibrate(axis); - } - } + printf_P(PSTR("D2130 - TMC2130\n")); + uint8_t axis = 0xff; + switch (strchr_pointer[1+4]) + { + case 'X': + axis = X_AXIS; + break; + case 'Y': + axis = Y_AXIS; + break; + case 'Z': + axis = Z_AXIS; + break; + case 'E': + axis = E_AXIS; + break; + } + if (axis != 0xff) + { + char ch_axis = strchr_pointer[1+4]; + if (strchr_pointer[1+5] == '0') { + tmc2130_set_pwr(axis, 0); + } + else if (strchr_pointer[1+5] == '1') { + tmc2130_set_pwr(axis, 1); + } + else if (strchr_pointer[1+5] == '+') + { + if (strchr_pointer[1+6] == 0) + { + tmc2130_set_dir(axis, 0); + tmc2130_do_step(axis); + } + else + { + uint8_t steps = atoi(strchr_pointer + 1 + 6); + tmc2130_do_steps(axis, steps, 0, 1000); + } + } + else if (strchr_pointer[1+5] == '-') + { + if (strchr_pointer[1+6] == 0) + { + tmc2130_set_dir(axis, 1); + tmc2130_do_step(axis); + } + else + { + uint8_t steps = atoi(strchr_pointer + 1 + 6); + tmc2130_do_steps(axis, steps, 1, 1000); + } + } + else if (strchr_pointer[1+5] == '?') + { + if (strcmp(strchr_pointer + 7, "mres") == 0) printf_P(PSTR("%c mres=%d\n"), ch_axis, tmc2130_mres[axis]); + else if (strcmp(strchr_pointer + 7, "step") == 0) printf_P(PSTR("%c step=%d\n"), ch_axis, tmc2130_rd_MSCNT(axis) >> tmc2130_mres[axis]); + else if (strcmp(strchr_pointer + 7, "mscnt") == 0) printf_P(PSTR("%c MSCNT=%d\n"), ch_axis, tmc2130_rd_MSCNT(axis)); + else if (strcmp(strchr_pointer + 7, "mscuract") == 0) + { + uint32_t val = tmc2130_rd_MSCURACT(axis); + int curA = (val & 0xff); + int curB = ((val >> 16) & 0xff); + if ((val << 7) & 0x8000) curA -= 256; + if ((val >> 9) & 0x8000) curB -= 256; + printf_P(PSTR("%c MSCURACT=0x%08lx A=%d B=%d\n"), ch_axis, val, curA, curB); + } + else if (strcmp(strchr_pointer + 7, "wave") == 0) + { + tmc2130_get_wave(axis, 0, stdout); + } + } + else if (strchr_pointer[1+5] == '!') + { + if (strncmp(strchr_pointer + 7, "step", 4) == 0) + { + uint8_t step = atoi(strchr_pointer + 11); + uint16_t res = tmc2130_get_res(axis); + tmc2130_goto_step(axis, step & (4*res - 1), 2, 1000, res); + } + else if (strncmp(strchr_pointer + 7, "mres", 4) == 0) + { + uint8_t mres = strchr_pointer[11] - '0'; + if ((mres >= 0) && (mres <= 8)) + { + st_synchronize(); + uint16_t res = tmc2130_get_res(axis); + uint16_t res_new = tmc2130_mres2usteps(mres); + tmc2130_set_res(axis, res_new); + if (res_new > res) + axis_steps_per_unit[axis] *= (res_new / res); + else + axis_steps_per_unit[axis] /= (res / res_new); + } + } + else if (strncmp(strchr_pointer + 7, "wave", 4) == 0) + { + uint8_t fac1000 = atoi(strchr_pointer + 11) & 0xffff; + if (fac1000 < TMC2130_WAVE_FAC1000_MIN) fac1000 = 0; + if (fac1000 > TMC2130_WAVE_FAC1000_MAX) fac1000 = TMC2130_WAVE_FAC1000_MAX; + tmc2130_set_wave(axis, 247, fac1000); + tmc2130_wave_fac[axis] = fac1000; + } + } + else if (strchr_pointer[1+5] == '@') + { + tmc2130_home_calibrate(axis); + } + } } #endif //TMC2130 #ifdef PAT9125 void dcode_9125() { - LOG("D9125 - PAT9125\n"); - if ((strchr_pointer[1+4] == '?') || (strchr_pointer[1+4] == 0)) - { + LOG("D9125 - PAT9125\n"); + if ((strchr_pointer[1+4] == '?') || (strchr_pointer[1+4] == 0)) + { // printf("res_x=%d res_y=%d x=%d y=%d b=%d s=%d\n", pat9125_xres, pat9125_yres, pat9125_x, pat9125_y, pat9125_b, pat9125_s); - printf("x=%d y=%d b=%d s=%d\n", pat9125_x, pat9125_y, pat9125_b, pat9125_s); - return; - } - if (strchr_pointer[1+4] == '!') - { - pat9125_update(); - printf("x=%d y=%d b=%d s=%d\n", pat9125_x, pat9125_y, pat9125_b, pat9125_s); - return; - } -/* - if (code_seen('R')) - { - unsigned char res = (int)code_value(); - LOG("pat9125_init(xres=yres=%d)=%d\n", res, pat9125_init(res, res)); - } -*/ - if (code_seen('X')) - { - pat9125_x = (int)code_value(); - LOG("pat9125_x=%d\n", pat9125_x); - } - if (code_seen('Y')) - { - pat9125_y = (int)code_value(); - LOG("pat9125_y=%d\n", pat9125_y); - } - if (code_seen('L')) - { - fsensor_log = (int)code_value(); - LOG("fsensor_log=%d\n", fsensor_log); - } + printf("x=%d y=%d b=%d s=%d\n", pat9125_x, pat9125_y, pat9125_b, pat9125_s); + return; + } + if (strchr_pointer[1+4] == '!') + { + pat9125_update(); + printf("x=%d y=%d b=%d s=%d\n", pat9125_x, pat9125_y, pat9125_b, pat9125_s); + return; + } + /* + if (code_seen('R')) + { + unsigned char res = (int)code_value(); + LOG("pat9125_init(xres=yres=%d)=%d\n", res, pat9125_init(res, res)); + } + */ + if (code_seen('X')) + { + pat9125_x = (int)code_value(); + LOG("pat9125_x=%d\n", pat9125_x); + } + if (code_seen('Y')) + { + pat9125_y = (int)code_value(); + LOG("pat9125_y=%d\n", pat9125_y); + } + if (code_seen('L')) + { + fsensor_log = (int)code_value(); + LOG("fsensor_log=%d\n", fsensor_log); + } } #endif //PAT9125 diff --git a/Firmware/MK3-MMU-FSensorBN2234.hex b/Firmware/MK3-MMU-FSensorBN2234.hex deleted file mode 100644 index 1632b971f4..0000000000 --- a/Firmware/MK3-MMU-FSensorBN2234.hex +++ /dev/null @@ -1,14217 +0,0 @@ -:100000000C94BD300C94EE300C94EE300C94EE3029 -:100010000C94EE300C94C7EE0C94EE300C94EE3051 -:100020000C9458F20C94EE300C94419C0C94EE30ED -:100030000C94EE300D94964D0C94EE300C94EE3002 -:100040000C94EE300C94FCB00C94EE300C94EE302A -:100050000C94EE300C94EE300D94173B0D94E48824 -:100060000C94EE300C942AAD0C94EE300C94EE30DF -:100070000C94EE300C94EE300C94EE300C94EE3088 -:100080000C94EE300C94EE300C94EE300C94EE3078 -:100090000C94E6AC0C94EE300C94EE300C94EE30F4 -:1000A0000C94EE300C94EE300C94EE300C94EE3058 -:1000B0000C94EE300C94EE300C94EE300C94EE3048 -:1000C0000C94EE300C94EE300C94EE300C9456C43C -:1000D0000C94EE300C94EE300C94EE300C94EE3028 -:1000E0000C94EE30E39AE79AED9AF69A0F9B2C9BCC -:1000F000699BA09B70D986D999D9A6D9B0D9DED9E8 -:10010000FFD905DA13DA16DA18DA22DA33DA44DA42 -:10011000520184018A015E01F2018001A2014001C5 -:100120007201800180018001800180018001A601AF -:1001300080018001800180018001800180018001B7 -:10014000800146018801C6018C01BA01A0015A0153 -:10015000FC01C801D2010E028201A8015C01CE019E -:100160003801B2013E014A019601F801BE01AA011F -:100170007E0104029A013E01B401EA01E801F001A6 -:10018000E601EE016001B001D4017601EC0110023C -:1001900090019E017A01CA01DC01D401C201F4017F -:1001A000C001084AD73B3BCE016E84BCBFFDC12FC6 -:1001B0003D6C74319ABD56833DDA3D00C77F11BE58 -:1001C000D9E4BB4C3E916BAAAABE000000803F055B -:1001D000A84CCDB2D44EB93836A9020C50B991868C -:1001E00088083CA6AAAA2ABE000000803F076342F6 -:1001F00036B79BD8A71A39685618AEBAAB558C1DBE -:100200003CB7CC5763BD6DEDFD753EF6177231BF3F -:10021000000000803F08000000BE922449123EAB5F -:10022000AAAA2ABECDCCCC4C3E00000080BEABAA10 -:10023000AAAA3E00000000BF000000803F000000AE -:100240000000084178D3BB4387D1133D190E3CC34E -:10025000BD4282AD2B3E68EC8276BED98FE1A93ECD -:100260004C80EFFFBE01C4FF7F3F00000000000094 -:100270000D940B840D945C000D94488A0D944F846A -:100280000D945C280D9433010D9436250D94002AAD -:100290000D94DF4C0D941C840D949C020D94043538 -:1002A0000D94B81F0D9400270D9430250D94348BB8 -:1002B0000D949A000D9450550D9418840D94B12608 -:1002C0000D9481860D940B070D94AA250D942E890B -:1002D0000D94BA010D94AC250D9497010D94FD5128 -:1002E0000D94494C0D94DE280D948F890D949586BC -:1002F0000D94E51F0D94C3860D94D09B0D9434840A -:100300000D940E2A0D9497550D9407270D94D61F22 -:100310000D9408550D94C8260D941C550D94F78A1C -:100320000D94AF860D943C250D9446070D942084C2 -:100330000D94238B0D943C840D94DB1F0D94B98692 -:100340000D944A550D942B270D94A8250D944F29F3 -:100350000D9415840D942E840D9405A70D94668A32 -:100360000D948B860D9411840D9442840D94332545 -:100370000D94534C0D942E550D942A000D942A84FF -:100380000D94FA860D94E6860D94DA8A0D9416552E -:100390000D9464550D94D2860D94D6000D94078467 -:1003A0000D94D11F0D9472550D9404870D94392529 -:1003B0000D94BD8A0D94584C0D94DC860D944D4CD3 -:1003C0000D945C890D94CA890D94AE250D947286A6 -:1003D0000D944A840D9446840D949D860D947786E1 -:1003E0000D946D860D9493260D94F0860D947500F2 -:1003F0000D9426840D94E01F0D9456550D94A08AFB -:100400000D94AB340D94148B0D9438840D94D14C11 -:100410000D9465010D94F7000D94A6250D9480555B -:100420000D94A5860D94838A6E616E00696E6600D8 -:100430004E414E494E495459494E46CDCCCC3D0AC9 -:10044000D7233C17B7D13877CC2B329595E6241FAC -:10045000B14F0A000020410000C84200401C462065 -:10046000BCBE4CCA1B0E5AAEC59D7400407A10F338 -:100470005A00A0724E18090010A5D4E80000E876D2 -:1004800048170000E40B54020000CA9A3B00000029 -:10049000E1F505000080969800000040420F000042 -:1004A00000A08601000000102700000000E8030003 -:1004B0000000006400000000000A000000000001CD -:1004C00000000000002C76D888DC674F0823DFC1CD -:1004D000DFAE59E1B1B796E5E3E453C63AE6519988 -:1004E0007696E8E6C28426EB898C9B62ED407C6FB1 -:1004F000FCEFBC9C9F40F2BAA56FA5F490055A2A68 -:10050000F75C936B6CF9676DC11BFCE0E40D47FE73 -:10051000F520E6B500D0ED902E0300943577050068 -:1005200080841E080000204E0A000000C80C3333EF -:1005300033330F986E12831141EF8D2114893BE6FE -:100540005516CFFEE6DB18D1844B381BF77C1D9087 -:100550001DA4BBE424203284725E228100C9F124F0 -:10056000ECA1E53D276364696E6F70737578585B25 -:1005700000256420627974657320777269747465EC -:100580006E20746F20454550524F4D20617420619C -:100590006464726573732030782530347800443396 -:1005A000202D20526561642F57726974652045457E -:1005B00050524F4D0A0020436F756E7420583A20F8 -:1005C000005344207072696E74696E67206279749A -:1005D0006520004E6F7420696E206661726D206D1B -:1005E0006F64652E00416374697665204578747286 -:1005F000756465723A2000496E76616C69642065A5 -:1006000078747275646572005A204F6666736574FB -:1006100000556E6B6E6F776E20636F6D6D616E64EB -:100620003A2022007A5F6D61783A20007A5F6D6926 -:100630006E3A2000795F6D61783A2000795F6D69CC -:100640006E3A2000785F6D61783A2000785F6D69BE -:100650006E3A20005265706F7274696E6720656E25 -:100660006473746F70207374617475730000534900 -:100670004C454E54004E4F524D414C002553204D99 -:100680004F44453A2050657263656E7420646F6E06 -:10069000653A2025643B207072696E742074696D20 -:1006A000652072656D61696E696E6720696E206D87 -:1006B000696E733A2025640A00456E642066696C91 -:1006C00065206C69737400426567696E2066696CA9 -:1006D00065206C6973740025643A2025640A000A59 -:1006E00050494E44412074656D7065726174757235 -:1006F000653A20252E3166205A2073686966742079 -:10070000286D6D293A20252E3366000A53746570D2 -:100710003A2025642F360A000A537465703A202562 -:10072000642F362028736B6970706564290A5049FC -:100730004E44412074656D70657261747572653ADE -:10074000202564205A20736869667420286D6D29FD -:100750003A300A000A5A45524F3A20252E33660A8B -:100760000073746172742074656D70657261747564 -:1007700072653A20252E31660A0025642020252E38 -:10078000326600255320583A20252E356620593AE6 -:1007900020252E3566205A3A20252E35660A004E31 -:1007A0006F7420696E206661726D206D6F64652EB6 -:1007B0000025640045303A25642052504D0A5052BD -:1007C0004E303A25642052504D0A00256400417590 -:1007D000746F0020452F443D00416476616E63656F -:1007E000204B3D004D3232302053256900255346C1 -:1007F000696C616D656E742073657474696E67737E -:100800003A2044697361626C65640A002553466945 -:100810006C616D656E742073657474696E67733A8C -:100820000A25532020204D3230302044252E3266B8 -:100830000A002553526574726163743A20533D4C2B -:10084000656E67746820286D6D2920463A5370657F -:10085000656420286D6D2F6D29205A3A205A4C6905 -:10086000667420286D6D290A25532020204D3230D2 -:10087000372053252E32662046252E3266205A25F3 -:100880002E32660A25535265636F7665723A20539D -:100890003D4578747261206C656E67746820286DC0 -:1008A0006D2920463A537065656420286D6D2F6D63 -:1008B000290A25532020204D3230382053252E324E -:1008C000662046252E32660A25534175746F2D52D7 -:1008D0006574726163743A20533D3020746F2064F4 -:1008E000697361626C652C203120746F20696E74AD -:1008F00065727072657420657874727564652D6FA9 -:100900006E6C79206D6F76657320617320726574EB -:100910007261637473206F72207265636F766572A3 -:100920006965730A25532020204D32303920532524 -:10093000640A002553504944206865617462656407 -:100940002073657474696E67733A0A2553202020FA -:100950004D3330342050252E32662049252E326604 -:100960002044252E32660A002553504944207365E1 -:100970007474696E67733A0A25532020204D333012 -:10098000312050252E32662049252E3266204425FE -:100990002E32660A00255353746570732070657299 -:1009A00020756E69743A0A255320204D393220583B -:1009B000252E32662059252E3266205A252E326683 -:1009C0002045252E32660A25534D6178696D756D77 -:1009D00020666565647261746573202D206E6F7288 -:1009E0006D616C20286D6D2F73293A0A25532020E4 -:1009F0004D3230332058252E32662059252E32664E -:100A0000205A252E32662045252E32660A25534D62 -:100A10006178696D756D2066656564726174657372 -:100A2000202D20737465616C746820286D6D2F73A0 -:100A3000293A0A255320204D3230332058252E32B2 -:100A4000662059252E3266205A252E3266204525ED -:100A50002E32660A25534D6178696D756D2061638C -:100A600063656C65726174696F6E202D206E6F72A4 -:100A70006D616C20286D6D2F7332293A0A25532041 -:100A8000204D3230312058256C752059256C752049 -:100A90005A256C752045256C750A25534D6178697A -:100AA0006D756D20616363656C65726174696F6EED -:100AB000202D20737465616C746820286D6D2F7310 -:100AC00032293A0A255320204D3230312058256CE6 -:100AD000752059256C75205A256C752045256C7537 -:100AE0000A2553416363656C65726174696F6E3A80 -:100AF00020533D616363656C65726174696F6E2C30 -:100B000020543D7265747261637420616363656C27 -:100B100065726174696F6E0A255320204D3230343E -:100B20002053252E32662054252E32660A25534145 -:100B30006476616E636564207661726961626C657A -:100B4000733A20533D4D696E206665656472617429 -:100B50006520286D6D2F73292C20543D4D696E2022 -:100B600074726176656C2066656564726174652077 -:100B7000286D6D2F73292C20423D6D696E696D754E -:100B80006D207365676D656E742074696D652028CE -:100B90006D73292C20583D6D6178696D756D2058F5 -:100BA00059206A65726B20286D6D2F73292C2020C7 -:100BB0005A3D6D6178696D756D205A206A65726B5A -:100BC00020286D6D2F73292C2020453D6D6178699B -:100BD0006D756D2045206A65726B20286D6D2F73D1 -:100BE000290A255320204D3230352053252E3266D8 -:100BF0002054252E32662042252E32662058252E7E -:100C000032662059252E3266205A252E326620451E -:100C1000252E32660A2553486F6D65206F66667310 -:100C2000657420286D6D293A0A255320204D3230F5 -:100C3000362058252E32662059252E3266205A2518 -:100C40002E32660A004D4D55203C3D202746256436 -:100C5000202564270A00504944204175746F74753B -:100C60006E652066696E69736865642120507574CD -:100C700020746865206C617374204B702C204B6964 -:100C800020616E64204B6420636F6E7374616E74B8 -:100C9000732066726F6D2061626F766520696E7475 -:100CA0006F20436F6E66696775726174696F6E2E2F -:100CB0006800504944204175746F74756E652066F4 -:100CC00061696C6564212074696D656F75740020BD -:100CD000403A00543A00423A005049442041757469 -:100CE0006F74756E65206661696C6564212054655A -:100CF0006D706572617475726520746F6F206869BC -:100D0000676800204B643A2000204B693A2000209D -:100D10004B703A200020436C617373696320504923 -:100D20004420002054753A2000204B753A200020C2 -:100D30006D61783A2000206D696E3A200020643A97 -:100D4000200020626961733A200020453A00205A51 -:100D50003A0020593A0020453A00205A3A002059DA -:100D60003A00583A00005A30005A310059300059C0 -:100D70003100583000583100456E642073746F7034 -:100D8000732064696167002E0044656C6574696F47 -:100D90006E206661696C65642C2046696C653A203A -:100DA0000046696C652064656C657465643A004E44 -:100DB0006F74205344207072696E74696E670050BE -:100DC00072696E742073617665640053442070729A -:100DD000696E7420706175736564000A002F000AE3 -:100DE000002F2F20616374696F6E3A63616E6365D3 -:100DF0006C0043524153485F43414E43454C0043CE -:100E0000524153485F5245434F5645520043524169 -:100E100053485F5245434F5645520022283229001D -:100E20005400496E76616C6964205420636F646578 -:100E30002E00556E6B6E6F776E204D20636F64656C -:100E40003A202573200A006E6F2076616C69642059 -:100E5000636F6D6D616E64002C20002C20002C20CF -:100E6000006E2F61002C20002C20002C20006E2F03 -:100E700061002F00503A005761697420666F72203C -:100E800050494E4441207461726765742074656DE9 -:100E900070657261747572653A004C414E4720531B -:100EA000454C20464F52434544002228312900300A -:100EB000303030303030302D303030302D30303038 -:100EC000302D303030302D30303030303030303028 -:100ED0003030300020555549443A00310020455803 -:100EE0005452554445525F434F554E543A00507248 -:100EF000757361206933204D4B3300204D414348C9 -:100F0000494E455F545950453A00312E3000206219 -:100F100061736564206F6E204D61726C696E20464E -:100F200049524D574152455F55524C3A687474705E -:100F3000733A2F2F6769746875622E636F6D2F7017 -:100F40007275736133642F50727573612D466972C7 -:100F50006D776172652050524F544F434F4C5F562E -:100F6000455253494F4E3A004649524D574152451A -:100F70005F4E414D453A50727573612D4669726DF1 -:100F80007761726520004D31313320530020423AA1 -:100F90000020453A00543A0020413A0020503A00DF -:100FA0002042403A0020403A00202F003A002054CE -:100FB00000202F0020423A00202F006F6B20543A6F -:100FC000002569206D696E2C2025692073656300FA -:100FD000496E76616C6964204D20636F64653A20C8 -:100FE0002573200A00556E6B6E6F776E2047206365 -:100FF0006F64653A202573200A004D65736820628E -:101000006564206C6576656C696E67206E6F742010 -:101010006163746976652E000A002020000A4D6520 -:1010200061737572656420706F696E74733A000A3B -:101030005A20736561726368206865696768743AED -:1010400020002C004E756D20582C593A2000206D40 -:101050006963726F6E730045786365737369766553 -:1010600020626564206C6576656C696E6720636FCD -:101070007272656374696F6E3A2000473238205788 -:10108000300050494E44412070726F6265206361A8 -:101090006C6962726174696F6E207374617274003E -:1010A000473238205730004D3234005345545F43A7 -:1010B000484F505F005345545F535445505F0053B1 -:1010C00045545F574156455F00544D435F004352BE -:1010D0004153485F005072657373206B6E6F6220DE -:1010E000746F2070726568656174206E6F7A7A6CB7 -:1010F0006520616E6420636F6E74696E75652E0085 -:10110000506C6561736520707265737320746865D7 -:10111000206B6E6F6220746F20756E6C6F6164203F -:1011200066696C616D656E740052656D6F766520E1 -:101130006F6C642066696C616D656E7420616E64AD -:1011400020707265737320746865206B6E6F622007 -:10115000746F207374617274206C6F6164696E6760 -:10116000206E65772066696C616D656E742E006116 -:101170006E6420707265737320746865206B6E6F87 -:101180006200496E736572742066696C616D656E8C -:101190007400436F6C6F72206E6F7420636F727295 -:1011A0006563740046696C616D656E74206E6F7462 -:1011B000206C6F61646564004368616E67656420DC -:1011C000636F72726563746C793F004C6F61646920 -:1011D0006E6720636F6C6F72004368616E67652095 -:1011E000737563636573732100506C65617365206B -:1011F0006F70656E2069646C657220616E64207228 -:10120000656D6F76652066696C616D656E74206DC5 -:10121000616E75616C6C792E005761732066696C24 -:10122000616D656E7420756E6C6F6164207375639B -:101230006365737366756C3F00506C656173652000 -:10124000757067726164652E004E657720666972FD -:101250006D776172652076657273696F6E20617655 -:1012600061696C61626C653A0057616974696E67A7 -:1012700020666F722050494E44412070726F626543 -:1012800020636F6F6C696E670043726173682064DE -:10129000657465637465642E20526573756D652091 -:1012A0007072696E743F0043726173682064657484 -:1012B00065637465642E00457874727564657200A8 -:1012C00043686F6F73652065787472756465723AF0 -:1012D0000043686F6F73652066696C616D656E743D -:1012E0003A004D32303020496E76616C6964206579 -:1012F0007874727564657220006F70656E00545268 -:1013000049474745524544004E6F206D6F76652E24 -:10131000005761697420666F7220757365722E2E96 -:101320002E00536F6D652070726F626C656D206565 -:101330006E636F756E74657265642C205A2D6C65D2 -:1013400076656C6C696E6720656E666F7263656446 -:10135000202E2E2E00537461626C6520616D6269CF -:10136000656E742074656D70657261747572652048 -:1013700032312D323643206973206E6565646564B1 -:101380002061207269676964207374616E642069EA -:10139000732072657175697265642E00506C6561A9 -:1013A00073652072756E2058595A2063616C6962AA -:1013B000726174696F6E2066697273742E00536C6B -:1013C0006565702E2E2E0073746172740A0061645C -:1013D000635F696E69740A001B5B324A1B5B313BB9 -:1013E00031484F726967696E616C20507275736124 -:1013F0002069331B5B323B33485072757361205256 -:101400006573656172636800466163746F72792009 -:101410005245534554004E6F7620313520323031DD -:101420003800436F6D70696C65643A2000286E6FF8 -:101430006E652C2064656661756C7420636F6E66E2 -:10144000696729004E6F76203135203230313820DF -:1014500031363A30383A34350020352E302E322DA0 -:10146000545A422D323233340A002055706C6F6169 -:101470006420696E2070726F677265737300205A02 -:101480003A0020593A0020583A0043524153485FED -:1014900044455445435445445859004352415348E8 -:1014A0005F444554454354454459004352415348D1 -:1014B0005F444554454354454458004D323900502B -:1014C00072757361206933204D4B332072656164FE -:1014D000792E00426C61636B6F7574206F63637566 -:1014E000727265642E205265636F76657220707229 -:1014F000696E743F0053656C667465737420776918 -:101500006C6C2062652072756E20746F2063616C54 -:1015100069627261746520616363757261746520CC -:1015200073656E736F726C657373207265686F6D2F -:10153000696E672E00546865726520697320737444 -:10154000696C6C2061206E65656420746F206D612C -:101550006B65205A2063616C6962726174696F6E99 -:101560002E20506C6561736520666F6C6C6F772000 -:10157000746865206D616E75616C2C2063686170A4 -:101580007465722046697273742073746570732C6D -:101590002073656374696F6E2043616C6962726168 -:1015A00074696F6E20666C6F772E005072696E746E -:1015B000657220686173206E6F74206265656E20AD -:1015C00063616C69627261746564207965742E2050 -:1015D000506C6561736520666F6C6C6F7720746802 -:1015E00065206D616E75616C2C2063686170746537 -:1015F000722046697273742073746570732C207343 -:10160000656374696F6E2043616C696272617469AD -:101610006F6E20666C6F772E004F6C64207365745C -:1016200074696E677320666F756E642E20446566FC -:1016300061756C74205049442C2045737465707337 -:10164000206574632E2077696C6C20626520736559 -:10165000742E005761726E696E673A20626F74680B -:10166000207072696E746572207479706520616E85 -:1016700064206D6F74686572626F61726420747942 -:101680007065206368616E6765642E005761726ED5 -:10169000696E673A207072696E7465722074797031 -:1016A00065206368616E6765642E005761726E69BC -:1016B0006E673A206D6F74686572626F6172642044 -:1016C00074797065206368616E6765642E00202000 -:1016D000506C616E6E6572427566666572427974B1 -:1016E00065733A20002046726565204D656D6F7206 -:1016F000793A2000204C61737420557064617465E0 -:10170000643A2000506F77657255700045787465B3 -:10171000726E616C2053504920666C61736820576B -:101720003235583230434C206E6F742072657370BE -:101730006F6E64696E672E006572726F72207772C9 -:101740006974696E6720746F2066696C6500656EE8 -:101750006473746F7073206869743A20006F6B0053 -:1017600043726173684465746563742044495341EE -:10177000424C454400437261736844657465637408 -:1017800020454E41424C45442100207C2041757447 -:10179000686F723A200020536F667477617265201B -:1017A000526573657400205761746368646F6720C5 -:1017B0005265736574002042726F776E206F757486 -:1017C000205265736574002045787465726E616C93 -:1017D00020526573657400446F6E6520736176698D -:1017E0006E672066696C652E0058595A2063616CDB -:1017F0006962726174696F6E20616C6C20726967D6 -:1018000068742E20536B65772077696C6C20626555 -:1018100020636F72726563746564206175746F6DA7 -:1018200061746963616C6C792E0058595A20636148 -:101830006C6962726174696F6E20616C6C20726990 -:101840006768742E20582F59206178657320617263 -:101850006520736C696768746C7920736B65776554 -:10186000642E20476F6F64206A6F62210058595AB6 -:101870002063616C6962726174696F6E206F6B2E98 -:1018800020582F592061786573206172652070653A -:101890007270656E646963756C61722E20436F6E41 -:1018A00067726174756C6174696F6E732100585949 -:1018B0005A2063616C6962726174696F6E2066613F -:1018C000696C65642E2052696768742066726F6E59 -:1018D000742063616C6962726174696F6E20706FED -:1018E000696E74206E6F7420726561636861626CEA -:1018F000652E0058595A2063616C6962726174697F -:101900006F6E206661696C65642E2046726F6E741E -:101910002063616C6962726174696F6E20706F69B7 -:101920006E7473206E6F7420726561636861626C9F -:10193000652E0058595A2063616C6962726174693E -:101940006F6E206661696C65642E20506C656173F2 -:101950006520636F6E73756C7420746865206D61AB -:101960006E75616C2E0058595A2063616C69627201 -:101970006174696F6E20636F6D70726F6D697365EE -:10198000642E2052696768742066726F6E742063DB -:10199000616C6962726174696F6E20706F696E74D8 -:1019A000206E6F7420726561636861626C652E00E1 -:1019B00058595A2063616C6962726174696F6E2054 -:1019C000636F6D70726F6D697365642E2046726F00 -:1019D0006E742063616C6962726174696F6E2070ED -:1019E0006F696E7473206E6F7420726561636861D5 -:1019F000626C652E0058595A2063616C696272618D -:101A000074696F6E206661696C65642E204265643E -:101A10002063616C6962726174696F6E20706F69B6 -:101A20006E7420776173206E6F7420666F756E64BC -:101A30002E00506C6561736520706C616365207366 -:101A40007465656C207368656574206F6E206865C9 -:101A500061746265642E0044697374616E6365200D -:101A60006265747765656E20746970206F66207496 -:101A70006865206E6F7A7A6C6520616E6420746888 -:101A800065206265642073757266616365206861B4 -:101A900073206E6F74206265656E207365742079A3 -:101AA00065742E20506C6561736520666F6C6C6F79 -:101AB0007720746865206D616E75616C2C20636899 -:101AC00061707465722046697273742073746570F6 -:101AD000732C2073656374696F6E2046697273742A -:101AE000206C617965722063616C696272617469EE -:101AF0006F6E2E00506C61636520612073686565B0 -:101B000074206F6620706170657220756E646572F6 -:101B100020746865206E6F7A7A6C652064757269CE -:101B20006E67207468652063616C696272617469B4 -:101B30006F6E206F66206669727374203420706F38 -:101B4000696E74732E20496620746865206E6F7A02 -:101B50007A6C6520636174636865732074686520BE -:101B600070617065722C20706F776572206F666689 -:101B700020746865207072696E74657220696D6D7D -:101B80006564696174656C792E00506C656173657C -:101B90002072656D6F766520737465656C2073685F -:101BA0006565742066726F6D206865617462656436 -:101BB0002E00497320737465656C207368656574C5 -:101BC000206F6E20686561746265643F00206F66F7 -:101BD000203400536561726368696E6720626564D2 -:101BE0002063616C6962726174696F6E20706F69E5 -:101BF0006E7400206F662039004D656173757269DF -:101C00006E67207265666572656E636520686569DA -:101C1000676874206F662063616C696272617469C1 -:101C20006F6E20706F696E7400506C656173652013 -:101C3000636C65616E20746865206E6F7A7A6C657E -:101C400020666F722063616C6962726174696F6E85 -:101C50002E20436C69636B207768656E20646F6E1D -:101C6000652E004175746F20686F6D650078797A14 -:101C700063616C5F6D656173737572655F656E74CA -:101C800065720A0078797A63616C5F73706972615A -:101C90006C382063783D25642063793D2564207A83 -:101CA000303D256420647A3D256420726164697545 -:101CB000733D25642061643D25640A0078797A6368 -:101CC000616C5F7365617263685A206E6F2073691F -:101CD000676E616C0A20783D256C6420793D256C27 -:101CE00064207A3D256C640A00204F4E2D534947ED -:101CF0004E414C20617420783D256420793D256457 -:101D0000207A3D25642061643D25640A0078797A53 -:101D100063616C5F7365617263685A20783D256CFE -:101D20006420793D256C64207A3D256C640A000AA4 -:101D300000253032780078797A63616C5F73636173 -:101D40006E5F706978656C735F333278333220630D -:101D5000783D25642063793D2564206D696E5F7A46 -:101D60003D2564206D61785F7A3D25640A00202559 -:101D700032642025640A000A002530327800206D84 -:101D8000696E3D2564206D61783D25642064696637 -:101D90003D25640A006D61785F633D253264206DE6 -:101DA00061785F6C3D25640A006D61785F633D2555 -:101DB00064206D61785F723D2564206D61785F6D90 -:101DC000617463683D25640A0020783D25642079AC -:101DD0003D2564207A3D25640A0020706174746595 -:101DE000726E20666F756E642061742025642025F4 -:101DF000640A000000F000F801FC03FE07FE07FE85 -:101E000007FE07FC03F801F000000073697A656FB4 -:101E10006628746F74616C293D25640A0073697AC1 -:101E2000656F6628626C6F636B5F6275666665726C -:101E3000293D25640A0078797A63616C5F6D65617C -:101E400073737572655F6C656176650A00706F69A2 -:101E50006E743D256420783D256420793D256420FD -:101E60007A3D25640A0058025802584D584DB00476 -:101E7000F055F055B00478797A63616C5F66696EED -:101E8000645F6265645F696E64756374696F6E5FD9 -:101E900073656E736F725F706F696E745F787920AF -:101EA000783D256C6420793D256C64207A3D256C55 -:101EB000640A00203C20005741524E494E473A20C8 -:101EC00046726F6E7420706F696E74206E6F74202E -:101ED000726561636861626C652E205920636F6F63 -:101EE0007264696E6174653A000000004041000050 -:101EF000C04000005C430000C04000005C430000A4 -:101F000046430000404100004643497465726174D5 -:101F1000696F6E3A200043616C6962726174696F27 -:101F20006E206661696C65642120436865636B207F -:101F3000746865206178657320616E642072756EC7 -:101F400020616761696E2E00773235783230636CBC -:101F50005F63666D0A00773235783230636C5F6597 -:101F60006E7465720A00504154393132355F524502 -:101F7000535F593D256868750A0050415439313224 -:101F8000355F5245535F583D256868750A002074D7 -:101F90006F6F206C6F6E6720657874727573696FF0 -:101FA0006E2070726576656E7465640020636F6C78 -:101FB0006420657874727573696F6E2070726576CF -:101FC000656E74656400256920686F7572732025DD -:101FD00069206D696E757465730054494D454F55A0 -:101FE000543A004D3131300046756C6C2052582007 -:101FF000427566666572006673656E736F725F73B5 -:10200000746F705F616E645F736176655F70726933 -:102010006E740A006673656E736F725F72657374B7 -:102020006F72655F7072696E745F616E645F636F1B -:102030006E74696E75650A0044495341424C4544CB -:102040000A00454E41424C4544004653656E736F4D -:10205000722025530A00504154393132355F696E80 -:1020600069743A256868750A00504154393132352F -:102070005F696E69743A256868750A005041543981 -:102080003132355F696E69743A256868750A0050A7 -:10209000415439313235206E6F7420726573706F20 -:1020A0006E64696E672028256429210A00446F6EDA -:1020B00065207072696E74696E672066696C650070 -:1020C0004E6F204C696E65204E756D62657220778B -:1020D00069746820636865636B73756D2C204C614F -:1020E0007374204C696E653A20004C696E65204E11 -:1020F000756D626572206973206E6F74204C617318 -:1021000074204C696E65204E756D6265722B312CA2 -:10211000204C617374204C696E653A2000667365CB -:102120006E736F725F6175746F6C6F61645F63680B -:1021300065636B5F7374617274202D206175746FB9 -:102140006C6F616420454E41424C45440A00667301 -:10215000656E736F725F6175746F6C6F61645F63DE -:102160006865636B5F73746F70202D206175746F89 -:102170006C6F61642044495341424C45440A00530A -:10218000544F505045442E20005072696E74657251 -:102190002073746F707065642064756520746F209F -:1021A0006572726F72732E2046697820746865209C -:1021B0006572726F7220616E6420757365204D398F -:1021C000393920746F20726573746172742E2028FF -:1021D00054656D70657261747572652069732072E3 -:1021E000657365742E20536574206974206166746C -:1021F00065722072657374617274696E6729004E2E -:102200006F20436865636B73756D20776974682010 -:102210006C696E65206E756D6265722C204C617301 -:1022200074204C696E653A2000636865636B737552 -:102230006D206D69736D617463682C204C617374DB -:10224000204C696E653A200053657474696E67733B -:102250002053746F7265640053746F7265642073E9 -:10226000657474696E6773207265747269657665EA -:10227000640048617264636F6465642044656661EC -:10228000756C742053657474696E6773204C6F614C -:1022900064656400563200000000C8420000C84275 -:1022A0000000C84300008C4300004843000048433E -:1022B000000040410000F042E8030000E803000095 -:1022C000C80000008813000000409C4400409C446B -:1022D0000000000000000000204E0000000020412F -:1022E00000002041CDCCCC3E00002040000000008A -:1022F0000000000000000000CDCCCC3E3D0A814132 -:10230000FF08433EB099AB438F42FC42E65A343F4C -:102310004C62B04500000000004040000034420024 -:102320000000000000000000000041000000E03F4D -:102330000000C8420000C842000040410000F042D6 -:10234000C0030000C0030000C800000088130000A4 -:10235000454550524F4D204572726F7200436F6E6B -:1023600074696E7565207769746820616E6F746832 -:10237000657220626F7764656E3F00250020202023 -:1023800020202000202020202020004552415349B9 -:102390004E4720616C6C2064617461004661637417 -:1023A0006F72792052455345540000007F430080EE -:1023B00054430000524300000000000080C09A997E -:1023C000193E00000000000080C09A99193E24F4D4 -:1023D000D43050C38E20C2A24017828B7011127A63 -:1023E000910D816CD90AA861E108C758660761514F -:1023F00043061E4B5D05C145A7041A411104093D62 -:102400009803713931034036DB0265339102D430D1 -:102410005402802E1D02632CEE01752AC501B028DE -:10242000A001102781018F2564012B244B01E0229C -:102430003401AC211F018D200D01801FFC00841E82 -:10244000ED00971DDF00B81CD200E61BC600201B64 -:10245000BC00641AB200B219A8000A19A0006A18D8 -:102460009900D117910040178B00B51684003116E2 -:102470007E00B31579003A157300C7146F00581425 -:102480006A00EE1366008813630025135E00C7120E -:102490005B006C12570015125400C11151007011ED -:1024A0004F0021114B00D61049008D1047004610F7 -:1024B000440002104200C00F4000800F3E00420F57 -:1024C0003C00060F3B00CB0E3800930E37005C0E2D -:1024D0003500270E3400F30D3200C10D3100900D90 -:1024E0003000600D2E00320D2D00050D2C00D90C92 -:1024F0002B00AE0C2900850C29005C0C2700350C44 -:1025000027000E0C2600E80B2400C40B2400A00BAF -:1025100023007D0B23005A0B2100390B2100180BDF -:102520002000F80A1F00D90A1E00BB0A1E009D0ADF -:102530001D00800A1D00630A1C00470A1B002C0AAC -:102540001B00110A1A00F7091A00DD091900C40955 -:102550001900AB091900920917007B0918006309DB -:1025600017004C09160036091600200916000A0942 -:102570001500F5081500E0081400CC081400B80890 -:102580001400A4081400900813007D0812006B08C2 -:1025900013005808120046081200340811002308DE -:1025A00011001208110001081100F0071000E007E7 -:1025B0001000D0071000C0071000B0070F00A107DF -:1025C000100091070E0083070F0074070F006507C6 -:1025D0000E0057070E0049070E003B070D002E079F -:1025E0000E0020070D0013070D0006070D00F90669 -:1025F0000C00ED060D00E0060C00D4060C00C80629 -:102600000C00BC060C00B0060C00A4060B009906DA -:102610000C008D060B0082060B0077060B006C0683 -:102620000B0061060A0057060B004C060A00420622 -:102630000A0038060A002E060A0024060A001A06B6 -:102640000A001006090007060A00FD050900F40546 -:102650000900EB050900E2050900D9050900D005CC -:102660000900C7050900BE050900B5050800AD054C -:102670000800A50509009C050800940508008C05C4 -:102680000800840508007C050800740508006C0536 -:102690000700650508005D050700560508004E05A2 -:1026A0000700470507004005080038050700310509 -:1026B00007002A050700230507001C05060016056C -:1026C00007000F0507000805060002050700FB04C8 -:1026D0000600F5040700EE040600E8040600E20424 -:1026E0000700DB040600D5040600CF040600C90479 -:1026F0000600C3040600BD040600B7040600B104CA -:102700000500AC040600A6040600A00405009B0416 -:10271000060095040500900406008A04050085045F -:102720000500800406007A040500750405007004A5 -:1027300005006B04050066040500610405005C04E7 -:10274000050057040500520405004D040500480427 -:102750000500430405003E0404003A040500350466 -:102760000500300404002C040500270404002304A1 -:1027700005001E0404001A040400160405001104D8 -:1027800004000D040400090405000404040000040E -:102790000400FC030400F8030400F4030400F00345 -:1027A0000400EC030400E8030400E4030400E00375 -:1027B0000400DC030400D8030400D4030400D003A5 -:1027C0000400CC030400C8030300C503030024F481 -:1027D00004D9201BC40C5C0E9804C4095F02650771 -:1027E0007101F405F900FB04B30048048700C1033C -:1027F00069005803550003034500BE023A008402F5 -:10280000310053022A002902250004022000E401BD -:102810001C00C8011900AF011700980114008401C1 -:102820001300710110006101100051010E004301FD -:102830000D0036010B002B010B0020010B001501D0 -:1028400009000C01090003010800FB000800F30067 -:102850000800EB000700E4000600DE000600D800D8 -:102860000600D2000600CC000500C7000500C2002B -:102870000500BD000400B9000400B5000400B1006B -:102880000400AD000400A9000400A5000300A2009C -:1028900003009F0004009B000300980003009500C4 -:1028A000020093000300900003008D0002008B00E3 -:1028B00003008800020086000200840003008100FB -:1028C00002007F0002007D0002007B000200790010 -:1028D000020077000100760002007400020072001E -:1028E0000100710002006F0002006D0001006C0029 -:1028F00002006A0001006900020067000100660032 -:102900000100650001006400020062000100610036 -:102910000100600001005F0002005D0001005C003A -:1029200001005B0001005A0001005900010058003D -:10293000010057000100560001005500010054003D -:10294000010053000000530001005200010051003B -:102950000100500001004F0001004E0000004E0039 -:1029600001004D0001004C0001004B0000004B0035 -:1029700001004A0001004900010048000000480031 -:10298000010047000100460000004600010045002C -:102990000000450001004400010043000000430026 -:1029A000010042000000420001004100000041001F -:1029B0000100400001003F0000003F0001003E0018 -:1029C00000003E0001003D0000003D0001003C0011 -:1029D00000003C0000003C0001003B0000003B0008 -:1029E00001003A0000003A000100390000003900FF -:1029F00001003800000038000000380001003700F6 -:102A000000003700010036000000360000003600EC -:102A100001003500000035000000350001003400E1 -:102A200000003400000034000100330000003300D7 -:102A300000003300010032000000320000003200CC -:102A400001003100000031000000310001003000C1 -:102A5000000030000000300001002F0000002F00B7 -:102A600000002F0000002F0001002E0000002E00AB -:102A700000002E0001002D0000002D0000002D00A0 -:102A800000002D0001002C0000002C0000002C0094 -:102A900000002C0001002B0000002B0000002B0088 -:102AA00000002B0001002A0000002A0000002A007C -:102AB00000002A0001002900000029000000290070 -:102AC0000000290000002900010028000000280063 -:102AD0000000280000002800000028000100270056 -:102AE000000027000000270000002700000027004A -:102AF000010026000000260000002600000026003D -:102B0000000026000100250000002500000025002F -:102B10000000250000002500000025000100240021 -:102B20000000240000002400000024000000240015 -:102B30000100230000002300000023000000230008 -:102B400000002300000023000000230001002200F9 -:102B500000002200000022000000220000002200ED -:102B600000002200010021000000210000002100DF -:102B700000002100000021000000210000002100D1 -:102B800001002000000020000000200000002000C4 -:102B900000002000000020000000200000002000B5 -:102BA00001001F0000001F0000001F0000001F00A8 -:102BB00000001F0000001F0000001F0001001E0099 -:102BC00000001E0000001E0000001E000000544D0A -:102BD0004320445249564552204F56455254454D84 -:102BE000500025632533642F25642563005A25365C -:102BF0002E326620005A2020202D2D2D2000256306 -:102C00002533642525002D2D2D00253368686400AB -:102C100025335325337325250020534400202020DD -:102C200000555342002025753E2575002046257528 -:102C30000020463020200025632D2D3A2D2D202008 -:102C400000256325337568202563256300256325EA -:102C50003032753A2530327525632563007265730D -:102C6000756C742076616C75653A2025640A0020C5 -:102C7000693D25326420636E743D2532642076619F -:102C80006C3D2532640A00636C7573746572733A27 -:102C90000A0020693D25326420737465703D253239 -:102CA000640A00736F727465642073616D706C6583 -:102CB000733A0A00555341525432207278204675B7 -:102CC0006C6C2121210A003A2000202020202020A5 -:102CD0002020202020202020202020202000203AFA -:102CE0002000202020202020202020202020202004 -:102CF00020202020202000202020202020202020F4 -:102D0000202020200025730050494E444120486572 -:102D10006174696E670054656D702E2063616C2E5E -:102D2000202020202020202020200043616C696288 -:102D3000726174696F6E20646F6E650043616C69C7 -:102D400062726174696E67205A0042656420646F24 -:102D50006E65004265642048656174696E6700486D -:102D6000656174696E6720646F6E652E00486561E9 -:102D700074696E670043686F6F736520636F6C6F73 -:102D8000723A004661696C207374617473004D3748 -:102D900030322043004661726D206E756D6265723F -:102DA000004D363030004D3234004D323320257323 -:102DB00000052E2E00526573756D696E6720707266 -:102DC000696E7400537570706F727400537461741F -:102DD00069737469637320200043616C6962726176 -:102DE00074696F6E004175746F4C6F616420666921 -:102DF0006C616D656E7400556E6C6F616420666900 -:102E00006C616D656E7400456A6563742066696CFB -:102E1000616D656E74004C6F616420746F206E6F1D -:102E20007A7A6C65004C6F61642066696C616D65CF -:102E30006E74004E6F2053442063617264005072C0 -:102E4000696E742066726F6D20534400526573750D -:102E50006D65207072696E740050617573652070C5 -:102E600072696E7400507265686561740054756EA5 -:102E700065004C6976652061646A757374205A0038 -:102E8000496E666F2073637265656E0046696E6990 -:102E90007368696E67206D6F76656D656E7473001B -:102EA000536F756E642020202020205B6C6F75644A -:102EB0005D00536F756E642020202020205B6D75AF -:102EC00074655D00536F756E64202020205B73690C -:102ED0006C656E745D00536F756E64202020202039 -:102EE000205B6F6E63655D00536F756E64202020FC -:102EF0002020205B6C6F75645D00437261736820F5 -:102F00006465742E20205B4E2F415D004372617317 -:102F100068206465742E2020205B6F6E5D00437214 -:102F2000617368206465742E20205B6F66665D00A7 -:102F30004D6F6465202020205B537465616C74685C -:102F40005D004D6F646520202020205B4E6F726D08 -:102F5000616C5D0046696C2E2073656E736F722024 -:102F6000205B6F6E5D0046696C2E2073656E736F1B -:102F700072205B6F66665D004368616E6765206600 -:102F8000696C616D656E7400466C6F770053706597 -:102F900065640046616E2073706565640042656417 -:102FA000004E6F7A7A6C650053657474696E67734E -:102FB000005072696E742061626F727465640059AA -:102FC0006573004E6F0053746F70207072696E7479 -:102FD0000046696C6520696E636F6D706C65746521 -:102FE0002E20436F6E74696E756520616E7977610E -:102FF000793F004D61696E00473830004D3435002F -:103000004D3435205A004737360057697A6172646B -:103010002073746174653A202564004469736162A9 -:103020006C65206661726D206D6F6465004661722B -:103030006D206E756D626572004D3834004D34340C -:1030400000473238205700473939004469736162BC -:103050006C65206661726D206D6F64653F00436131 -:103060006C69627261746500506C65617365206C97 -:103070006F616420504C412066696C616D656E74AF -:103080002066697273742E00497320504C4120668B -:10309000696C616D656E74206C6F616465643F007E -:1030A00043616E63656C0046696C616D656E7400AA -:1030B00053656C65637420504C412066696C616D8A -:1030C000656E743A0052756E6E696E672057697A44 -:1030D0006172642077696C6C2064656C657465202E -:1030E00063757272656E742063616C69627261747B -:1030F000696F6E20726573756C747320616E6420E5 -:1031000073746172742066726F6D207468652062DA -:103110006567696E6E696E672E20436F6E74696EA7 -:1031200075653F0050726568656174696E67206EF1 -:103130006F7A7A6C652E20506C65617365207761BB -:1031400069742E00456A65637400556E6C6F616426 -:103150000055736520756E6C6F616420746F20720A -:10316000656D6F76652066696C616D656E74203182 -:103170002069662069742070726F7472756465735B -:10318000206F757473696465206F662074686520AC -:1031900072656172204D4D5520747562652E205503 -:1031A000736520656A6563742069662069742069A7 -:1031B000732068696464656E20696E207475626549 -:1031C0002E004C6F6164696E672066696C616D6585 -:1031D0006E7400506C6561736520696E73657274FE -:1031E00020504C412066696C616D656E7420746F6F -:1031F000207468652065787472756465722C20741B -:1032000068656E207072657373206B6E6F622074D8 -:103210006F206C6F61642069742E00506C6561735F -:103220006520696E7365727420504C412066696C2C -:10323000616D656E7420746F2074686520666972B4 -:1032400073742074756265206F66204D4D552C2077 -:103250007468656E20707265737320746865206B86 -:103260006E6F6220746F206C6F61642069742E0031 -:10327000596F752063616E20616C7761797320727C -:103280006573756D65207468652057697A6172642D -:103290002066726F6D2043616C6962726174696F40 -:1032A0006E202D3E2057697A6172642E00506C6545 -:1032B00061736520636865636B206F757220686158 -:1032C0006E64626F6F6B20616E6420666978207433 -:1032D00068652070726F626C656D2E205468656E33 -:1032E00020726573756D65207468652057697A6111 -:1032F0007264206279207265626F6F74696E6720F4 -:10330000746865207072696E7465722E00416C6C11 -:1033100020697320646F6E652E204861707079207B -:103320007072696E74696E672100506C65617365B7 -:1033300020636C65616E20686561746265642061FC -:103340006E64207468656E20707265737320746893 -:1033500065206B6E6F622E00446F20796F75207749 -:10336000616E7420746F20726570656174206C6189 -:103370007374207374657020746F20726561646A61 -:103380007573742064697374616E6365206265741B -:103390007765656E206E6F7A7A6C6520616E642049 -:1033A000686561746265643F00492077696C6C20D0 -:1033B000737461727420746F207072696E74206C03 -:1033C000696E6520616E6420796F752077696C6C19 -:1033D000206772616475616C6C79206C6F776572BF -:1033E00020746865206E6F7A7A6C6520627920722D -:1033F0006F746174696E6720746865206B6E6F62AC -:103400002C20756E74696C20796F7520726561630C -:1034100068206F7074696D616C2068656967687495 -:103420002E20436865636B2074686520706963743F -:103430007572657320696E206F75722068616E64A5 -:10344000626F6F6B20696E206368617074657220B3 -:1034500043616C6962726174696F6E2E004E6F77A2 -:1034600020492077696C6C2063616C6962726174B9 -:10347000652064697374616E636520626574776545 -:10348000656E20746970206F6620746865206E6FA9 -:103490007A7A6C6520616E64206865617462656427 -:1034A00020737572666163652E004973206974200C -:1034B000504C412066696C616D656E743F005365C8 -:1034C0006C656374206E6F7A7A6C652070726568C3 -:1034D0006561742074656D706572617475726520C4 -:1034E0007768696368206D61746368657320796FBC -:1034F0007572206D6174657269616C2E004E6F7714 -:1035000020492077696C6C20707265686561742051 -:103510006E6F7A7A6C6520666F7220504C412E0077 -:1035200049732066696C616D656E74206C6F6164AF -:1035300065643F0049732066696C616D656E742037 -:1035400031206C6F616465643F004E6F77204920C5 -:1035500077696C6C2070726568656174206E6F7A33 -:103560007A6C6520666F7220504C412E004920779E -:10357000696C6C2072756E207A2063616C6962726E -:103580006174696F6E206E6F772E004E6F772072B8 -:10359000656D6F766520746865207465737420703E -:1035A00072696E742066726F6D20737465656C202D -:1035B00073686565742E00506C6561736520726573 -:1035C0006D6F7665207368697070696E67206865D5 -:1035D0006C706572732066697273742E004920776F -:1035E000696C6C2072756E2078797A2063616C69E1 -:1035F00062726174696F6E206E6F772E204974203D -:1036000077696C6C2074616B6520617070726F7883 -:103610002E203132206D696E732E004669727374EC -:103620002C20492077696C6C2072756E2074686557 -:103630002073656C667465737420746F20636865AD -:10364000636B206D6F737420636F6D6D6F6E20619F -:103650007373656D626C792070726F626C656D73E7 -:103660002E0048692C204920616D20796F757220E9 -:103670004F726967696E616C205072757361206961 -:1036800033207072696E7465722E20576F756C648A -:1036900020796F75206C696B65206D6520746F20D3 -:1036A000677569646520796F75207468726F7567D6 -:1036B00068207468652073657475702070726F631C -:1036C0006573733F00452D636F7272656374005AB2 -:1036D0002D636F727265637400592D636F7272652A -:1036E000637400582D636F72726563740041757462 -:1036F0006F206465706C6574655B4E2F415D0041A1 -:1037000075746F206465706C6574655B6F66665D6B -:10371000004175746F206465706C657465205B6F23 -:103720006E5D00536F756E642020202020205B6C3E -:103730006F75645D00536F756E642020202020201B -:103740005B6D7574655D00536F756E64202020207D -:103750005B73696C656E745D00536F756E642020D9 -:10376000202020205B6F6E63655D00536F756E6473 -:103770002020202020205B6C6F75645D00536F72E9 -:10378000743A2020202020205B6E6F6E655D005310 -:103790006F72743A20205B616C7068616265745D61 -:1037A00000536F72743A2020202020205B74696DD2 -:1037B000655D005344206361726420205B6E6F720C -:1037C0006D616C5D0053442063617264205B666CC4 -:1037D00073684169725D0052506920706F72742085 -:1037E000202020205B6F6E5D0052506920706F7248 -:1037F00074202020205B6F66665D0054656D702E1E -:103800002063616C2E2020205B6F6E5D0054656D1F -:10381000702E2063616C2E20205B6F66665D004C0D -:10382000696E2E20636F7272656374696F6E0046F5 -:10383000616E7320636865636B20205B6F66665DF5 -:103840000046616E7320636865636B2020205B6FA8 -:103850006E5D00462E206175746F6C6F6164205B35 -:103860006F66665D00462E206175746F6C6F6164D3 -:1038700020205B6F6E5D00462E206175746F6C6F4B -:103880006164205B4E2F415D0046696C2E2073659C -:103890006E736F72205B4E2F415D004469736162ED -:1038A0006C65207374657070657273004D6F76651A -:1038B00020617869730054656D706572617475720A -:1038C000650054656D702E2063616C69627261746D -:1038D000696F6E0052657365742058595A20636190 -:1038E0006C6962722E0053686F772070696E646134 -:1038F000207374617465005049442063616C69628F -:10390000726174696F6E00426564206C6576656CE7 -:1039100020636F7272656374004D65736820426541 -:1039200064204C6576656C696E670043616C696202 -:1039300072617465205A0043616C696272617465DA -:103940002058595A0053656C6674657374202020A2 -:10395000202020202020004669727374206C617939 -:1039600065722063616C2E0057697A617264004C45 -:103970006F61642066696C616D656E742035004C02 -:103980006F61642066696C616D656E742034004CF3 -:103990006F61642066696C616D656E742033004CE4 -:1039A0006F61642066696C616D656E742032004CD5 -:1039B0006F61642066696C616D656E742031004CC6 -:1039C0006F616420616C6C004C6F61642066696C8F -:1039D000616D656E742035004C6F61642066696CA2 -:1039E000616D656E742034004C6F61642066696C93 -:1039F000616D656E742033004C6F61642066696C84 -:103A0000616D656E742032004C6F61642066696C74 -:103A1000616D656E74203100456A65637420666966 -:103A20006C616D656E74203500456A65637420664F -:103A3000696C616D656E74203400456A656374203D -:103A400066696C616D656E74203300456A656374E8 -:103A50002066696C616D656E74203200456A65632D -:103A6000742066696C616D656E74203100506C6500 -:103A70006173652070756C6C206F75742066696C5D -:103A8000616D656E7420696D6D6564696174656CE6 -:103A90007900556E6C6F6164696E672066696C6150 -:103AA0006D656E740057697A61726420656E64207A -:103AB00073746174653A2025640A00000021104285 -:103AC0002063308440A550C660E770088129914A80 -:103AD000A16BB18CC1ADD1CEE1EFF1311210027307 -:103AE000325222B5529442F772D662399318837BD0 -:103AF000B35AA3BDD39CC3FFF3DEE3622443342057 -:103B0000040114E664C774A44485546AA54BB5281F -:103B1000850995EEE5CFF5ACC58DD55336722611E6 -:103B2000163006D776F6669556B4465BB77AA7196F -:103B3000973887DFF7FEE79DD7BCC7C448E55886AE -:103B400068A7784008611802282338CCC9EDD98EBF -:103B5000E9AFF9488969990AA92BB9F55AD44AB746 -:103B60007A966A711A500A333A122AFDDBDCCBBF0F -:103B7000FB9EEB799B588B3BBB1AABA66C877CE416 -:103B80004CC55C222C033C600C411CAEED8FFDEC5F -:103B9000CDCDDD2AAD0BBD688D499D977EB66ED526 -:103BA0005EF44E133E322E511E700E9FFFBEEFDDAF -:103BB000DFFCCF1BBF3AAF599F788F8891A981CA8C -:103BC000B1EBA10CD12DC14EF16FE18010A100C26B -:103BD00030E3200450254046706760B9839893FB1A -:103BE000A3DAB33DC31CD37FE35EF3B1029012F3BB -:103BF00022D2323542145277625672EAB5CBA5A86A -:103C00009589856EF54FE52CD50DC5E234C324A00A -:103C10001481046674476424540544DBA7FAB799F9 -:103C200087B8975FE77EF71DC73CD7D326F236915A -:103C300006B01657667676154634564CD96DC90EC1 -:103C4000F92FE9C899E9898AB9ABA94458654806AA -:103C5000782768C018E1088238A3287DCB5CDB3F59 -:103C6000EB1EFBF98BD89BBBAB9ABB754A545A37FA -:103C70006A167AF10AD01AB32A923A2EFD0FED6C29 -:103C8000DD4DCDAABD8BADE89DC98D267C076C644A -:103C90005C454CA23C832CE01CC10C1FEF3EFF5D39 -:103CA000CF7CDF9BAFBABFD98FF89F176E367E559A -:103CB0004E745E932EB23ED10EF01E7C3C3E5E2BC7 -:103CC0003D3F2F5B5D3B2C2A225C00222066616910 -:103CD0006C65643A204275666665722066756C6C28 -:103CE00021002200656E717565696E6720220020D3 -:103CF000423A0020453A00543A00494E543400728A -:103D000065636F7665725F6D616368696E655F7329 -:103D1000746174655F61667465725F706F776572F8 -:103D20005F70616E69632C20696E697469616C20D3 -:103D3000007265636F7665725F6D616368696E6559 -:103D40005F73746174655F61667465725F706F77CD -:103D500065725F70616E69632C20696E6974696158 -:103D60006C20004739322045005052555341207590 -:103D7000766C6F004734205330004D323620532587 -:103D80006C75004D3130362053004D3832004731CC -:103D9000204625640047312045322A6465666175F6 -:103DA0006C745F72657472616374696F6E204634FF -:103DB0003830004731205A00204632303030002061 -:103DC000590047312058004D383300506F736974E3 -:103DD000696F6E20726561642066726F6D20656523 -:103DE00070726F6D3A004D3233202573002E676379 -:103DF0006F0046656564726174653A00473120451D -:103E00002D64656661756C745F726574726163744C -:103E1000696F6E20463438300047312045352046E2 -:103E2000313230004D3833004D3139302053256464 -:103E3000004D313039205325640047323820582056 -:103E400059004731205A32352046383030006275EB -:103E500073793A2070617573656420666F722069AA -:103E60006E70757400627573793A20706175736550 -:103E70006420666F72207573657200627573793A9B -:103E80002070726F63657373696E67002046004728 -:103E900031205A0020460047312045004D3833007C -:103EA0006F6B0A0055564C4F202D20656E642025FF -:103EB000640A007374707325640A00776F726C640F -:103EC00020636F6F7264696E617465733A20282590 -:103ED0002E33662C20252E33662C20252E33662982 -:103EE0000A00706879736963616C20636F6F726434 -:103EF000696E617465733A2028252E33662C20255F -:103F00002E33662C20252E3366290A0043757272E3 -:103F1000656E7420706F73205A5F415849533A257B -:103F20002E33660A43757272656E7420706F73204B -:103F3000455F415849533A252E33660A004166745D -:103F400065722077616974696E6720666F7220748C -:103F5000656D703A0A43757272656E7420706F7386 -:103F600020585F415849533A252E33660A437572EB -:103F700072656E7420706F7320595F415849533ACF -:103F8000252E33660A005265636F766572696E6727 -:103F9000207072696E7420202020001B5B323B3140 -:103FA00048416D6269656E743A2020256425631B63 -:103FB0005B333B314850494E44413A202020202574 -:103FC000642563001B5B303B31484E6F7A7A6C6529 -:103FD0003A202020256425631B5B313B3148426534 -:103FE000643A20202020202025642563001B5B31BB -:103FF0003B31485057523A20202020202025642E63 -:1040000025303164561B5B323B31484245443A20EF -:10401000202020202025642E2530316456001B5B93 -:10402000303B314842656C74207374617475731B46 -:104030005B313B3248582025641B5B323B32485988 -:1040400020256400464C4558202D20203234302F46 -:1040500035300050502020202D20203235342F3193 -:1040600030300048495053202D20203232302F313B -:1040700030300041425320202D20203235352F3161 -:1040800030300050455420202D20203233302F383E -:104090003500504C4120202D20203231352F363034 -:1040A00000414253202020202D20203235352F3151 -:1040B0003030006E6F7A7A6C65202D2020323530DA -:1040C0002F30006661726D2020202D202032353087 -:1040D0002F363000466C6173684169722049502068 -:1040E000416464723A004D4D55322020202020203A -:1040F000204E2F4100756E6B6E6F776E0025642E1B -:1041000025642E25642D2564002046573A004D4D28 -:10411000553220636F6E6E6563746564004E6F7612 -:1041200020313520323031380045334476366675DB -:104130006C6C0045494E53795F31306100315F3717 -:10414000356D6D5F4D4B33002D2D2D2D2D2D2D2DCE -:104150002D2D2D2D00207265706F20556E6B6E6FAA -:10416000776E0020352E302E322D545A422D3232A9 -:104170003334004669726D776172653A0025642EAA -:1041800025642E25642E2564004D373032004D37CE -:104190003031004578747275646572006D6D000091 -:1041A00059005800580059005A002563252E313215 -:1041B000533A2573252B30362E336600436F6F6CD0 -:1041C000646F776E00566F6C746167657300546539 -:1041D0006D7065726174757265730042656C7420F0 -:1041E00073746174757300457874727564657220B8 -:1041F000696E666F0058595A2063616C2E206465A1 -:104200007461696C7300446174653A00686F777417 -:104210006F2E707275736133642E636F6D00666FFD -:1042200072756D2E707275736133642E636F6D00DD -:10423000707275736133642E636F6D0046696C61D3 -:104240006D656E7420657874727564696E6720267A -:10425000207769746820636F727265637420636F7E -:104260006C6F723F00507265686561742074686598 -:10427000206E6F7A7A6C6521004552524F523A0097 -:104280004175746F6C6F6164696E672066696C61FB -:104290006D656E74206973206163746976652C2086 -:1042A0006A75737420707265737320746865206B0F -:1042B0006E6F6220616E6420696E73657274206631 -:1042C000696C616D656E742E2E2E00546F74616C76 -:1042D000207072696E742074696D6500546F74612A -:1042E0006C2066696C616D656E74005072696E74E5 -:1042F0002074696D650046696C616D656E7420752A -:10430000736564005269676874004C65667400598F -:104310002064697374616E63652066726F6D206DD1 -:10432000696E0053657665726520736B657700531F -:104330006C6967687420736B6577004D6561737590 -:1043400072656420736B6577005B303B305D207075 -:104350006F696E74206F66667365740041646A7578 -:104360007374696E67205A005265736574005265F4 -:1043700061722073696465205B756D5D0046726FC4 -:104380006E7420736964655B756D5D005269676862 -:104390007420736964655B756D5D004C656674209F -:1043A00073696465205B756D5D0053657420746589 -:1043B0006D70657261747572653A001B5B324A25D7 -:1043C00053203A1B5B313B394825382E3266206D2D -:1043D0000A2553203A0A25376C6464203A2532684E -:1043E000686468203A253032686864206D001B5B81 -:1043F000324A25533A1B5B313B364825382E32660C -:104400006D200A2553203A1B5B333B384825326424 -:104410006820253032646D202530326473002536E3 -:104420002E32666D6D004E2F41001B5B303B3048D5 -:1044300025533A0A25530A25533A0A25533A001BB5 -:104440005B303B3135484E2F41001B5B303B3135F3 -:104450004825342E326601001B5B303B3048255323 -:104460003A0A25530A25533A202025352E32660173 -:104470000A25533A202025352E3266010020003EC1 -:10448000003E0020003E003E0054656D7065726184 -:10449000747572652063616C6962726174696F6EB4 -:1044A000206661696C65642E20436F6E74696E7559 -:1044B000652077697468207072657373696E672010 -:1044C000746865206B6E6F622E0054656D70657246 -:1044D00061747572652063616C6962726174696F81 -:1044E0006E20646F6E652E20436F6E74696E756505 -:1044F0002077697468207072657373696E672074C1 -:104500006865206B6E6F622E005A3020284C45443F -:10451000206F6E2920005A3120284C4544206F66B8 -:10452000662900502E492E4E2E442E412E207374A3 -:104530006174650054656D70657261747572652093 -:1045400063616C6962726174696F6E206661696C27 -:1045500065640054656D7065726174757265206381 -:10456000616C6962726174696F6E2069732066693B -:104570006E697368656420616E6420616374697636 -:10458000652E2054656D702E2063616C69627261C6 -:1045900074696F6E2063616E206265206469736167 -:1045A000626C656420696E206D656E75205365745C -:1045B00074696E67732D3E54656D702E2063616C57 -:1045C0002E004578747275646572004D6F766520B3 -:1045D0005A004D6F76652059004D6F766520580062 -:1045E0001B5B324A4372617368206465746563744F -:1045F000696F6E2063616E1B5B313B3048626520E2 -:104600007475726E6564206F6E206F6E6C792069B0 -:104610006E1B5B323B30484E6F726D616C206D6F6C -:104620006465001B5B324A5741524E494E473A1B64 -:104630005B313B3048437261736820646574656325 -:1046400074696F6E1B5B323B304864697361626CE6 -:10465000656420696E1B5B333B3048537465616C45 -:104660007468206D6F6465004175746F6C6F616470 -:10467000696E672066696C616D656E742061766134 -:10468000696C61626C65206F6E6C79207768656E0D -:104690002066696C616D656E742073656E736F72F0 -:1046A000206973207475726E6564206F6E2E2E2ED5 -:1046B000004552524F523A2046696C616D656E74E6 -:1046C0002073656E736F72206973206E6F74207231 -:1046D0006573706F6E64696E672C20706C656173B2 -:1046E0006520636865636B20636F6E6E65637469D4 -:1046F0006F6E2E00526573656E6400486561746963 -:104700006E672064697361626C65642062792073EE -:1047100061666574792074696D65722E004B494C31 -:104720004C45442E20005072696E74657220686199 -:104730006C7465642E206B696C6C28292063616C35 -:104740006C656421004D31303420496E76616C69AE -:104750006420657874727564657220004D3130355F -:1047600020496E76616C6964206578747275646541 -:104770007220004D31303920496E76616C696420B9 -:10478000657874727564657220004D323138204945 -:104790006E76616C696420657874727564657220E8 -:1047A000004D32323120496E76616C696420657843 -:1047B000747275646572200025533A20256C640A72 -:1047C00025530A002079645F6D696E3D2575207957 -:1047D000645F6D61783D25752079645F6176673D22 -:1047E00025752073685F6176673D25750A00207323 -:1047F000745F73756D3D25752079645F73756D3DCC -:1048000025752065725F73756D3D25752065725F36 -:104810006D61783D256868750A00004B494C4C3A3B -:104820002025640A006673656E736F725F6F715F37 -:104830006D656173737572655F73746F702C20257D -:104840006868752073616D706C65730A00667365C6 -:104850006E736F725F6F715F6D6561737375726593 -:104860005F73746172740A004D36303000465345F0 -:104870004E534F525F5245434F5645520066736543 -:104880006E736F725F757064617465202D204D3694 -:1048900030300A006673656E736F725F6572725FA7 -:1048A000636E74203D20300A004731204533204696 -:1048B00032303000473120452D3320463230300031 -:1048C0004D3730310020573A0020453A00543A0025 -:1048D0005A206C6976652061646A757374206F75FF -:1048E00074206F662072616E67652E205365747444 -:1048F000696E6720746F20302E20436C69636B20D3 -:10490000746F20636F6E74696E75652E005A206C2B -:104910006976652061646A757374206F7574206FA1 -:10492000662072616E67652E2053657474696E67C8 -:1049300020746F20300043757272656E7400557379 -:10494000656420647572696E67207072696E7400A8 -:104950005049442063616C2E2066696E69736865F6 -:1049600064005049442063616C2E202020202020C8 -:10497000202020202000506C6561736520776169DC -:1049800074004D313137204669727374206C61793F -:1049900065722063616C2E005072696E74207061C4 -:1049A0007573656400496E76616C69642050494492 -:1049B0002063616C2E20726573756C74732E204EAB -:1049C0006F742073746F72656420746F2045455056 -:1049D000524F4D2E004D353030004731205A313581 -:1049E00020463135303000473931004731205835C5 -:1049F00030205931393020453020463730303000B2 -:104A0000473930004D373032004D373032204300C7 -:104A10004D3730322055004D373032004D3730326F -:104A20002043004731205A3135204631353030009F -:104A3000473931004731205835302059313930203D -:104A40004530204637303030004D3833004739305C -:104A5000004D3834004D313034205330004D38345F -:104A6000004D373032204300473120583130205933 -:104A7000313830204634303030004731205A313020 -:104A80002046313330302E303030004D313430203C -:104A90005330004D31303420533000473120452D04 -:104AA000302E30373530302046323130302E3030F5 -:104AB000303030004D31303700473120583530200C -:104AC0005935352045332E363237373300473120BC -:104AD00058323030205935352045302E343933386E -:104AE0003600473120583230302059373520453391 -:104AF0002E3632373733004731205835302059377A -:104B0000352045302E34393338360047312058357A -:104B100030205939352045332E3632373733004768 -:104B2000312058323030205939352045302E343933 -:104B30003338360047312058323030205931313542 -:104B40002045332E36323737330047312058353041 -:104B500020593131352045302E343933383600472D -:104B6000312058353020593133352045332E3632F7 -:104B70003737330047312058323030205931333500 -:104B80002045302E36363137340047312058323008 -:104B90003020593135352045322E36323737330003 -:104BA00047312058313030205931353520453200D9 -:104BB00047312058373520593135352045322E358B -:104BC000004731204631303830004731205A302EEE -:104BD0003135302046373230302E303030004731DA -:104BE0002058353020593135350047312046343092 -:104BF0003030004D323034205331303030004731C6 -:104C0000205A352046373230302E30303000473190 -:104C100020452D312E353030303020463231303085 -:104C20002E3030303030004D3833004739300047B7 -:104C30003231004739322045302E3000473120587C -:104C40003130302E30204531322E35204631303053 -:104C5000302E30004731205836302E302045392E46 -:104C6000302046313030302E300047312058352E3C -:104C7000302045342E302046313030302E30004741 -:104C800031205A302E32302046313030302E300034 -:104C90004731205835352E302045323520463134C5 -:104CA00030302E3000473120592D322E3020463101 -:104CB0003030302E3000473120583234302E302002 -:104CC0004532352E30202046323230302E300047EB -:104CD00039322045302E30004731205A302E3320D3 -:104CE00046313030302E30004731205835352E30A7 -:104CF0002045382E302046323030302E30004731BB -:104D00002058352E30204533322E30204631383071 -:104D1000302E30004731205835352E302045333283 -:104D20002E302046313037332E30004731205A3074 -:104D30002E342046313030302E3000473120592D6E -:104D4000332E302046313030302E30004D38330095 -:104D50004739322045302E3000473238004D31304F -:104D6000392053323135004D31393020533630003F -:104D70004D31343020533630004D313034205332F1 -:104D80003135004D313037006F6B0A00737461723A -:104D9000740A004D4D5532206669726D77617265F7 -:104DA0002076657273696F6E20696E76616C6964D6 -:104DB0002E2052657175697265642076657273691B -:104DC0006F6E3A206275696C64206E756D626572F3 -:104DD000202564206F72206869676865722E0066FE -:104DE0006C0A006E6B0A0046530A0052300A0045F6 -:104DF000340A0045330A0045320A0045310A0045AD -:104E0000300A0055300A0043300A004C340A004C86 -:104E1000330A004C320A004C310A004C300A00546C -:104E2000340A0054330A0054320A0054310A005440 -:104E3000300A004D4D55203D3E2027434D44205221 -:104E400045545259203078253258270A004D4D5587 -:104E5000203D3E2027434D442041434B20307825C0 -:104E60003258270A004D4D55203D3E20274572728D -:104E70006F20356D2054696D656F7574270A004D7C -:104E80004D55203D3E202766697854686550726F05 -:104E9000626C656D2121270A004D4D55203D3E2055 -:104EA000276F6B270A004D4D55203D3E20276F6B25 -:104EB000203A29270A004D4D55203D3E2027776195 -:104EC0006974696E6720666F722066696C616D65D2 -:104ED0006E742040204D4B332053656E736F7227E4 -:104EE0000A004D363030004D363030204155544F99 -:104EF000004653454E534F525F5245434F5645521D -:104F000000256868750050300A0045450A004D4D7F -:104F100055203C3D202746696C616D656E74207399 -:104F200065656E206174206578747275646572279A -:104F30000A0045450A004D4D55203C3D2027523082 -:104F4000270A0045450A004D4D55203C3D20274588 -:104F50002564270A0045450A004D4D55203C3D205B -:104F6000275530270A0045450A004D4D55203C3D48 -:104F700020274330270A0045450A004D4D55203C67 -:104F80003D20274C2564270A0045450A0045450A6F -:104F9000004D4D55203C3D2027542564270A0046EE -:104FA000530A0052300A0045340A0045330A0045CE -:104FB000320A0045310A0045300A0055300A0043E4 -:104FC000300A004C340A004C330A004C320A004CC0 -:104FD000310A004C300A0054340A0054330A005499 -:104FE000320A0054310A0054300A004D4D55202D2C -:104FF00020454E41424C45440025686875005030BC -:105000000A0050300A004D4D552076657273696F65 -:105010006E2076616C69640025750053320A0025A4 -:1050200075004D4D55206E6F7420726573706F6EF4 -:1050300064696E67202D2044495341424C45440029 -:1050400053310A004D4D5520737461727473207290 -:105050006573706F6E64696E670A004D4D55206E02 -:105060006F7420726573706F6E64696E670A0000FA -:1050700000803F555585410000803F0000C8410039 -:10508000000040555505420000C03F000048420066 -:1050900000204055558542000070C1ABAAA64200D1 -:1050A0000060C10000A0410000C0C000002041001D -:1050B000002041ABAA3A41000020C15555D540001F -:1050C0000048C2555505424D373031204530004D1E -:1050D000373031204531004D373031204532004DD9 -:1050E000373031204533004D373031204534004DC5 -:1050F000373031204534004D373031204533004DB5 -:10510000373031204532004D373031204531004DA8 -:105110003730312045300046696C616D656E742012 -:105120006E72206F7574206F662072616E676521E4 -:1051300000506C65617365207570646174652066EC -:1051400069726D7761726520696E20796F75722062 -:105150004D4D55322E2057616974696E6720666F18 -:10516000722072657365742E004D4D55204F4B2E85 -:1051700020526573756D696E672E2E2E004D4D554C -:10518000204F4B2E20526573756D696E6720706FCE -:10519000736974696F6E2E2E2E004D4D55204F4B46 -:1051A0002E20526573756D696E672074656D70652C -:1051B0007261747572652E2E2E00466978207468AF -:1051C0006520697373756520616E64207468656E0F -:1051D00020707265737320627574746F6E206F6EC9 -:1051E000204D4D5520756E69742E00507265737395 -:1051F00020746865206B6E6F6220746F2072657317 -:10520000756D65206E6F7A7A6C652074656D70655A -:105210007261747572652E004D4D55206E65656422 -:1052200073207573657220617474656E74696F6E36 -:105230002E00506C656173652072656D6F76652018 -:1052400066696C616D656E7420616E64207468655A -:105250006E20707265737320746865206B6E6F6268 -:105260002E00456A656374696E672066696C616DBE -:10527000656E740025632533642F25642563000063 -:105280000E1315110E000000041209120400000094 -:105290001C1F11111F00000006191803130C000435 -:1052A0000E1F041C000000040A0A0A0A11110E0055 -:1052B0001F1511151F0000000103161C0800000037 -:1052C00000110A04110A040C12120C00000000253F -:1052D00063252D3138532563002563252E31355341 -:1052E0003A2573253364002563252E3132533A2540 -:1052F000732500457872656D65207370616E206F4F -:105300006620746865205A2076616C75657321008B -:1053100000004041000000400000E4420000004066 -:105320000000574300000040000057430000C44203 -:105330000000E4420000C442000040410000C442BA -:1053400000004041000042430000E44200004243AC -:105350000000574300004243205B6F66665D0042D9 -:105360006564206C6576656C696E67206661696C42 -:1053700065642E2053656E736F72206469646E7469 -:1053800020747269676765722E2044656272697362 -:10539000206F6E206E6F7A7A6C653F20576169745A -:1053A000696E6720666F722072657365742E0010D7 -:1053B00000C90210012C014001220170011801B046 -:1053C000010E01F00104015002FA00B002F00030B9 -:1053D00003E600D003DC009004D2007005C800A0F2 -:1053E00006BE000008B400B009AA00D00BA00060FF -:1053F0000E960060118C000015820020197800C004 -:105400001D6E00A0226400B0275A00902C500000AE -:10541000314600E0343C0010383200903A280060F9 -:105420003C1E00A03D1400803E0A00203F0000709A -:10543000012C0190012701B0012201C0011D01F0E2 -:105440000118011002130130020E016002090190DF -:10545000020401C002FF000003FA004003F50080CF -:1054600003F000D003EB002004E6007004E100E04C -:1054700004DC004005D700C005D2004006CD00D0B6 -:1054800006C8008007C3003008BE00F008B900C09D -:1054900009B400B00AAF00B00BAA00D00CA5000000 -:1054A0000EA000500F9B00C01096005012910000FB -:1054B000148C00C0158700B0178200B0197D00D091 -:1054C0001B7800001E730040206E0090226900F0DF -:1054D00024640040275F0090295A00E02B550010FB -:1054E0002E500020304B0010324600E03341009037 -:1054F000353C001037370070383200A0392D00B02D -:105500003A2800A03B2300603C1E00103D1900908B -:105510003D1400103E0F00703E0A00C03E05000022 -:105520003F000090137D00B0157800F01773006005 -:105530001A6E00F01C6900A01F640050225F00205A -:10554000255A00E0275500902A5000202D4B00A03E -:105550002F4600F031410010343C00F0353700A0F8 -:1055600037320020392D00603A2800703B2300605C -:105570003C1E00203D1900C03D1400403E0F00A01D -:105580003E0A00F03E0500403F0000703FFBFF90E8 -:105590003FF6FFB03FF1FFC03FECFFD03FE7FFE039 -:1055A0003FE2FFF03FDDFFF03FD8FF20484F54457A -:1055B0004E4420544845524D414C2052554E41577F -:1055C00041590020484541544245442054484552E1 -:1055D0004D414C2052554E41574159005448455277 -:1055E0004D414C2052554E415741590042454420AF -:1055F000544845524D414C2052554E415741590057 -:1056000020544845524D414C2052554E4157415926 -:105610002028205052454845415420484F54454E7B -:1056200044290020544845524D414C2052554E418A -:10563000574159202820505245484541542048455B -:105640004154424544290050524548454154204563 -:1056500052524F5200424544205052454845415411 -:10566000204552524F52004572723A204D415854D3 -:10567000454D50003A204578747275646572207308 -:1056800077697463686564206F66662E204D4158A3 -:1056900054454D50207472696767657265642021B6 -:1056A000004572723A204D415854454D50204245B4 -:1056B000440054656D70657261747572652068652B -:1056C00061746564206265642073776974636865DA -:1056D00064206F66662E204D415854454D5020740D -:1056E00072696767657265642021004572723A20AD -:1056F0004D494E54454D50204245440054656D700F -:105700006572617475726520686561746564206294 -:105710006564207377697463686564206F66662EBC -:10572000204D494E54454D5020747269676765722B -:1057300065642021004572723A204D494E54454D12 -:1057400050003A20457874727564657220737769E9 -:105750007463686564206F66662E204D494E54451B -:105760004D5020747269676765726564202100740A -:105770006D63323133305F686F6D655F656E746580 -:105780007228617865735F6D61736B3D3078253089 -:105790003278290A00746D63323133305F686F6D7F -:1057A000655F6578697420746D63323133305F737F -:1057B000675F686F6D696E675F617865735F6D6164 -:1057C000736B3D3078253032780A0043616E6E6F1E -:1057D0007420656E746572207375626469723A2014 -:1057E0000053442063617264206F6B006F70656EBC -:1057F000526F6F74206661696C656400766F6C75BA -:105800006D652E696E6974206661696C656400530C -:105810004420696E6974206661696C00536F72740C -:10582000696E672066696C657300536F6D652066ED -:10583000696C65732077696C6C206E6F742062658B -:1058400020736F727465642E204D61782E204E6F28 -:105850002E206F662066696C657320696E2031208A -:10586000666F6C64657220666F7220736F72746904 -:105870006E67206973203130302E001F1F1F1F1FDD -:105880001F1F1F2E002E004E6F77206672657368F3 -:105890002066696C653A20004E6F7720646F696EF0 -:1058A000672066696C653A20002220706F730022C1 -:1058B00020706172656E743A2200535542524F5502 -:1058C00054494E452043414C4C20746172676574C5 -:1058D0003A2200747279696E6720746F2063616C7C -:1058E0006C207375622D67636F64652066696C65F3 -:1058F00073207769746820746F6F206D616E7920F2 -:105900006C6576656C732E204D4158206C6576650C -:105910006C2069733A0057726974696E6720746FFE -:105920002066696C653A200046696C652073656C79 -:105930006563746564002053697A653A200046699E -:105940006C65206F70656E65643A200046696C6115 -:105950006D656E742073656E736F7200537761703E -:105960007065640046726F6E742F6C656674206695 -:10597000616E7300417869730041786973206C65CA -:105980006E677468004C6F6F73652070756C6C6522 -:105990007900456E6473746F70206E6F742068694F -:1059A0007400456E6473746F70004D6F746F720095 -:1059B000456E6473746F707300576972696E672007 -:1059C0006572726F7200426564202F2048656174B1 -:1059D0006572004E6F7420636F6E6E6563746564EC -:1059E000004865617465722F546865726D697374DF -:1059F0006F7200506C6561736520636865636B202E -:105A00003A0053656C6674657374206572726F72C8 -:105A100020210046696C616D656E742073656E733C -:105A20006F723A005072696E742066616E3A00457A -:105A3000787472756465722066616E3A0053656CA5 -:105A40006674657374206661696C6564202000412A -:105A50006C6C20636F72726563742020202020209C -:105A600000436865636B696E672073656E736F7260 -:105A7000732000436865636B696E6720626564200C -:105A80002020202000436865636B696E67205A20E0 -:105A900061786973202000436865636B696E6720D5 -:105AA000592061786973202000436865636B696ED3 -:105AB0006720582061786973202000436865636B14 -:105AC000696E6720686F74656E64202000436865A6 -:105AD000636B696E6720656E6473746F70730045E5 -:105AE00072726F72202D20737461746963206D650A -:105AF0006D6F727920686173206265656E206F76C4 -:105B000065727772697474656E00436172642072A5 -:105B1000656D6F766564004361726420696E7365BC -:105B200072746564002D2D2D2D2D2D2D2D2D2D2DD7 -:105B30002D2D2D2D2D2D2D2D2D0043616C69627283 -:105B40006174696E6720686F6D6500000000000079 -:105B5000110A0450525553413344465700207930BE -:105B60003D25640A002078303D25640A004F4B0A29 -:105B7000004552524F522061643D25640A002020A6 -:105B8000207A303D25640A00207A303D25640A00E1 -:105B90002079303D25640A002078303D25640A00D4 -:105BA00078797A63616C5F66696E645F706F696E45 -:105BB000745F63656E746572320A00462564202541 -:105BC000640A00352E302E322D545A420072630082 -:105BD0006265746100616C7068610064657600786C -:105BE000797A63616C5F73706972616C322063787B -:105BF0003D25642063793D2564207A303D2564206D -:105C0000647A3D2564207261646975733D25642062 -:105C100061643D25640A000102102020080810205C -:105C20004010204080020102010804020101020428 -:105C300008102040808040201008040201800402E7 -:105C4000018040201008040201080402010102043E -:105C50000810204080010204081020408010080431 -:105C60000880102040044080102040048000002262 -:105C700000250028002B002E003100340002010016 -:105C800000050108010B01050505050705080808C1 -:105C900008020202020A0A080804040404010101BD -:105CA00001010101010303030303030303040707C5 -:105CB000070C0C0C0C0C0C0C0C0202020206060663 -:105CC00006060606060B0B0B0B0B0B0B0B07070A46 -:105CD0000A0A0A0A0A050505040404080802746D84 -:105CE00063323133305F676F746F5F737465702038 -:105CF0002564202564202564202564200A002E00C8 -:105D00006F70656E206661696C65642C2046696CF5 -:105D1000653A20000000A0400000A04000000040C4 -:105D200025336420737465703D253264206D736380 -:105D30006E743D2534640A0000007F4300805843A0 -:105D40009AD95143FFFFFF46696C616D656E7420FF -:105D50006F7574206F662072616E67652025642000 -:105D60000A0067636F64655F4D3730312062656795 -:105D7000696E0A0057616974696E6720666F7220E8 -:105D80006E6F7A7A6C6520616E6420626564206350 -:105D90006F6F6C696E670053656C66207465737411 -:105DA000204F4B0053656C662074657374207374C8 -:105DB0006172742020006C63645F73656C66636855 -:105DC00065636B5F617869732025642C2025640A04 -:105DD000004D3834004731205A31352046313030BB -:105DE000300047323820570025632041584953205E -:105DF0005347313D25640A0041786973206C656E14 -:105E000067746820646966666572656E63653A25C5 -:105E10002E33660A004D6561737572656420617882 -:105E20006973206C656E6774683A252E33660A00C4 -:105E30004D3234004D3233202573006175746F2567 -:105E4000692E670022206661696C65643A2042759C -:105E5000666665722066756C6C2100456E717565AD -:105E6000696E6720746F207468652066726F6E7447 -:105E70003A2022004572726F723A002200456E711C -:105E80007565696E6720746F207468652066726F2F -:105E90006E743A2022006563686F3A004572723A68 -:105EA000205052494E542046414E204552524F52A6 -:105EB000005072696E742066616E2073706565644F -:105EC000206973206C6F776572207468656E206539 -:105ED00078706563746564004572723A2045585461 -:105EE000522E2046414E204552524F520045787462 -:105EF00072756465722066616E20737065656420DA -:105F00006973206C6F776572207468656E206578A0 -:105F1000706563746564002F2F20616374696F6E10 -:105F20003A70617573650000002100240027002A83 -:105F3000002D003000330001010000040107010AB8 -:105F400001000020002300260029002C002F003231 -:105F5000000001000003010601090100000A0B0214 -:105F6000090C0D0E080703040100000000000000EA -:105F70000000000000000000000000000000000021 -:105F800000000000000000121110000000000000DE -:105F90000000000000000000000000000000000001 -:105FA00000000000000000000000000000000000F1 -:105FB000002563252E3132533A2573252B30362E9A -:105FC000316600202020202020202020202020209A -:105FD00020202020202020003E003E0020003E0007 -:105FE0003E0020004E6F74207370696E6E696E679C -:105FF000005370696E6E696E67004C656674206848 -:106000006F74656E642066616E3F0046726F6E74D9 -:10601000207072696E742066616E3F0046616E206A -:10602000746573740046696C2E2058643A25336495 -:106030002059643A2533640A496E743A2025336442 -:106040002020536875743A202533640046696C61DA -:106050006D656E742073656E736F720A6973206468 -:10606000697361626C65642E001B5B303B30484E87 -:106070006F7A7A6C652046414E3A2025346420526E -:10608000504D0A5072696E742046414E3A202025C8 -:1060900034642052504D0A001B5B303B3048546F33 -:1060A00074616C206661696C757265731B5B313B52 -:1060B0003148506F776572206661696C75726573DF -:1060C0002020252D33641B5B323B314846696C61CF -:1060D0006D2E2072756E6F7574732020252D3364BC -:1060E0001B5B333B31484372617368202058202585 -:1060F0002D336420205920252D3364001B5B303B59 -:1061000030484C617374207072696E7420666169E6 -:106110006C757265731B5B313B3148506F776572EC -:10612000206661696C757265732020252D33641BB0 -:106130005B323B314846696C616D2E2072756E6F23 -:106140007574732020252D33641B5B333B3148432A -:106150007261736820205820252D33642020592037 -:10616000252D336400546F74616C004C617374208E -:106170007072696E7400AC017C0111241FBECFEFF8 -:10618000D1E2DEBFCDBF00E00CBF16E0A0E0B2E080 -:10619000EAE8F3E703E00BBF02C007900D92A63BCD -:1061A000B107D9F729E1A6EBB6E001C01D92A73DE2 -:1061B000B207E1F710E3CCEBD0E300E006C0219793 -:1061C0000109802FFE010F94D0B8CB3BD10780E0AE -:1061D0000807A9F70F940A8F0D94B4B90C94000026 -:1061E0002F923F924F925F926F927F928F929F92E7 -:1061F000AF92BF92CF92DF92EF92FF920F931F93D5 -:10620000CF93DF93CDB7DEB7C757D1090FB6F89458 -:10621000DEBF0FBECDBF8091981390919913892B4B -:1062200011F40C94EB6F82E090E090932302809342 -:10623000220288E393E00E94A9A78823B1F080910D -:106240002B0D90912C0D6AE270E005960F9433B9F6 -:10625000009711F0DC011C9280912B0D90912C0D78 -:1062600005960F9460530C94096BC0908715D090DD -:106270008815860103561C4E46E050E06EEC70E136 -:10628000C8010F9466AC892B09F0EFC08DE393E051 -:106290000E94A9A7882309F49BC088E50F94909BCE -:1062A000182F89E50F94909B811112600F949883A9 -:1062B0008091B70601E0080F0093B706811105C071 -:1062C00084E696E10E943EDD0EC048EC5FEA60E0A5 -:1062D00070E084E696E10E94F9DC882331F01092A8 -:1062E00064161092B70601E007C0033049F7109218 -:1062F00064161092B70600E081E00F9427370F94E0 -:106300001D3782E00F94932F10FF15C086E69FE0A3 -:106310000F9463B361E0680F86E69FE00F9475B356 -:1063200085E09FE00F9470B3BC016F5F7F4F85E005 -:106330009FE00F948FB311FF15C088E69FE00F9484 -:1063400063B361E0680F88E69FE00F9475B383E064 -:106350009FE00F9470B3BC016F5F7F4F83E09FE0BD -:106360000F948FB381E00F94273782E00F94932F1F -:1063700087EA92E10F94EE5140E061E081E00F94F2 -:10638000BB6E0F949883002321F061E08DE09EE0C6 -:106390001BC0E091FE0CF0E0EE0FFF1FE757FA4E36 -:1063A0001182108240E060E089E892E10F94A0073A -:1063B000182F81E00F94273761E0112319F08FEF38 -:1063C0009DE002C082EF9DE00E9465DB0C94096BAA -:1063D0008CE493E00E94A9A7882379F080913F0E76 -:1063E000882331F060E070E080E89FE30E94DBE604 -:1063F00081E080930C020C94096B8AE593E00E9483 -:10640000A9A7882311F40C94096B10923F0E81E028 -:1064100080930C0280917C0E811104C00E94BECE3C -:106420000C94096B813011F00C94096BE1EEFDE0E6 -:1064300084918F01882339F00E946EAD0F5F1F4F4A -:10644000F8018491F7CF8AE00E946EADEDE5F7E1A7 -:1064500084918F01882311F40C9496690E946EAD8B -:106460000F5F1F4FF8018491F5CF44E050E069ECD5 -:1064700070E1C8010F9466AC892B09F00EC186014A -:106480000F551C4E49E050E06FEB70E1C8010F94CE -:1064900066AC892BD9F4F601E655FC4E1081153413 -:1064A00031F01855143010F00C94096B01C013E052 -:1064B0004AE050E060E070E0C60185559C4E0F94C4 -:1064C0001DAA812F0F946B5B0C94096B49E050E07F -:1064D00065EB70E1C8010F9466AC892B61F5F6019C -:1064E000E655FC4E1081153431F01855143010F07B -:1064F0000C94096B01C013E04AE050E060E070E0EA -:10650000C60185559C4E0F941DAAE12FF0E0E05F77 -:10651000F84F40E051E0008002C0569547950A943C -:10652000E2F7842F880F880F81506823812F0F9402 -:10653000195D0C94096B49E050E06BEA70E1C80109 -:106540000F9466AC892B11F00C94096BF601E6559B -:10655000FC4E8081853449F008EA902E980EF3E0D5 -:10656000F91510F40C94096B02C013E0912EE92C7C -:10657000F12C5701AA0CBB1CF501EF5CFD4F1081FB -:10658000012F0F70712E7294BFE07B22272D277090 -:10659000722E111F1127111F61816770660F162B54 -:1065A000F501EE5CFD4F8081882E8694869486945A -:1065B000382D3370832E1A821982C60185559C4E60 -:1065C000DC012C912223E1F14AE050E0BE016F5F33 -:1065D0007F4F0F941DAA062F0F7089819A81009713 -:1065E00079F1FC012081222359F14AE050E0BE01FB -:1065F0006F5F7F4F0F941DAA6770762E89819A81F5 -:106600000097F1F0DC012C912223D1F04AE050E018 -:10661000BE016F5F7F4F0F941DAA162F1F708981D7 -:106620009A81009769F0FC012081222349F04AE019 -:1066300050E0BE016F5F7F4F0F941DAA6370862EDE -:10664000F501EF5CFD4F972D97709295907F612F2C -:10665000679566276795902B962B9083612F66959B -:106660001181107E882D8370880F880F880F162B5C -:10667000182B1183C701875E9D4FD701A35EBD4FC5 -:10668000B701605F784FFC0120814C91DB016C9178 -:10669000892D0E94E1C60C94096B87E693E00E9465 -:1066A000A9A7882321F00E940B9F0C94096B87E710 -:1066B00093E00E94A9A7882309F4B5C18DE793E070 -:1066C0000E94A9A7882391F08091C80F882311F414 -:1066D0000C94096B0F94258860937A1670937B163F -:1066E00080937C1690937D160C94096B82E893E05E -:1066F0000E94A9A7882349F08091E50E8F9380918D -:10670000E40E8F938BEC97E03DC086E893E00E9407 -:10671000A9A7882329F140917813509179132CE38C -:10672000249FC001259F900D11249F938F9340912A -:10673000761350917713249FC001259F900D11244B -:106740009F938F9384EB97E09F938F930F9493ADD8 -:106750000F900F900F900F900F900F900C94096B6B -:106760008AE893E00E94A9A78823C9F08091C80F06 -:10677000882391F080912A078F93809129078F9326 -:1067800081EB97E09F938F930F9493AD0F900F90B1 -:106790000F900F900C94096B8FE997E0F0C08DE893 -:1067A00093E00E94A9A7882321F0109228070C9457 -:1067B000096B81E993E00E94A9A7882349F060E072 -:1067C00085EA9FE00F9475B361E087EA90E1FCCD24 -:1067D00086E993E00E94A9A7882321F00F94602600 -:1067E0000C94096B8DE993E00E94A9A7882319F105 -:1067F0008091C80F8823C9F08AEA95E5DC0180936F -:10680000FC1F9093FD1FA093FE1FB093FF1F88E015 -:106810008093FB1F98E10FB6F894A89590936000C1 -:106820000FBE80936000F894FFCF83EA93E00E944C -:10683000A7AE0C94096B85EB93E00E94A9A788236F -:1068400039F180912B0D90912C0D41E061E0039680 -:106850000F94E5438091AE189091AF18A091B018B5 -:10686000B091B11880935B1990935C19A0935D1956 -:10687000B0935E1986EA98E10E9435E38C010E948C -:106880006EAD0A30110531F70F9437570C94096B30 -:1068900088EB93E00E94A9A7882381F00F94BF663C -:1068A00081E080933B0780912B0D90912C0D41E06E -:1068B00060E004960F94E5430C94096B8CEB93E035 -:1068C0000E94A9A7882309F45EC08091C80F88237D -:1068D00009F453C010928B156091D1197091D2199F -:1068E0008BE390E00F940EAD6091D1197091D219A5 -:1068F00083E590E00F940EAD19821B821A82CE01BF -:1069000001960E94EDDC00E010E0FF24F3948091FA -:10691000EF0D9091F00D2091F10D3091F20D821B51 -:10692000930B8F779927892B81F00E94CAACF09244 -:106930008B156091D1197091D21990E00F940EAD22 -:106940000F5F1F4F10928B15E2CF64E670E0CE010F -:1069500001960E94C4DC811103C003311105BCF211 -:1069600081E080938B156091D1197091D2198AE0E2 -:1069700090E00F940EAD0C94096B83ED95E00F94AD -:10698000BBAD0C94096B8FEB93E00E94A9A7882301 -:1069900061F003EC13E0F80181918F01882311F479 -:1069A0000C9496690E946EADF6CF82ED93E00E9442 -:1069B000A9A7882361F006ED13E0D8018D918D0120 -:1069C000882311F40C9496690E946EADF6CF85EF82 -:1069D00093E00E94A9A781110C94096B8AEF93E0C0 -:1069E0000E94A9A7882341F060E070E088EF9FE053 -:1069F0000E94B8FD0C94096B8DEF93E00E94A9A74B -:106A0000882321F00F9425880C94096B82E094E090 -:106A10000E94A9A7882311F40C94096B80E00E94BE -:106A20009FA90C94096B8EE50F94909B8AAF8111FE -:106A30000C94096B87E40F94909BF82E882311F433 -:106A40000C94BB420F94879B0F944EB56C34710528 -:106A500009F404C27CF56430710509F4FCC054F4F7 -:106A60006230710509F4E2C00CF0E9C077FF6DC037 -:106A70000C94AF426C31710509F43FC15CF46A308B -:106A8000710509F435C16B30710511F00C94AF42FA -:106A900080E02FC16E31710509F471C16B3471054D -:106AA00011F00C94AF4208E210E0FAE7EF2EF7E0A5 -:106AB000FF2EB5C16835710511F40C94096BECF427 -:106AC0006135710511F40C94764154F46F347105FD -:106AD00009F431C76035710509F459C70C94AF4208 -:106AE0006635710511F40C941F426735710511F07C -:106AF0000C94AF4281E00C9420426C35710511F486 -:106B00000C9428427CF46A35710511F40C942442EB -:106B10006B35710511F00C94AF4281E08093FA0E51 -:106B20000C94096B6236710511F40C94884263363B -:106B3000710511F00C94AF421092C80F60E084EC24 -:106B40009FE00F9475B30C94AA4280915E0F81115F -:106B50000C94096B0F94B0A36091480E7091490E8C -:106B600080914A0E90914B0E0F948CAE6B017C017C -:106B7000409041105090421060904310709044102B -:106B80008090D50F9090D60FA090D70FB090D80FCF -:106B9000A5019401C301B2010F94EEB320E030E0EF -:106BA00048EC52E40F94F5A79B01AC01C701B60174 -:106BB0000F943AB61816D4F4A3019201C501B4019A -:106BC0000F94EEB320E030E048EC52E40F94F5A7C8 -:106BD000A70196010F94EFB30F9454B56093480E3C -:106BE0007093490E80934A0E90934B0E8091FB1048 -:106BF000882311F40C94076B88E50F94909B811106 -:106C00000C94076B89E50F94909B81110C94076B92 -:106C10008AE50F94909B81110C94076B85E40F9487 -:106C2000909B81110C94DE6A0C94076B80915E0F2F -:106C300081110C94096B0F9471A481E008C08091BC -:106C40005E0F81110C94096B0F9471A480E00F9476 -:106C5000729D0C94096B80E50F94909B882339F00A -:106C60000F94879B0F9454B56B017C0103C0C12C1A -:106C7000D12C760183E50F94909B882361F00F94CB -:106C8000879B20E030E04AE754E40F94F5A70F9487 -:106C900054B56B017C01C114D104E104F10421F06D -:106CA0008EEB93E10F94EE510F9498830F94258807 -:106CB000C60ED71EE81EF91E0F9425886093FF0E9E -:106CC0007093000F8093010F9093020F0F9425880B -:106CD0006C157D058E059F0510F00C94096B0F94C3 -:106CE000BC7D80E00F94680E80E00F94932FEECF70 -:106CF00081E00F94FCA40C94096B88E50F94909BA1 -:106D00008EAF0F947C9B1B012C0189E50F94909B07 -:106D1000682E0F947C9B26966CAF7DAF8EAF9FAF95 -:106D200026978AE50F94909BD82E0F947C9B4B015D -:106D30005C0187E50F94909B782E83E40F94909BE1 -:106D40007F928F93CD2C2696ECACFDAC0EAD1FAD93 -:106D50002697262DB201A1018EAD0F94D96B0F900D -:106D60000F90BEADB1110C94096B61100C94096BBE -:106D700071100C94096BD1100C94096B08C60F9418 -:106D8000988381E00E94DBA58C0180E090E0A8E47C -:106D9000B4E480937E0290937F02A0938002B0932C -:106DA000810260E070E080E291EC0F949D4280915E -:106DB00040108F9380913F108F9380913E108F935E -:106DC00080913D108F9380913C108F9380913B1068 -:106DD0008F9380913A108F93809139108F93809187 -:106DE00038108F93809137108F93809136108F9346 -:106DF000809135108F938DE99FE29F938F9383E865 -:106E000097E09F938F930F9493ADC8010E94BAA50A -:106E10000FB6F894DEBF0FBECDBF0C94096BB8015E -:106E2000012E000C880B990B0F948EAE0F94A808BE -:106E30009F938F937F936F931F930F93FF92EF9284 -:106E40000F9493AD0F5F1F4F0FB6F894DEBF0FBEC8 -:106E5000CDBF0F36110519F70C94096B0E94C6AC13 -:106E60008A3F30F08CE993E10F9441080C94096B50 -:106E70008091FF0C882341F08091000D882321F040 -:106E80008091010D811106C081E08093971380EA03 -:106E900090E197C585E593E10F94410840E060E0FB -:106EA00082EB9BE10F94A007882309F493C080E054 -:106EB00090E0A0EAB0E480933D1090933E10A09340 -:106EC0003F10B09340102091391030913A1040910A -:106ED0003B1050913C1060913510709136108091AC -:106EE000371090913810FEEF6F2EFCE07F2E7F92CE -:106EF0006F92812C912CA8E4AA2EA2E4BA2EB1E4C0 -:106F0000CB2EB0E1DB2EE12CF12C00EA10E40E9444 -:106F1000518780923D1090923E10A0923F10B09207 -:106F2000401080E090E0A4E3B3E4809339109093A4 -:106F30003A10A0933B10B0933C10609135107091C3 -:106F4000361080913710909138107F926F928501A2 -:106F5000740120E030E044E353E40E9451870F9431 -:106F600098838AE89BE10F944108EEEEFEE12591BB -:106F70003591459154912093391030933A104093B4 -:106F80003B1050933C10EAEEFEE1659175918591BE -:106F900094916093351070933610809337109093CE -:106FA0003810E0903D10F0903E1000913F1010918D -:106FB00040107F926F920E9451870F94988341E016 -:106FC00060E080E00F94BB6E0F900F900F900F90D9 -:106FD0000F900F9020E030E04CE052E46091A10E61 -:106FE0007091A20E8091A30E9091A40E0F943AB6C8 -:106FF00018160CF0A4C08091C80F8111A0C080E0C9 -:1070000090E0A8ECB2E480933D1090933E10A093E2 -:107010003F10B09340102091391030913A104091B8 -:107020003B1050913C10609135107091361080915A -:10703000371090913810EEEFFCE0FF93EF93812C26 -:10704000912C18E4A12E12E4B12E01E4C02E00E12F -:10705000D02EE12CF12C08EC12E40E94518780E044 -:1070600090E0ACE0B2E48F8F98A3A9A3BAA30F94E9 -:10707000423219821A821B821C82CE0101960F9421 -:107080007F761092030D1092020D19821A821B82D4 -:107090001C821D82CE0101960E943EDD0F900F9052 -:1070A0002F8D38A149A15AA16091A10E7091A20E15 -:1070B0008091A30E9091A40E0F943AB6181694F5F1 -:1070C00089E692E10F94930764E080E00F946E32BA -:1070D00082E00E949D9A81EA9EE00E9446A00F9461 -:1070E000103185E094E00F941031CE014F960E944C -:1070F00046A00F94103187E094E00F94103188EE91 -:1071000093E00F94BD120E94C7F240E053E567E0A0 -:1071100070E0CE0101960E94F9DC882309F4C0CF0B -:1071200010E001C011E06BE47BE581E00F942332B5 -:1071300081E00F942737111102C080E0F8C381E08D -:107140000F94273781E090E09093230280932202EE -:10715000E2E8F0E184918F01882339F00E946EAD5E -:107160000F5F1F4FF8018491F7CF8AE00E946EAD48 -:107170001A821982C090A10ED090A20EE090A30EA8 -:10718000F090A40E20E030E040EA50E4C701B601E0 -:107190000F94DDB40F944EB525E0269FA001279FE4 -:1071A000500D1124BA01550F880B990B0F948EAE18 -:1071B0003B01382E292E20E030E04CE052E40F94C1 -:1071C00088AE87FF06C0612C712CACE03A2EB2E489 -:1071D0002B2EC101262D372D492F522DC701B60167 -:1071E0000F943AB6181674F420E030E040EA50E408 -:1071F000F101662D772D8F2F922D0F94EFB33B0168 -:10720000382E292E2F923F927F926F9281E697E03F -:107210009F938F930F9493AD20E030E040EF51E4C3 -:10722000F101662D772D8F2F922D0F94EEB320E074 -:1072300030E04CE852E40F94EFB30F944EB57093E6 -:10724000030D6093020D84E090E09093410E8093D3 -:10725000400E81E090E09093260F8093250F86E109 -:107260009DE20F94EE5180E090E0A0EAB0E48093BC -:107270003D1090933E10A0933F10B093401020918A -:10728000391030913A1040913B1050913C10609170 -:107290003510709136108091371090913810BEEFF4 -:1072A0004B2EBCE05B2E5F924F92812C912C18E408 -:1072B000A12E12E4B12E01E4C02E00E1D02EE12C6B -:1072C000F12C00EA10E40E94518780E090E0A0EAEF -:1072D000B1E48093351090933610A0933710B0939B -:1072E000381080E090E0A0E7B2E4809339109093EA -:1072F0003A10A0933B10B0933C10E0903D10F090FA -:107300003E1000913F10109140105F924F929C01EF -:10731000AD0160E070E080EA91E40E9451878AE963 -:1073200099E9A9E1BEE380933D1090933E10A093AC -:107330003F10B09340102091391030913A10409195 -:107340003B1050913C106091351070913610809137 -:107350003710909138105F924F921AE9E12E19E997 -:10736000F12E09E11EE30E9451870F9498830FB616 -:10737000F894DEBF0FBECDBF2091A10E3091A20EBA -:107380004091A30E5091A40EF101662D772D8F2F01 -:10739000922D0F943AB618163CF488EE93E00F94B1 -:1073A000BD120E94C7F2E8CF60E086EA9FE00F942A -:1073B00075B380E090E0A0EAB0E480933D10909334 -:1073C0003E10A0933F10B09340102091391030919F -:1073D0003A1040913B1050913C10609135107091E3 -:1073E000361080913710909138100EEF402E0CE03F -:1073F000502E5F924F92812C912CE8E4AE2EE2E465 -:10740000BE2EF1E4CF2EF0E1DF2EE12CF12C00EACC -:1074100010E40E945187EAEEFEE165917591859135 -:107420009491609335107093361080933710909339 -:107430003810EEEEFEE1259135914591549120935F -:10744000391030933A1040933B1050933C10E09029 -:107450003D10F0903E1000913F10109140105F924F -:107460004F920E9451870F94988360E070E080E80B -:107470009FEB0F949D420F900F900F900F908823D9 -:1074800009F45BCE30913D1027963FAF279740918E -:107490003E102B964FAF2B9750913F102F965FAF1A -:1074A0002F976091401063966FAF63976F935F93D0 -:1074B0004F933F9384E597E09F938F930F9493AD01 -:1074C0000F900F900F900F900F900F908EEA9FE00B -:1074D0009FAF8EAF44244A94542C13E2C12ED12C7A -:1074E000E12CF12C8201B6010D2C000C880B990BBC -:1074F0000F948EAE4B015C0197012F5F3F4F3BAF66 -:107500002AAFDF92CF923F932F9348E157E05F93EA -:107510004F930F9493AD0F900F900F900F900F908B -:107520000F908FEF4816580611F40C94DC6FBE01D3 -:107530006F5F7F4F8EAD9FAD0E94B8FDA501940196 -:10754000F101662D772D8F2F922D0F9488AE18168E -:10755000A4F495E0E916F10471F095E0C90ED11C90 -:10756000AFEF4A1A5A0AEEADFFAD3296FFAFEEAF5B -:10757000EAACFBACB7CF05E010E0C8018752984FEA -:10758000DC01AA0FBB1FBFAFAEAF3801B3E06B0E7B -:10759000711C25E0209FC001219F900D11241BAE7E -:1075A0001AAEFC01BD966696FFAFEEAF6697AEEFE2 -:1075B0004A2EACE05A2EC301029705970CF0B6C1D3 -:1075C00066966EAD7FAD66978AAC9BAC680D791DF3 -:1075D000072E000C880B990B0F948EAE26966CAF7D -:1075E0007DAF8EAF9FAF26977F926F92FBE0AF2E5D -:1075F000F7E0BF2EBF92AF920F9493AD7092260F1B -:107600006092250F20E030E040EF51E426966CAD0B -:107610007DAD8EAD9FAD26970F94EEB320E030E0A8 -:1076200040E251E40F94F5A720E030E040EA50E456 -:107630000F94DDB420E030E048E452E40F94EFB35F -:107640000F944EB57093030D6093020D80E090E0AF -:10765000A0EAB0E480933D1090933E10A0933F10B9 -:10766000B09340102091391030913A1040913B1066 -:1076700050913C1060913510709136108091371008 -:10768000909138105F924F92812C912CA8E4AA2EF1 -:10769000A2E4BA2EB1E4CB2EB0E1DB2EE12CF12C2A -:1076A00000EA10E40E94518780E090E0A0EAB1E493 -:1076B0008093351090933610A0933710B093381004 -:1076C000812C912CF0E7AF2EF2E4BF2E809239107E -:1076D00090923A10A0923B10B0923C10E0903D1076 -:1076E000F0903E1000913F10109140105F924F9229 -:1076F000812C912C28E4A22E22E4B22E20E030E04E -:1077000040E752E4BC01CD010E9451872AE939E9E2 -:1077100049E15EE320933D1030933E1040933F10CB -:10772000509340102091391030913A1040913B1005 -:1077300050913C1060913510709136108091371047 -:10774000909138105F924F921AE9E12E19E9F12ECB -:1077500009E11EE30E9451870F9498830FB6F894B5 -:10776000DEBF0FBECDBF2091A10E3091A20E409181 -:10777000A30E5091A40E26966CAD7DAD8EAD9FAD3F -:1077800026970F943AB618163CF488EE93E00F94BF -:10779000BD120E94C7F2E7CF80E090E0A0EAB0E41B -:1077A00080933D1090933E10A0933F10B0934010F3 -:1077B0002091391030913A1040913B1050913C107B -:1077C000609135107091361080913710909138107B -:1077D0005F924F92812C912CB8E4AB2EB2E4BB2E79 -:1077E00011E4C12E10E1D12EE12CF12C00EA10E4BD -:1077F0000E945187EAEEFEE1659175918591949121 -:107800006093351070933610809337109093381032 -:10781000EEEEFEE12591359145915491209339107A -:1078200030933A1040933B1050933C10E0903D1041 -:10783000F0903E1000913F10109140105F924F92D7 -:107840000E9451870F94988360E070E080E89FEB7E -:107850000F949D42AAADBBAD1596BBAFAAAFBFEFCB -:107860006B1A7B0A0F900F900F900F90811103C03D -:107870000F94D59C5BC027967FAD27972B966FAD55 -:107880002B972F969FAD2F9763968FAD6397272FDA -:10789000362F492F582F60913D1070913E108091E6 -:1078A0003F10909140100F94EEB3162F072FF82E33 -:1078B000E92E2091851030918610409187105091CB -:1078C0008810D801F7016B2F7A2F8F2F9E2F0F94DE -:1078D000F5A70F944EB57A836983EF92FF920F93C9 -:1078E0001F938091A40E8F938091A30E8F9380910C -:1078F000A20E8F938091A10E8F93EFEDF6E0FF9390 -:10790000EF930F9493ADBE016F5F7F4F8EAD9FAD30 -:107910000E94B8FD2EAD3FAD2E5F3F4F3FAF2EAF63 -:107920000FB6F894DEBF0FBECDBF45CE81E00F94F9 -:10793000D59C0C94096B0FEF10E0A7EDCA2EA6E0C2 -:10794000DA2E1093BC190093BB19F4E6EF2EF12C3C -:1079500084E690E00F94BD1251E0E51AF108C1F7FA -:10796000809179138F93809178138F931F930F9346 -:10797000DF92CF920F9493AD055011090F900F90A5 -:107980000F900F900F900F90E1F60C94096B81E02F -:107990008093590E2091FF0C80910110909102105C -:1079A000222341F02091000D222321F05090010D5F -:1079B00051100FC0029749F081E0809397138BE735 -:1079C00090E10F94B1760C94096B1092590E0C94BF -:1079D000096B0297D1F38091400E9091410E289649 -:1079E0009FAF8EAF2897A091250FB091260F2C96B0 -:1079F000BFAFAEAF2C9781E090E09093410E8093A3 -:107A0000400E83E190E09093260F8093250F81E054 -:107A10000F94932F0F94F5600F94682A80E090E004 -:107A2000A0EAB0E480933D1090933E10A0933F10E5 -:107A3000B09340102091391030913A1040913B1092 -:107A400050913C1060913510709136108091371034 -:107A500090913810EEEF6E2EECE07E2E7F926F92BA -:107A6000F5E58F2E982CA82CF1E4BF2EA1E4CA2EA8 -:107A7000A0E1DA2EE12CF12C00EA10E40E945187FB -:107A8000E0E1F3E5659175918591949160933510EE -:107A9000709336108093371090933810E4E1F3E53B -:107AA00025913591459154912093391030933A1096 -:107AB00040933B1050933C10E0903D10F0903E10EE -:107AC00000913F10109140107F926F92812C912C69 -:107AD000E8ECAE2EE2E4BE2E0E9451870F9498830C -:107AE0000F900F900F900F9005EC1FE0C8010F94BE -:107AF00070B3019639F00E5F1F4F053DEFE01E0792 -:107B0000A9F75AAE80E00E94DBA560969FAF8EAFCA -:107B1000609780E1482E83E5582E612C712CC301BB -:107B200063E070E00F94A1B824967FAF6EAF249706 -:107B30001C0160FF06C002E0802E912C881A990A71 -:107B400014019AAC9920A1F16114710489F1249671 -:107B50008EAD9FAD2497880F991F2496AEACBFAC15 -:107B600024978A0D9B1D820D931D880F991F8D539D -:107B7000904F0F9470B3BC01990F880B990B0F9421 -:107B80008EAE2AE037ED43E25CE30F94F5A7209137 -:107B90008D1530918E1540918F15509190150F9441 -:107BA000EFB322966CAF7DAF8EAF9FAF229706C02A -:107BB00022961CAE1DAE1EAE1FAE229720E030E016 -:107BC00040EA50E420933D1030933E1040933F1024 -:107BD000509340102091391030913A1040913B1051 -:107BE00050913C1060913510709136108091371093 -:107BF00090913810AEEFBCE0BF93AF93812C912CE5 -:107C0000B0EAAB2EB1E4BB2E11E4C12E10E1D12EAF -:107C1000E12CF12C00EA10E40E9451870F94988324 -:107C2000F20185919591A591B4918093351090932F -:107C30003610A0933710B0933810F2013496859126 -:107C40009591A591B4918093391090933A10A09397 -:107C50003B10B0933C1069E370E185E390E10E9432 -:107C60006BA8E0903D10F0903E1000913F101091F5 -:107C700040102091391030913A1040913B105091B2 -:107C80003C106091351070913610809137109091B2 -:107C90003810FEEF8F2EFCE09F2E9F928F92812C4A -:107CA000912CA6E1AA2EA3E4BA2E0E9451870F942C -:107CB00098830F900F900F900F90BAACBB2081F07B -:107CC0006114710469F020E030E040E85FE322963F -:107CD0006CAD7DAD8EAD9FAD22970F94EEB304C019 -:107CE00060E070E080E291EC0F949D42882309F4FB -:107CF0008BC0C0903D10D0903E10E0903F10F090AF -:107D00004010A701960160E070E080EA90E40F94D3 -:107D1000EEB32DEC3CEC4CEC5DE30F9488AE87FDAC -:107D200073C02AAD2223A1F0A701960122966CAD63 -:107D30007DAD8EAD9FAD22970F94EEB39F7720E07F -:107D400030E040E85FE30F943AB618160CF45CC0DC -:107D5000C090A10ED090A20EE090A30EF090A40EC1 -:107D600080910F078823A9F00E9490A9882389F0A9 -:107D7000C701B6010F94A808209185103091861094 -:107D800040918710509188100F94DDB49B01AC0195 -:107D900003C020E030E0A901A7E024968EAD9FAD9E -:107DA0002497A89F8001A99F100D1124020D131D77 -:107DB000000F111F000F111F04571A4E60913D1044 -:107DC00070913E1080913F10909140100F94EEB34F -:107DD000F80161837283838394838091250F90914E -:107DE000260F01979093260F8093250FFFEF6F1AB0 -:107DF0007F0A81E00F94932F28E0420E511C39E056 -:107E00006316710409F08BCE80E090E0A0EAB0E444 -:107E100080933D1090933E10A0933F10B09340107C -:107E20002091391030913A1040913B1050913C1004 -:107E30006091351070913610809137109091381004 -:107E4000EEEFFCE0FF93EF93812C912C00EAA02E43 -:107E500001E4B02EE1E4CE2EE0E1DE2EE12CF12CA7 -:107E600000EA10E40E9451870F9498830F900F90BE -:107E700049E06416710409F47AC080910107909179 -:107E800002078130910531F018F0029719F005C012 -:107E900080E001C081E00E94E5BC212C312CB0EAD9 -:107EA0004B2EB0E45B2E1EEF612E1CE0712E82E2A1 -:107EB00093E10F9493078EE190E00F94729C0E94DF -:107EC00014A65091DB0F5AAF61E06093DB0F109264 -:107ED000DA0F20923D1030923E1040923F105092A7 -:107EE00040102091391030913A1040913B10509140 -:107EF0003C10609135107091361080913710909140 -:107F000038107F926F92812C912CE0EAAE2EE1E442 -:107F1000BE2EF1E4CF2EF0E1DF2EE12CF12C00EAB1 -:107F200010E40E9451870F9498838AAD8093DB0FF1 -:107F30001092DA0F82E00F9485830F900F90A801C2 -:107F400097010F943AB618160CF4B1CF1092410E67 -:107F50001092400E81E00F94273740E061E081E00D -:107F60000F94BB6E81E0809397130C94096B60961D -:107F70008EAD9FAD60970E94BAA50F94152A6091AF -:107F8000FC0C7091FD0C072E000C880B990B0F94C4 -:107F90008EAE9058209185103091861040918710B8 -:107FA000509188100F94DDB40F94262A80EC9FE046 -:107FB0000F9463B3082FDE0111961D0110E080902D -:107FC000870290908802A0908902B0908A028AAEBF -:107FD0009BAEACAEBDAE50EE852E55E1952E2AADD2 -:107FE0003BAD4CAD5DAD29833A834B835C83D101BE -:107FF0008D911D010F94909B882319F00F947C9B09 -:108000001BC0013009F026C1123028F4112341F0C1 -:108010008EEB9FE00AC0123031F08CEB9FE005C080 -:108020008FEB9FE002C08DEB9FE00F9463B3682F4E -:10803000880F770B880B990B6115710581059105E8 -:1080400009F408C10F948EAE2FE632E143E85AE3FB -:108050000F94F5A76B017C019F7727E139ED4EEC7A -:108060005DE30F943AB618160CF033C0E4E7FEE572 -:1080700084915F01882341F00E946EADFFEFAF1A3B -:10808000BF0AF5018491F6CFE7E5F0E184915F0145 -:10809000882341F00E946EADFFEFAF1ABF0AF501D1 -:1080A0008491F6CF42E0C701B6010E9411AEEEE422 -:1080B000F0E184917F01882341F00E946EADFFEFD3 -:1080C000EF1AFF0AF7018491F6CF8AE00E946EADA5 -:1080D000C1C020E030E040E05FE3C701B6011230EC -:1080E00009F461C0133009F48AC0113071F10F94A2 -:1080F000F5A72B013C014CE8A42E45E1B42EA301C9 -:108100009201D50115966D917D918D919C91189755 -:108110000F94EFB3F5016583768387839087A7017A -:10812000960161817281838194810F94EFB3D501AF -:1081300011966D937D938D939C931497BCE1AB0E38 -:10814000B11C8A149B04D9F685C00F94F5A72B01A6 -:108150003C013CE8A32E35E1B32EA3019201F501C9 -:1081600065817681878190850F94EFB3D50115964F -:108170006D937D938D939C931897A7019601199603 -:108180006D917D918D919C911C970F94EFB3F501AA -:108190006187728783879487FCE1AF0EB11C8A14D4 -:1081A0009B04D9F657C00F94F5A72B013C012DE88D -:1081B000A22E25E1B22EA3019201D5015C966D910C -:1081C0007D918D919C915F970F94EFB3F501648F32 -:1081D000758F868F978FA70196016081718182814B -:1081E00093810F94EFB3D5016D937D938D939D9300 -:1081F0005D01B9E9AB16B5E1BB06E9F62BC00F94FA -:10820000F5A72B013C0199EAA92E95E1B92EA3010E -:108210009201F50160817181828193810F94EFB3A6 -:10822000D5016D937D938D939D935D01A70196017B -:1082300058966D917D918D919C915B970F94EFB3C2 -:10824000F501608F718F828F938FF5EBAF16F5E19B -:10825000BF06E9F61F5F143009F0C1CE0F940D611F -:1082600081E080938C150F94C12AE091FE0C24E0EC -:10827000E29FF0011124E452F04F20E030E04FE2A1 -:1082800053E460817181828193810F943AB618160C -:1082900084F480910F07882361F00E9490A98823BD -:1082A00041F08091020D9091030DC29714F00C944F -:1082B0005F6B81E090E090932302809322028FEB2A -:1082C00094E10F94EE5128964EAD5FAD28975093F0 -:1082D000410E4093400E2C968EAD9FAD2C979093FF -:1082E000260F8093250F1092590E34C180918C1562 -:1082F000882309F495C0E4E4F0E184918F01882398 -:1083000039F00E946EAD0F5F1F4FF8018491F7CFD7 -:1083100067E070E080E090E00E94F7ADE2E4F0E119 -:1083200084918F01882339F00E946EAD0F5F1F4F3B -:10833000F8018491F7CF67E070E080E090E00E9460 -:10834000F7ADEFE2F0E184918F01882339F00E94CC -:108350006EAD0F5F1F4FF8018491F7CF65E070E0BD -:1083600080E090E00E94F7ADEDE1F0E184918F01B3 -:10837000882339F00E946EAD0F5F1F4FF801849182 -:10838000F7CF8AE00E946EAD00E010E0BAE16B2EFC -:10839000B0E17B2E88E1A82E80E1B82EE12CF12CF3 -:1083A0004801F8EA8F0E911CF3018491AAE1CA2ECC -:1083B000A0E1DA2E882341F00E946EADFFEFCF1AC4 -:1083C000DF0AF6018491F6CFF401EE0DFF1DE457AC -:1083D000FA4E618172818381948145E00E9411AEE1 -:1083E000F4E0EF0EF11C2CE1E216F104E9F6F501E0 -:1083F0008491F8E1EF2EF0E1FF2E882341F00E94F6 -:108400006EADFFEFEF1AFF0AF7018491F6CF0C5122 -:1084100011090C33FFEF1F0709F0C0CF0C94096B53 -:10842000EAEFFFE084918F01882311F40C949669A0 -:108430000E946EAD0F5F1F4FF8018491F5CF86EE5D -:108440000E949AA90C94096B1092FA0E0C94096B75 -:1084500085E40F94909B811102C00F94988369EF7B -:10846000662E62E0762E75E3A72E70E1B72EE1ED61 -:108470008E2EE0E19E2ED12CD3018D913D010F94E3 -:10848000909B8823C9F1B3E0DB120CC00F94879B4B -:10849000F501608371838283938381E490E10E947C -:1084A000D5BD2AC00F94879B9B01AC01D4016D916F -:1084B0007D918D919C910F94EFB3F5016083718351 -:1084C00082839383E0903D10F0903E1000913F1026 -:1084D000109140102091391030913A1040913B108A -:1084E00050913C106091351070913610809137108A -:1084F000909138100F94BA59D394F4E0AF0EB11C98 -:1085000024E0820E911C34E0D312B6CF0C94096B98 -:1085100081E08093C80F0F94258860937A1670933A -:108520007B1680937C1690937D166091C80F84EC27 -:108530009FE00F9475B369E277E081EC9FE00E94C1 -:10854000B8FD1092420E60E08FEF9FE00F9475B37C -:108550000C94096B82E00F94932F0C94096B80911B -:1085600087159091881583569C4E9F938F9385EE27 -:108570009FE00C94C2338DE40F94909B882311F4F8 -:108580000C946D68E0912B0DF0912C0D319681913A -:108590008032E9F38930D9F380538A3060F08091DA -:1085A00087159091881583569C4E9F938F9380EDED -:1085B0009FE00C94C2330F94879B0F944EB5AB0190 -:1085C000BC01CA0150932D0F40932C0F4937510520 -:1085D00011F40C94B4500CF0DCC04F32510509F486 -:1085E000AAC60CF061C04931510509F451C33CF5EC -:1085F0004431510509F4BDC294F44131510509F4E7 -:10860000AEC234F44230510508F4F6C10C945668F9 -:108610004231510511F40C94A94D0C945668463121 -:10862000510509F4EAC20CF4E4C24731510509F4DA -:10863000EAC24831510509F4FEC20C9456684E3125 -:10864000510509F45BC48CF44B31510509F43BC36B -:108650000CF42BC34C31510509F424C44D315105A0 -:1086600011F40C9468680C9456684A32510509F468 -:108670000CC654F44F31510509F4ACC540325105D4 -:1086800009F40DC50C9456684C32510509F444C6E2 -:108690004D32510511F00C9456688AE50F94909B69 -:1086A0000E9405700C9468684936510509F41BC78F -:1086B000A4F54435510511F40C94A94DDCF4413571 -:1086C000510511F40C948B4D34F44934510509F4DF -:1086D00078C60C9456684235510511F40C94A54D9A -:1086E0004335510511F00C94566881E08093320FA8 -:1086F0000C9468684635510511F40C940B4E14F433 -:108700000C94F04D4C35510511F40C942A4E48361A -:10871000510509F4B3C60C9456684037510509F465 -:10872000CCC69CF44B36510511F40C94854D14F4D1 -:108730000C94554D4D36510509F4F4C74E3651058C -:1087400011F40C94AE4E0C9456684337510511F455 -:108750000C94FE4E84F44137510511F40C94C14E33 -:108760004237510511F00C945668E2E6FDE0849121 -:108770008F010C94D74F4737510511F40C94B95021 -:108780004837510511F00C945668109221020C9450 -:1087900068688E3541E0940711F40C949C670CF0E6 -:1087A0007FC0803D910511F40C942A54CCF58B3C8C -:1087B000910511F40C948752FCF48E3B910511F451 -:1087C0000C942C4C34F48C38910509F47BC60C9431 -:1087D0005668883C910511F40C94D651893C91055A -:1087E00011F00C94566849EFE42E42E0F42E09E7AC -:1087F00010E1D12C0C9442528D3C910511F40C9453 -:10880000255314F40C94E0528E3C910511F40C9411 -:10881000D4538F3C910511F40C94F3530C94566887 -:10882000803F910511F40C946868CCF48C3D91055F -:1088300011F40C94A7543CF4813D910511F40C946F -:1088400052540C9456688D3D910511F40C94B85413 -:10885000823E910511F40C94D9540C9456688E32D2 -:1088600061E0960711F40C94C8566CF48C32B1E0B8 -:108870009B0711F40C943C558D32914011F40C94EB -:1088800074550C9456688F32F1E09F0711F40C94E4 -:10889000DD568033914011F40C9430560C94566898 -:1088A0008A3532E0930711F40C9429630CF047C029 -:1088B000853F51E0950711F40C94EB5AECF48039A4 -:1088C000A1E09A0711F40C94A35A3CF48F3591401F -:1088D00011F40C9468680C9456688339F1E09F0792 -:1088E00011F40C94A75A843F914011F00C945668EF -:1088F0000E9491B00C9468688D3F31E0930711F4A9 -:108900000C94AB5D6CF4863F51E0950711F40C9428 -:10891000EF5A873F914011F40C94F35A0C94566827 -:108920008835A2E09A0711F40C94865E893592404E -:1089300011F00C9456680F94348B0C9468688D3544 -:10894000E3E09E0711F40C94FD63DCF48E3B22E01F -:10895000920711F40C9445683CF48D3B924011F45D -:108960000C9439680C945668833553E0950711F4DC -:108970000C94C75D8C35934011F40C942C630C94CB -:1089800056688C38A3E09A0711F40C94686894F444 -:108990008438E3E09E0711F40C9419668B389340F9 -:1089A00011F00C94566809EFA02E02E0B02E00E002 -:1089B0000C947C67803A23E0920709F4DCC3873E7D -:1089C000934011F00C94566810925E0F1092F50FC0 -:1089D0008091030F9091040FA091050FB091060FA5 -:1089E00080932D0D90932E0DA0932F0DB093300DED -:1089F0000F94DF120C946868E0912B0DF0912C0D10 -:108A00008F010E5F1F4F80E50F94909B882371F0BC -:108A10000F94879B0F9454B56B017C01AA24A394F7 -:108A2000672B682B692B31F4A12C04C0A12CC12C1D -:108A3000D12C760183E50F94909B882391F00F94BD -:108A4000879B20E030E04AE754E40F94F5A70F94A9 -:108A500054B56B017C01BB24B394672B682B692B45 -:108A600009F4B12C6AE270E0C8010F9433B90097A1 -:108A700011F0DC011C92F801CF0121912032E1F3C9 -:108A8000A11007C0B11005C0222319F00F94605344 -:108A900004C081E193E10F94EE5181E08093470E91 -:108AA0001092460E0F9498830F9425886093FF0EC2 -:108AB0007093000F8093010F9093020FC114D104A3 -:108AC000E104F10419F10F942588C60ED71EE81EA3 -:108AD000F91E84E090E090932302809322020F9489 -:108AE00025886C157D058E059F0510F00C94A16BF3 -:108AF0000F946B3081110C94A16B0F94BC7D81E0BD -:108B00000F94680E80E00F94932FE9CF84E090E0FB -:108B100090932302809322020F946B30811109C03D -:108B20000F94BC7D81E00F94680E80E00F94932F2A -:108B3000F3CF82E090E09093230280932202809111 -:108B40008016882331F085EB9DE20F94EE510C9452 -:108B500068688FEB94E10F94EE510C94686888E09C -:108B600093E10F94EE5117981698159814980C9459 -:108B70006868E7ECF6E084918F01882339F00E9461 -:108B80006EAD0F5F1F4FF8018491F7CF8AE00E940E -:108B90006EAD109261191092601984ED96E10E94F9 -:108BA000A4E08BE1E4EDF6E1DE01119601900D9277 -:108BB0008A95E1F740E050E0BE016F5F7F4F88E0AB -:108BC00094E00F94787BCE0101960E94BDA7E9EB5B -:108BD000F6E084918F01882339F00E946EAD0F5F1B -:108BE0001F4FF8018491F7CF8AE00E946EAD0C947C -:108BF00068680F94BB480C946868109280161092B5 -:108C000081160C94686880912B0D90912C0D6AE26E -:108C100070E004960F9433B9009711F0DC011C92B8 -:108C200080912B0D90912C0D41E061E004960F9402 -:108C3000E5430C94686880918216811114C060E04D -:108C400086E69FE00F9475B360E088E69FE00F949E -:108C500075B360E085E69FE00F9475B360E084E64D -:108C60009FE00F9475B380918116882329F081E0ED -:108C700080938016109282160F9425886093500E70 -:108C80007093510E8093520E9093530E0C9468681B -:108C900080918016882311F40C94686810928016D5 -:108CA00081E0809382160C946868809181168823F5 -:108CB00011F40C94686883E50F94909B81110C94D7 -:108CC000AD6B0C94686880918016882309F4B8C055 -:108CD0000CE916E1F80181918F01882319F00E94B7 -:108CE0006EADF8CFEFEDFDE084918F01882339F070 -:108CF0000E946EAD0F5F1F4FF8018491F7CFE1EC3A -:108D0000F5E084918F01882339F00E946EAD0F5FEA -:108D10001F4FF8018491F7CF60915B1970915C1936 -:108D200080915D1990915E194AE00E9486ADEDED4B -:108D3000FDE084918F01882339F00E946EAD0F5FB2 -:108D40001F4FF8018491F7CF609153197091541916 -:108D500080915519909156194AE00E9486AD8AE09B -:108D60000E946EAD0F94258840E6C42E4AEED42EA4 -:108D7000E12CF12CA70196010F94B3B349015A01DC -:108D80006091500E7091510E8091520E9091530E41 -:108D9000A70196010F94B3B38401021B130BC80102 -:108DA0006CE370E00F948DB8CB019927EAE0F0E016 -:108DB000BF010F94A1B8282FCB01BF010F94A1B818 -:108DC000805D8093B319205D2093B4191092B5197A -:108DD00053EBE52E59E1F52E6701D6018D916D011A -:108DE000882319F00E946EADF8CF8AE30E946EAD21 -:108DF000C8016CE370E00F948DB86AE070E00F94E6 -:108E0000A1B8605D6093B319805D8093B41910922E -:108E1000B519F70181917F01882319F00E946EAD89 -:108E2000F8CFEBEDFDE084918F01882311F40C94D1 -:108E300068680E946EAD0F5F1F4FF8018491F5CFF7 -:108E400080918216882371F0EBECFDE084918F0114 -:108E5000882309F4C9CE0E946EAD0F5F1F4FF80141 -:108E60008491F6CF80913F0E882371F0EFEBFDE007 -:108E700084918F01882309F4B7CE0E946EAD0F5FF5 -:108E80001F4FF8018491F6CFEFEAFDE084918F0146 -:108E9000882309F4A9CE0E946EAD0F5F1F4FF80121 -:108EA0008491F6CF80912B0D90912C0D6AE270E0A9 -:108EB00004960F9433B98C01892BA9F08091871502 -:108EC000909188156EE470E083569C4E0F9433B9F0 -:108ED00060E270E00F9433B9019690932C0D80936B -:108EE0002B0DD8011C9280912B0D90912C0D41E0FF -:108EF00060E004960F94E5430C94686880918116B5 -:108F0000882311F40C9468680F94375780912B0DC7 -:108F100090912C0D6AE270E004960F9433B98C01A5 -:108F2000892BA9F080918715909188156EE470E0E7 -:108F300083569C4E0F9433B960E270E00F9433B9BE -:108F4000019690932C0D80932B0DF8011082C09008 -:108F50002B0DD0902C0D86010C5F1F4F8091811638 -:108F6000882311F40C94686886EA98E10E94CAE3A9 -:108F7000109280161F8E1AA284ED96E19093F0163F -:108F80008093EF160115110591F0D60114968C917E -:108F90008F3239F4BE01615E7F4FC8010F942B59A7 -:108FA00006C081EF96E19093F0168093EF166091E2 -:108FB000EF167091F01619821C8222E0A801CE01F2 -:108FC00001960E9491E58823A1F0CE0101960F94AD -:108FD000E67A882371F061E0CE0101960E944BE3AE -:108FE000009739F025EEFC0120831C820E94CFDD22 -:108FF000F82ECE0101960E94BDA7FF2021F1E1EAE3 -:10900000FDE084917F01882341F00E946EADFFEF67 -:10901000EF1AFF0AF7018491F6CFD8018D918D01E7 -:10902000882319F00E946EADF8CF8AE00E946EADE1 -:1090300010925B1910925C1910925D1910925E19D2 -:109040000F94A84626C0E9E8FDE084917F018823BB -:1090500041F00E946EADBFEFEB1AFB0AF70184915D -:10906000F6CFD8018D918D01882319F00E946EAD45 -:10907000F8CFE7E8FDE084918F01882339F00E9462 -:109080006EAD0F5F1F4FF8018491F7CF8AE00E9409 -:109090006EADCE014F960E94BDA70C94686880917A -:1090A000801681110F94988300912B0D10912C0D37 -:1090B0000C5F1F4F6AE270E0C8010F9433B97C0166 -:1090C00061E270E0C8010F9433B9009719F08C0188 -:1090D0000F5F1F4FE114F10411F0D7011C9280E5DE -:1090E0000F94909BF82E80912B0D90912C0D0817CA -:1090F000190708F4F12C80918116882311F40C943F -:10910000686841E04F2561E0C8010F94E54383E5BD -:109110000F94909B8823B9F080912B0D90912C0D8A -:109120008017910780F40F947C9BAB01BC014093A6 -:109130005B1950935C1960935D1970935E1986EA10 -:1091400098E10E940EE080918116882329F081E049 -:109150008093801610928216F1100C9468680F9418 -:1091600025886093500E7093510E8093520E909309 -:10917000530E0C94686880912B0D90912C0D6AE22F -:1091800070E005960F9433B98C01892BA9F080917A -:109190008715909188156EE470E083569C4E0F946D -:1091A00033B960E270E00F9433B9019690932C0DBF -:1091B00080932B0DF801108280912B0D90912C0D36 -:1091C00021E020937F1641E060E005960F94E5438F -:1091D0000C9468680F9425880091500E1091510EE0 -:1091E0002091520E3091530E6B017C01C01AD10AAE -:1091F000E20AF30AC701B60128EE33E040E050E08E -:109200000F94B3B3CA01B9012CE330E040E050E061 -:109210000F94B3B37F936F93C701B60120E63AEE84 -:1092200040E050E00F94B3B33F932F9381EC9FE065 -:109230009F938F938E010F5F1F4F1F930F930F9478 -:10924000ECADE6E9FEE584910FB6F894DEBF0FBE03 -:10925000CDBF7F01882341F00E946EAD3FEFE31A3E -:10926000F30AF7018491F6CF7801D7018D917D0142 -:10927000882319F00E946EADF8CF8AE00E946EAD8F -:10928000C8010F9460530C94686883E50F94909B19 -:10929000882311F40C9468680F94879B0F944EB543 -:1092A000F62EE72E862F9E2D8C0180E50F94909B45 -:1092B000882331F00F3F110509F010F40C94BE6BB8 -:1092C0000DE010E0EBE8F2E08191919180179107B9 -:1092D00011F40C946868B2E0E33CFB07A9F7063090 -:1092E000110539F48F2D9E2D9093BC198093BB19D5 -:1092F00004C017FF02C00C94686861E0802F0F94CF -:109300000A866F2D802F0F94DC856F2D7E2D802F88 -:109310000F9446860C9468688FEF0E949AA960E0CB -:1093200070E088EF9FE00F948FB30F94192D0F9486 -:10933000FB2C0C94686884E090E090932302809367 -:1093400022020F941D370F94BC7D81E00F94680EAC -:1093500060E080E00F946E3288E79DE00F949531D5 -:1093600061E080E00F946E321E9903C082E79DE0B9 -:1093700002C085E79DE00F94953162E080E00F9494 -:109380006E321D9903C08CE69DE002C08FE69DE021 -:109390000F94953163E080E00F946E321C9903C006 -:1093A00086E69DE002C089E69DE00F9495310F941A -:1093B0006B30882341F20F941D370F94388A0C9438 -:1093C000686880E50F94909B882331F00F94879B09 -:1093D0000F9454B560933A0282E50F94909B8823D2 -:1093E00041F00F94879B0F9454B570933E026093A5 -:1093F0003D0281E50F94909B882331F00F94879B69 -:109400000F9454B56093390283E50F94909B8823A1 -:1094100041F00F94879B0F9454B570933C02609376 -:109420003B0280913E028F9380913D028F93809109 -:109430003A021F928F9385E796E09F938F930CE7F4 -:1094400016E01F930F930F9493AD80913C028F937E -:1094500080913B028F93809139021F928F938EE609 -:1094600096E09F938F931F930F930F9493AD0FB636 -:10947000F894DEBF0FBECDBF0C946868BE016F5F6D -:109480007F4F88E690E00F9436A381110C946868B2 -:1094900083E50F94909B882311F40C9468681981DC -:1094A0000F94879B11110C9468680F944EB57093BC -:1094B0008A15609389150C94686863E08DE696E0E0 -:1094C0000F940A0E83E50F94909B882311F40C945B -:1094D00068680F94879B0F944EB57093030D60934B -:1094E000020D0C946868BE016F5F7F4F89E690E0C3 -:1094F0000F9436A381110C946868EBEBFFE0849124 -:109500008F01882339F00E946EAD0F5F1F4FF80165 -:109510008491F7CFE98124E0E29FF0011124E45225 -:10952000F04F608171818281938141E00E9411AE90 -:10953000E8EBFFE084918F01882339F00E946EAD43 -:109540000F5F1F4FF8018491F7CFE981F0E0EE0F34 -:10955000FF1FE757FA4E60817181072E000C880BC0 -:10956000990B0F948EAE41E00E9411AEE4EBFFE048 -:1095700084918F01882339F00E946EAD0F5F1F4FD9 -:10958000F8018491F7CF60910807709109078091E5 -:109590000A0790910B0741E00E9411AEE1EBFFE05A -:1095A00084918F01882339F00E946EAD0F5F1F4FA9 -:1095B000F8018491F7CF6091020D7091030D072E91 -:1095C000000C880B990B0F948EAE41E00E9411AEF7 -:1095D000EEEAFFE084918F01882339F00E946EAD9E -:1095E0000F5F1F4FF8018491F7CF60E070E0CB016F -:1095F0000E94F7ADECEAFFE084918F01882339F0F7 -:109600000E946EAD0F5F1F4FF8018491F7CF6091FC -:10961000DC0F7091DD0F8091DE0F9091DF0F41E044 -:109620000E9411AEE9EAFFE084918F01882339F0AE -:109630000E946EAD0F5F1F4FF8018491F7CF6091CC -:10964000891570918A15072E000C880B990B0F94C1 -:109650008EAE41E00E9411AEE5EAFFE084918F01F9 -:10966000882339F00E946EAD0F5F1F4FF80184917F -:10967000F7CFE981F0E0E45AF04F608170E080E0DC -:1096800090E00E94F7ADE0EAFFE084918F0188232B -:1096900039F00E946EAD0F5F1F4FF8018491F7CF34 -:1096A00060915B0F70E080E090E00E94F7ADECE924 -:1096B000FFE084918F01882339F00E946EAD0F5F27 -:1096C0001F4FF8018491F7CF6091A10E7091A20E07 -:1096D0008091A30E9091A40E41E00E9411AEE8E9A2 -:1096E000FFE084918F01882339F00E946EAD0F5FF7 -:1096F0001F4FF8018491F7CF60919D0E70919E0EDF -:1097000080919F0E9091A00E41E00E9411AE8AE0E0 -:109710000E946EAD81E090E090932302809322023C -:109720000C94EB6FBE016F5F7F4F8DE690E00F945E -:1097300036A381110C9468688DE69DE20F94EE517A -:1097400081E090E09093340E8093330E8091C80FA7 -:10975000882329F060E081E090E00F94BE0283E569 -:109760000F94909B882379F019810F94879B111196 -:1097700006C00F944EB570938A156093891581E0E9 -:109780008093040212C082E50F94909B882369F0B5 -:1097900019810F94879B111106C00F944EB57093D9 -:1097A0008A1560938915109204020F9425884B0145 -:1097B0005C01F9800F2D10E0F801EE0FFF1FE75755 -:1097C000FA4E60817181072E000C880B990B0F9463 -:1097D0008EAEF801EE0FFF1FEE0FFF1FE452F04FA9 -:1097E00011E020813181428153810F943AB61816DD -:1097F0000CF010E01093070F81E090E090932302AB -:109800008093220210925A0E4F2DC501B4010F947D -:109810006B118FE59DE20F94EE5182E090E0909302 -:109820002302809322029093340E8093330E809112 -:10983000C80F882329F060E082E090E00F94BE0218 -:109840000F9425886093FF0E7093000F8093010F93 -:109850009093020F0C94686883E59DE20F94EE519B -:1098600083E090E09093340E8093330E8091C80F84 -:10987000882329F060E081E090E00F94BE0283E548 -:109880000F94909B882361F00F94879B0F944EB5A3 -:109890007093030D6093020D81E0809304020FC06A -:1098A00082E50F94909B882351F00F94879B0F942F -:1098B0004EB57093030D6093020D109204020F9445 -:1098C00025884B015C0110925A0E6091020D709137 -:1098D000030D072E000C880B990B0F948EAE11E030 -:1098E000209108073091090740910A0750910B0712 -:1098F0000F943AB618160CF010E01093070F81E0A1 -:1099000090E0909323028093220205E91FE0B1E9E1 -:10991000EB2EBFE0FB2E8DE8C82E8FE0D82E809175 -:10992000070F6091020D7091030D8823B9F08091AB -:109930005A0E811113C0072E000C880B990B0F943F -:109940008EAE209108073091090740910A07509187 -:109950000B070F943AB61816BCF08BC0072E000CFC -:10996000880B990B0F948EAE209108073091090750 -:1099700040910A0750910B070F9488AE87FF79C07A -:1099800080910402811175C00F942588DC01CB0100 -:1099900088199909AA09BB09893E9340A105B10517 -:1099A00008F45EC08091C80F811156C0E091FE0C92 -:1099B00024E0E29FF0011124E452F04F40805180F6 -:1099C00062807380F8018491A5E9AA2EAFE0BA2ED7 -:1099D000882341F00E946EADFFEFAF1ABF0AF50178 -:1099E0008491F6CF42E0C301B2010E9411AEF701AB -:1099F0008491F1E9AF2EFFE0BF2E882341F00E9451 -:109A00006EADFFEFAF1ABF0AF5018491F6CF6091FA -:109A1000FE0C70E080E090E00E94F7ADF6018491CA -:109A2000EDE8AE2EEFE0BE2E882341F00E946EAD31 -:109A3000FFEFAF1ABF0AF5018491F6CF60910807D6 -:109A40007091090780910A0790910B0741E00E94ED -:109A500011AE8AE00E946EAD0F9425884B015C0127 -:109A60000F94BC7D80E00F94680E80E00F94932FDC -:109A700056CF8AE49DE20F94EE5182E090E09093FD -:109A800023028093220284E090E09093340E80932E -:109A9000330E0F9425886093FF0E7093000F809310 -:109AA000010F9093020F0C94686883E50F94909BCC -:109AB000882319F10F94879B20E030E0A9010F94CF -:109AC00088AE87FD0FC00F94879B20E030E04FE702 -:109AD00053E40F943AB6181644F00F94879B0F94F2 -:109AE0004EB505C060E070E002C06FEF70E07093AB -:109AF000BC196093BB190C9468688FEF90E0909349 -:109B0000BC198093BB190C9468681092BC19109210 -:109B1000BB190C9468680F94A63A0F949883149A12 -:109B20000F94F1831092BC191092BB1968EE73E088 -:109B300080E090E00F940D8789E094E00F94EE515F -:109B400080E00F94932F0C9468681092320F0C945D -:109B5000686883E50F94909B882399F00F94879B06 -:109B600020E030E04AE754E40F94F5A70F9454B591 -:109B700060937602709377028093780290937902D3 -:109B80001DC088E50F94909B81110C94C56B89E5ED -:109B90000F94909B81110C94C56B8AE50F94909B58 -:109BA00081110C94C56B85E40F94909B81110C94EA -:109BB000C56B0F949883149A0F94F1838FEF9FEFE6 -:109BC00090933E0280933D0290933C0280933B022F -:109BD00080933A02809339021092330F0C94686894 -:109BE00083E50F94909B882311F40C9468680F947C -:109BF000879B20E030E04AE754E40F94F5A70F94E8 -:109C000054B56093FB0E7093FC0E8093FD0E909301 -:109C1000FE0E0C94686883E50F94909B882311F4E2 -:109C20000C9468680F94879B20E030E04AE754E486 -:109C30000F94F5A70F9454B560937202709373025A -:109C4000809374029093750289E696E10E943EDD4E -:109C50000C94686829EF32E03BAF2AAF09E710E1C6 -:109C60007FE5C72E7DE0D72EF12CAAADBBAD8D913F -:109C7000BBAFAAAF0F94909B882309F463C0B3E0F5 -:109C8000FB1259C00F94879B2B013C0120E030E070 -:109C900040EA51E40F9488AE87FF45C0A3019201CA -:109CA000F80164817581868197810F94DDB44B0141 -:109CB0005C019B01AC016091CD107091CE10809140 -:109CC000CF109091D0100F94F5A76093CD107093A2 -:109CD000CE108093CF109093D01020902B02309014 -:109CE0002C02A5019401D1011C966D917D918D915D -:109CF0009C911F970F94F5A7F1016487758786875C -:109D00009787D6016D917D918D919C910F948CAE2A -:109D1000A50194010F94F5A70F9454B5F601608343 -:109D2000718382839383D80114964D925D926D92D4 -:109D30007C92179707C00F94879BF8016483758303 -:109D400086839783F3940C5F1F4FF4E0CF0ED11CF2 -:109D500064E0862EF81089CF0C9468688EE40F9426 -:109D6000909B882311F40C9468680F947C9B6093FB -:109D70002D0D70932E0D80932F0D9093300D0C941C -:109D8000686883E50F94909B882379F080912B0D70 -:109D900090912C0D4AE050E060E070E001960F9445 -:109DA0001DAA60934F020C946868E6E9FEE5849171 -:109DB0008F01882339F00E946EAD0F5F1F4FF801AD -:109DC0008491F7CFC0904F02D12CE12CF12CE6E822 -:109DD000FFE084918F01882339F00E946EAD0F5F00 -:109DE0001F4FF8018491F7CF4AE0C701B6010E94E6 -:109DF00086AD8AE00E946EAD0C94686886E50F948B -:109E0000909B882379F0E3ECFBE584918F01882314 -:109E100011F40C94F4450E946EAD0F5F1F4FF801D2 -:109E20008491F5CF85E50F94909B382E8823D9F146 -:109E3000E0902B0DF0902C0DFFEFEF1AFF0AF0923F -:109E40002C0DE0922B0D270167014601D6018D9163 -:109E50006D0190ED980F9A30C0F38E3211F00C9492 -:109E600068685D013501F50181915F0190ED980F02 -:109E70009A30C0F38E3211F00C946868CF018C01D7 -:109E8000DC012C90019620ED220D2A30C0F3822DAA -:109E90000F94C45181110C94E46BBDE22B120C940D -:109EA00068680C94E46BE8E6FFE084918F018823F6 -:109EB00039F00E946EAD0F5F1F4FF8018491F7CF0C -:109EC000E3ECFBE584918F01882339F00E946EADAD -:109ED0000F5F1F4FF8018491F7CFEEE0FFE0849110 -:109EE0008F01882339F00E946EAD0F5F1F4FF8017C -:109EF0008491F7CFEAE0FFE084918F01882339F065 -:109F00000E946EAD0F5F1F4FF8018491F7CFEBEF0A -:109F1000FEE084918F01882339F00E946EAD0F5FBF -:109F20001F4FF8018491F7CFEEEEFEE084918F0190 -:109F3000882339F00E946EAD0F5F1F4FF8018491A6 -:109F4000F7CFEDEDFEE084918F01882339F00E9478 -:109F50006EAD0F5F1F4FF8018491F7CFEBEDFEE080 -:109F600084918F01882339F00E946EAD0F5F1F4FDF -:109F7000F8018491F7CFE4EDFEE084918F0188230E -:109F800039F00E946EAD0F5F1F4FF8018491F7CF3B -:109F9000EFEAFEE084918F01882311F40C94F445DC -:109FA0000E946EAD0F5F1F4FF8018491F5CF88239B -:109FB00039F00E946EAD0F5F1F4FF8018491F7CF0B -:109FC0006091351070913610809137109091381053 -:109FD00042E00E9411AEEEE5FDE084918F018823FE -:109FE00039F00E946EAD0F5F1F4FF8018491F7CFDB -:109FF0006091391070913A1080913B1090913C1013 -:10A0000042E00E9411AEEAE5FDE084918F018823D1 -:10A0100039F00E946EAD0F5F1F4FF8018491F7CFAA -:10A0200060913D1070913E1080913F1090914010D2 -:10A0300042E00E9411AEE6E5FDE084918F018823A5 -:10A0400039F00E946EAD0F5F1F4FF8018491F7CF7A -:10A050006091411070914210809143109091441092 -:10A0600042E00E9411AEE6EBF5E084918F01882377 -:10A0700039F00E946EAD0F5F1F4FF8018491F7CF4A -:10A0800080E00F9477830F948EAE20917D103091F5 -:10A090007E1040917F10509180100F94DDB442E00B -:10A0A0000E9411AEE2E5FDE084918F01882339F032 -:10A0B0000E946EAD0F5F1F4FF8018491F7CF81E0D2 -:10A0C0000F9477830F948EAE20918110309182107F -:10A0D00040918310509184100F94DDB442E00E94AF -:10A0E00011AEEEE4FDE084918F01882339F00E94E7 -:10A0F0006EAD0F5F1F4FF8018491F7CF82E00F9490 -:10A1000077830F948EAE2091851030918610409108 -:10A110008710509188100F94DDB442E00E9411AE78 -:10A12000EAE4FDE084918F01882339F00E946EAD4E -:10A130000F5F1F4FF8018491F7CF83E00F9477836F -:10A140000F948EAE2091891030918A1040918B101F -:10A1500050918C100F94DDB442E00E9411AE8AE061 -:10A160000E946EAD0C94686881E0809321020C948B -:10A170006868E4E5F6E084918F01882339F00E9455 -:10A180006EAD0F5F1F4FF8018491F7CF8AE00E94F8 -:10A190006EADECE4F6E084918F01882339F00E94E3 -:10A1A0006EAD0F5F1F4FF8018491F7CF1E9B0DC05E -:10A1B000EEEFF2E184918F018823A1F00E946EAD51 -:10A1C0000F5F1F4FF8018491F7CFE9EFF2E184911F -:10A1D0008F01882339F00E946EAD0F5F1F4FF80189 -:10A1E0008491F7CF8AE00E946EADE4E4F6E08491BA -:10A1F0008F01882339F00E946EAD0F5F1F4FF80169 -:10A200008491F7CF8091060182FF0DC0EEEFF2E15D -:10A2100084918F018823A1F00E946EAD0F5F1F4FC4 -:10A22000F8018491F7CFE9EFF2E184918F0188235F -:10A2300039F00E946EAD0F5F1F4FF8018491F7CF88 -:10A240008AE00E946EADECE3F6E084918F018823F2 -:10A2500039F00E946EAD0F5F1F4FF8018491F7CF68 -:10A260001D9B0DC0EEEFF2E184918F018823A1F0D8 -:10A270000E946EAD0F5F1F4FF8018491F7CFE9EF99 -:10A28000F2E184918F01882339F00E946EAD0F5F57 -:10A290001F4FF8018491F7CF8AE00E946EADE4E38E -:10A2A000F6E084918F01882339F00E946EAD0F5F34 -:10A2B0001F4FF8018491F7CF8091060187FF0DC0F1 -:10A2C000EEEFF2E184918F018823A1F00E946EAD40 -:10A2D0000F5F1F4FF8018491F7CFE9EFF2E184910E -:10A2E0008F01882339F00E946EAD0F5F1F4FF80178 -:10A2F0008491F7CF8AE00E946EADECE2F6E08491A3 -:10A300008F01882339F00E946EAD0F5F1F4FF80157 -:10A310008491F7CF1C9B0DC0EEEFF2E184918F0189 -:10A320008823A1F00E946EAD0F5F1F4FF80184914A -:10A33000F7CFE9EFF2E184918F01882339F00E9491 -:10A340006EAD0F5F1F4FF8018491F7CF8AE00E9436 -:10A350006EADE4E2F6E084918F01882339F00E942B -:10A360006EAD0F5F1F4FF8018491F7CF01990FC0B9 -:10A37000EEEFF2E184918F01882311F40C94F445FF -:10A380000E946EAD0F5F1F4FF8018491F5CFE9EF8A -:10A39000F2E184918F01882311F40C94F4450E941A -:10A3A0006EAD0F5F1F4FF8018491F5CF1091FE0C39 -:10A3B00084E50F94909B882301F10F94879B0F9461 -:10A3C00054B5162F6623C9F0E6E9FEE584918F01A6 -:10A3D000882339F00E946EAD0F5F1F4FF801849102 -:10A3E000F7CF02EE12E1D8018D918D01882311F48F -:10A3F0000C9468680E946EADF6CF84E40F94909B35 -:10A40000882311F40C9468680F94879B20E030E057 -:10A41000A9010F9488AE811103C0109210112EC0B3 -:10A420000F94879BB4E01B9FF0011124EF5EFE4E5A -:10A430006083718382839383C0901111D090121135 -:10A44000E0901311F090141120E030E0A901C70151 -:10A45000B6010F9488AE811106C0C12CD12C50EEEC -:10A46000E52E5FE3F52EC0921111D0921211E09209 -:10A470001311F092141181E0809310110F94DA0CF3 -:10A480000C946868F70181917F010F94909B882359 -:10A49000A1F10F94879B0F9454B5F1E0FD15ACF03A -:10A4A000653C29E0720781059105A0F4562F472FDE -:10A4B000382F292F613CA3E07A078105910590F0A0 -:10A4C00050EC43E030E020E00DC0562F472F382FEE -:10A4D000292F08C050EC43E030E020E064EC79E044 -:10A4E00080E090E0F80164A375A386A397A3E455E8 -:10A4F000FF4F5083418332832383D3940C5F1F4FDC -:10A50000F4E0DF12BFCF0E9477BD0C94686829EF9A -:10A51000A22E22E0B22E39E7C32E30E1D32E912CA9 -:10A52000D5018D915D010F94909B882309F43EC065 -:10A530000F94879B7B018C01B1E0B91514F120E0E9 -:10A5400030E048E453E40F943AB618163CF4512C2A -:10A55000612C88E4782E93E4892E04C05E2C6F2C45 -:10A56000702E812E20E030E048EC52E4B701C801A3 -:10A570000F943AB618164CF4E12CF12C08EC12E4C6 -:10A5800004C0562E6F2C782E812E852D962DA72D4A -:10A59000B82DF601848B958BA68BB78BC701D8019C -:10A5A000E456FF4F80839183A283B3839394F4E0B6 -:10A5B000CF0ED11C14E0812E9810B2CF0C94686895 -:10A5C00083E50F94909B8823E9F00F94879B609319 -:10A5D000AD107093AE108093AF109093B01084E5DF -:10A5E0000F94909B882311F40C9468680F94879BB8 -:10A5F0006093B1107093B2108093B3109093B41025 -:10A600000C94686880E50F94909B882351F00F9418 -:10A61000879B6093AD107093AE108093AF109093B2 -:10A62000B01082E50F94909B882351F00F94879B84 -:10A630006093B1107093B2108093B3109093B410E4 -:10A6400084E50F94909B0C94686883E50F94909B2D -:10A65000882351F00F94879B6093B5107093B610C8 -:10A660008093B7109093B81084E50F94909B882343 -:10A6700051F00F94879B6093B9107093BA10809338 -:10A68000BB109093BC1082E40F94909B882361F0E0 -:10A690000F94879B0F9454B56093BD107093BE10B8 -:10A6A0008093BF109093C01088E50F94909B8823EF -:10A6B00091F00F94879B6093C5107093C6108093A0 -:10A6C000C7109093C8106093C1107093C21080930C -:10A6D000C3109093C41089E50F94909B882351F088 -:10A6E0000F94879B6093C5107093C6108093C7101A -:10A6F0009093C8108AE50F94909B882351F00F9493 -:10A70000879B6093C9107093CA108093CB1090936D -:10A71000CC1085E40F94909B882351F00F94879B75 -:10A720006093CD107093CE108093CF109093D01083 -:10A7300020E030E040E251E46091C1107091C2101D -:10A740008091C3109091C4100F943AB6181664F417 -:10A7500080E090E0A0E2B1E48093C1109093C21039 -:10A76000A093C310B093C41020E030E040E251E465 -:10A770006091C5107091C6108091C7109091C8105B -:10A780000F943AB6181614F00C94686880E090E0C4 -:10A79000A0E2B1E48093C5109093C610A093C710B7 -:10A7A000B093C8100C946868A9EFEA2EA2E0FA2EC4 -:10A7B00001ED10E1BDEDCB2EB0E1DB2ED7018D9187 -:10A7C0007D010F94909B882339F00F94879BF801AB -:10A7D00060837183828393830C5F1F4FC016D10601 -:10A7E00069F70C94686883E50F94909B882351F077 -:10A7F0000F94879B6093FC107093FD108093FE1064 -:10A800009093FF1086E40F94909B882381F00F941F -:10A81000879B20E030E040E752E40F94DDB4609382 -:10A8200000117093011180930211909303118AE536 -:10A830000F94909B882311F40C9468680F94879B65 -:10A840006093041170930511809306119093071182 -:10A850000C94686883E50F94909B882351F00F94C3 -:10A86000879B609308117093091180930A1190934C -:10A870000B1186E40F94909B882311F40C94686864 -:10A880000F94879B20E030E040E752E40F94DDB462 -:10A8900060930C1170930D1180930E1190930F1112 -:10A8A0000C94686883E50F94909B882311F40C94B2 -:10A8B00068680F94879B0F944EB56115710551F030 -:10A8C0006130710569F481E08093FB101092D90F1B -:10A8D0000C9468681092FB101092D90F0C94686861 -:10A8E000E6E9FEE584918F01882339F00E946EAD80 -:10A8F0000F5F1F4FF8018491F7CFE1E1F6E08491FB -:10A900008F01882339F00E946EAD0F5F1F4FF80151 -:10A910008491F7CF009187151091881503561C4E2E -:10A92000D8018D918D01882319F00E946EADF8CF6A -:10A93000EAEAFEE084918F01882311F40C94F44537 -:10A940000E946EAD0F5F1F4FF8018491F5CF83E534 -:10A950000F94909B882311F40C9468680F94879B44 -:10A960000F944EB570934402609343020C94686850 -:10A9700083E50F94909B882309F480CD0F94879BE7 -:10A980000F944EB56B017C0184E50F94909B882356 -:10A9900059F0BE016F5F7F4F8DED90E00F9436A3AD -:10A9A00081110C9468686ACDD0928302C0928202B1 -:10A9B00065CD80E50F94909B882311F40C94686812 -:10A9C0000F94879B0F944EB5D62E862F972F7C0120 -:10A9D00083E50F94909B882331F00F94879B0F940D -:10A9E0004EB58B0102C00FEF1FEFC8010196039710 -:10A9F00010F00C946868EBE8F2E083EC92E02191AF -:10AA00003191E216F30611F40C9468688E179F07D3 -:10AA1000B1F7F7FE02C00C9468680F949883FD2C80 -:10AA200060E08D2D0F940A860F3FFFEF1F0731F076 -:10AA30000130110571F401E010E00DC08D2D0F946F -:10AA4000C9A731E020E0892B09F030E0032F122F55 -:10AA500002C000E010E08F2D0F94C9A78017910766 -:10AA600011F40C9468680F94BC7D80E00F94680E1C -:10AA700080E00F94932FEFCF83E50F94909B882372 -:10AA800031F00F94879B0F944EB58B0102C00EE6F8 -:10AA900010E080E50F94909B882329F00F94879B0A -:10AAA0000F944EB502C068EE73E06B01770FEE08AD -:10AAB000FF081016110694F4809101079091020787 -:10AAC000029718F4C8010F94185EC701B6010F94DD -:10AAD0000D8784E50F94524D0C946868C701B60148 -:10AAE0000F940D870C94686880E50F94909B8823E1 -:10AAF00051F00F94879B6093E1107093E210809364 -:10AB0000E3109093E41089E40F94909B882381F0E4 -:10AB10000F94879B2CEA35EC47E25EE30F94F5A790 -:10AB20006093E5107093E6108093E7109093E8101F -:10AB300084E40F94909B882381F00F94879B2CEAE8 -:10AB400035EC47E25EE30F94DDB46093E910709357 -:10AB5000EA108093EB109093EC1083E40F94909B99 -:10AB6000882351F00F94879B609300027093010239 -:10AB700080930202909303020F944F82EDE5F7E178 -:10AB800084918F01882339F00E946EAD0F5F1F4FB3 -:10AB9000F8018491F7CF06E114E0D8018D918D0181 -:10ABA000882319F00E946EADF8CF6091E11070918A -:10ABB000E2108091E3109091E41042E00E9411AE07 -:10ABC0000AE114E0F80181918F01882319F00E94B5 -:10ABD0006EADF8CF2CEA35EC47E25EE36091E5100C -:10ABE0007091E6108091E7109091E8100F94DDB419 -:10ABF00042E00E9411AE0EE114E0D8018D918D016A -:10AC0000882319F00E946EADF8CF2CEA35EC47E2AC -:10AC10005EE36091E9107091EA108091EB109091E1 -:10AC2000EC100F94F5A742E00E9411AE02E214E08E -:10AC3000F80181918F01882319F00E946EADF8CF41 -:10AC400060910002709101028091020290910302D2 -:10AC500042E00E9411AE8AE00E946EAD0C946868DA -:10AC600080E50F94909B882351F00F94879B60930D -:10AC7000ED107093EE108093EF109093F01089E434 -:10AC80000F94909B882381F00F94879B2CEA35ECDE -:10AC900047E25EE30F94F5A76093F1107093F21012 -:10ACA0008093F3109093F41084E40F94909B882386 -:10ACB00081F00F94879B2CEA35EC47E25EE30F941A -:10ACC000DDB46093F5107093F6108093F7109093B5 -:10ACD000F8100F944F82EDE5F7E184918F018823FE -:10ACE00039F00E946EAD0F5F1F4FF8018491F7CFCE -:10ACF00006E114E0D8018D918D01882319F00E949E -:10AD00006EADF8CF6091ED107091EE108091EF1064 -:10AD10009091F01042E00E9411AE0AE114E0F801B7 -:10AD200081918F01882319F00E946EADF8CF2CEA33 -:10AD300035EC47E25EE36091F1107091F210809182 -:10AD4000F3109091F4100F94DDB442E00E9411AE24 -:10AD50000EE114E0D8018D918D01882319F00E9435 -:10AD60006EADF8CF2CEA35EC47E25EE36091F5106A -:10AD70007091F6108091F7109091F8100F94F5A74C -:10AD800042E00E9411AE8AE00E946EAD0C946868A9 -:10AD900083E50F94909B882319F00F94879B03C041 -:10ADA00060E070E0CB0160932402709325028093F1 -:10ADB0002602909327020C94686885E40F94909B78 -:10ADC000882359F00F94879B0F944EB524967FAF3C -:10ADD0006EAF249777FF05C013C024961FAE1EAE3A -:10ADE000249763961FAE639765961FAE659726E11D -:10ADF00067962FAF679733E468963FAF68970EC0AA -:10AE000063961FAE639765961FAE65974CE867968D -:10AE10004FAF679752E468965FAF689783E50F94EA -:10AE2000909B882371F00F94879B63966FAF639715 -:10AE300065967FAF659767968FAF679768969FAF68 -:10AE4000689783E40F94909B882349F00F94879B25 -:10AE50000F944EB5A6967FAF6EAFA69706C085E05D -:10AE600090E0A6969FAF8EAFA697A6968EAC9FACAD -:10AE7000A6979092300E80922F0E1092240F10926F -:10AE8000320E1092310E0F94258862966CAF7DAF12 -:10AE90008EAF9FAF62972496AEACBFAC2497B7FC41 -:10AEA00005C02AE0A7962FAFA79704C03DE2A7965A -:10AEB0003FAFA7970F942588E3966CAF7DAF8EAF19 -:10AEC0009FAFE39724968EAC9FAC24971814190477 -:10AED000B4F406E214E0D8018D918D01882319F0B5 -:10AEE0000E946EADF8CF8AE00E946EAD81E0809343 -:10AEF000240F1092320E1092310E0C94686800E507 -:10AF000014E0F80181918F01882319F00E946EAD41 -:10AF1000F8CF8AE00E946EAD0F94A63A24968EACCC -:10AF20009FAC24978FE7892809F451C080935B0F69 -:10AF300062968CAC9DACAEACBFAC62976C968CAE9E -:10AF40009DAEAEAEBFAE6C97AF968CAE9DAEAEAEC4 -:10AF5000BFAEAF972B961FAE2B976D961FAE6D971A -:10AF600020E46E962FAF6E973CE16F963FAF6F97E0 -:10AF700046E4A0964FAFA097A1961FAEA197A296C8 -:10AF80001FAEA297A3961FAEA397A4961FAEA49739 -:10AF9000EFE78E2E912CA12CB12C2A968CAE9DAE73 -:10AFA000AEAEBFAE2A97FFE74F2E512C612C712C0D -:10AFB000AB961CAE1DAE1EAE1FAEAB9721E0E89661 -:10AFC0002FAFE8971AAE1EAE212C312C06C080930D -:10AFD0005C0FAECF80E00F94932FA89580915D0F0A -:10AFE000882309F474C10F94CA4124968EAC9FAC97 -:10AFF0002497892859F49090DC0F9AAEA090DD0F29 -:10B00000AEAE2090DE0F3090DF0F0AC0B090080780 -:10B01000BAAE809009078EAE20900A0730900B07D9 -:10B020002AAD3EADA101A1966FADA197A2967FADCD -:10B03000A297A3968FADA397A4969FADA4970F94C4 -:10B040003AB6181674F09AACA1969FAEA197AEAC22 -:10B05000A296AFAEA297A3962FAEA397A4963FAEAB -:10B06000A4976D962FAD6D976E963FAD6E976F96C8 -:10B070004FAD6F97A0965FADA0976AAD7EADC10151 -:10B080000F943AB6181674F0BAAC6D96BFAE6D97C1 -:10B090008EAC6E968FAE6E976F962FAE6F97A09612 -:10B0A0003FAEA0970F942588DC01CB01E3968CACD2 -:10B0B0009DACAEACBFACE39788199909AA09BB094E -:10B0C000853C9940A105B10550F00F949A7D0F94ED -:10B0D0002588E3966CAF7DAF8EAF9FAFE397E89680 -:10B0E0008FACE897882009F474C02AAD3EADA10169 -:10B0F00063966FAD639765967FAD659767968FADE5 -:10B10000679768969FAD68970F9488AE87FFDFC0FA -:10B110000F942588DC01CB0162968CAC9DACAEAC63 -:10B12000BFAC629788199909AA09BB09893893416C -:10B13000A105B10508F4CBC0D301C2012A968CAC9D -:10B140009DACAEACBFAC2A9788199909AA09BB0976 -:10B150002496AEACBFAC2497B595A79597958795E7 -:10B16000AB2819F080935B0F02C080935C0F0F94A3 -:10B1700025886C966CAF7DAF8EAF9FAF6C974B01FF -:10B180005C0162962CAD3DAD4EAD5FAD6297821A0B -:10B19000930AA40AB50AAB968CAE9DAEAEAEBFAE16 -:10B1A000AB9763968FAC6397A1968FAEA197659688 -:10B1B0009FAC6597A2969FAEA2976796AFAC679734 -:10B1C000A396AFAEA3976896BFAC6897A496BFAEA0 -:10B1D000A4972AAD3EADA10163966FAD63976596C6 -:10B1E0007FAD659767968FAD679768969FAD6897B7 -:10B1F0000F943AB6181614F00C94D16E0F9425885B -:10B20000DC01CB016C968CAC9DACAEACBFAC6C974A -:10B2100088199909AA09BB0989389341A105B10583 -:10B2200010F40C94D16E0F94258862966CAF7DAFAC -:10B230008EAF9FAF6297DC01CB0188199909AA09EB -:10B24000BB092091310E3091320E1216130614F400 -:10B250000C94FC6C2A968CAD9DADAEADBFAD2A971B -:10B26000840D951DA61DB71D24968EAC9FAC24970A -:10B27000B595A79597958795892811F40C94CD6E6F -:10B2800080935B0F8091310E9091320E01969093D6 -:10B29000320E8093310E63969FAC63976D969FAE8E -:10B2A0006D976596AFAC65976E96AFAE6E976796E5 -:10B2B000BFAC67976F96BFAE6F9768968FAC689775 -:10B2C000A0968FAEA09721E0E8962FAFE89720E0F8 -:10B2D00030E040EA51E463966FAD639765967FADC9 -:10B2E000659767968FAD679768969FAD68970F943F -:10B2F000EFB32AAD3EADA1010F9488AE87FF0EC01B -:10B30000E9EDFCE084918F01882309F4ECCD0E94E3 -:10B310006EAD0F5F1F4FF8018491F6CF0F94258813 -:10B32000DC01CB01AF968CAC9DACAEACBFACAF97A3 -:10B3300088199909AA09BB09813D9740A105B10562 -:10B3400008F4B4C024968EAC9FAC2497892881F071 -:10B35000E0905B0FF12CE6EDFCE084918F018823F7 -:10B36000B9F00E946EAD0F5F1F4FF8018491F7CFC7 -:10B37000E0905C0FF12CE3EDFCE084918F018823D9 -:10B3800039F00E946EAD0F5F1F4FF8018491F7CF27 -:10B3900042E06AAD7EADC1010E9411AEEFECFCE06F -:10B3A00084918F01882339F00E946EAD0F5F1F4F8B -:10B3B000F8018491F7CFB701FF0C880B990B0E941D -:10B3C000F7AD8AE00E946EAD2B968FAC2B9788204C -:10B3D00009F452C0A7969FACA797891418F4282D9A -:10B3E0002F5F59C02B968FAC2B97A7969FACA79732 -:10B3F000891054C0282D2F5F2B962FAF2B97E496E2 -:10B400002FADE497E5963FADE597E6964FADE6970D -:10B41000E7965FADE7976AAD7EADC1010F94EEB3DD -:10B420006B017C0120E030E0A9010F943AB61816B8 -:10B430005CF420E030E040EA50E4C701B6010F942C -:10B4400088AE87FF2BC00AC020E030E040EA50EC15 -:10B45000C701B6010F943AB6181604F524966FADDD -:10B460002497661F6627661F80E00F94D93D81E010 -:10B470008093240F0C9468688AACE4968FAEE497AE -:10B480009EACE5969FAEE597E6962FAEE697E796DB -:10B490003FAEE79721E02B962FAF2B970F9425888F -:10B4A000AF966CAF7DAF8EAF9FAFAF970F942588EF -:10B4B0006B017C010F9425886C960CAD1DAD2EADF3 -:10B4C0003FAD6C9762968CAC9DACAEACBFAC629756 -:10B4D000080D191D2A1D3B1DC01AD10AE20AF30AE4 -:10B4E000DC01CB018C0D9D1DAE1DBF1D81389F441D -:10B4F000A241B10570F0E2EBFCE084918F0188235A -:10B5000009F4F1CC0E946EAD0F5F1F4FF8018491DA -:10B51000F6CF8091310E9091320EA6968EAC9FACF4 -:10B52000A697881699060CF055CDE6E5FCE08491C7 -:10B530008F01882309F4D7CC0E946EAD0F5F1F4F97 -:10B54000F8018491F6CF0F9498830C9468688091E9 -:10B550007B13882311F40C94686885E40F94909B06 -:10B56000882331F00F94879B0F9454B5162F01C098 -:10B570001FEF86E40F94909B882331F00F94879BF4 -:10B580000F9454B5062F01C00FEF1F920F931F9217 -:10B590001F9385E49CE09F938F930F9493AD1F922C -:10B5A0000F931F921F938BEB9BE59F938F930F94A9 -:10B5B000E1A60FB6F894DEBF0FBECDBF1AE00F9420 -:10B5C0006E26181614F40C946868115011F00C943F -:10B5D000D66E0C9468680E9420AF0C9468680E9434 -:10B5E000EAAE0C9468688091DC108F938091DB1038 -:10B5F0008F938091DA108F938091D9108F938091DF -:10B60000D8108F938091D7108F938091D6108F93FD -:10B610008091D5108F938091D4108F938091D31007 -:10B620008F938091D2108F938091D1108F9306E9E0 -:10B630001EE51F930F931F930F938091D0108F934C -:10B640008091CF108F938091CE108F938091CD10E9 -:10B650008F938091CC108F938091CB108F9380919A -:10B66000CA108F938091C9108F938091C8108F93C7 -:10B670008091C7108F938091C6108F938091C510D1 -:10B680008F938091C4108F938091C3108F9380917A -:10B69000C2108F938091C1108F938091C0108F93AF -:10B6A0008091BF108F938091BE108F938091BD10B9 -:10B6B0008F938091BC108F938091BB108F9380915A -:10B6C000BA108F938091B9108F938091B8108F9397 -:10B6D0008091B7108F938091B6108F938091B510A1 -:10B6E0008F931F930F931F930F938091B4108F9399 -:10B6F0008091B3108F938091B2108F938091B1108D -:10B700008F938091B0108F938091AF108F93809121 -:10B71000AE108F938091AD108F931F930F931F9353 -:10B720000F93809134118F93809133118F93809177 -:10B7300032118F93809131118F93809130118F93BB -:10B7400080912F118F9380912E118F9380912D11C5 -:10B750008F9380912C118F9380912B118F938091D7 -:10B760002A118F93809129118F93809128118F93A3 -:10B77000809127118F93809126118F9380912511AD -:10B780008F931F930F931F930F938091AC108F9300 -:10B790008091AB108F938091AA108F938091A91004 -:10B7A0008F938091A8108F938091A7108F93809191 -:10B7B000A6108F938091A5108F938091A4108F93E2 -:10B7C0008091A3108F938091A2108F938091A110EC -:10B7D0008F938091A0108F9380919F108F93809171 -:10B7E0009E108F9380919D108F931F930F931F93A3 -:10B7F0000F93809124118F93809123118F938091C7 -:10B8000022118F93809121118F93809120118F931A -:10B8100080911F118F9380911E118F9380911D1124 -:10B820008F9380911C118F9380911B118F93809126 -:10B830001A118F93809119118F93809118118F9302 -:10B84000809117118F93809116118F93809115110C -:10B850008F931F930F931F930F9380919C108F933F -:10B8600080919B108F9380919A108F938091991063 -:10B870008F93809198108F93809197108F938091E0 -:10B8800096108F93809195108F93809194108F9341 -:10B89000809193108F93809192108F93809191104B -:10B8A0008F93809190108F9380918F108F938091C0 -:10B8B0008E108F9380918D108F931F930F931F93F2 -:10B8C0000F9380918C108F9380918B108F93809128 -:10B8D0008A108F93809189108F93809188108F9315 -:10B8E000809187108F93809186108F93809185101F -:10B8F0008F93809184108F93809183108F93809188 -:10B9000082108F93809181108F93809180108F93FC -:10B9100080917F108F9380917E108F9380917D1006 -:10B920008F931F930F931F930F9385E999E09F9334 -:10B930008F930F9493AD0FB6F894DEBF0FBECDBFBB -:10B940002CEA35EC47E25EE36091E9107091EA1071 -:10B950008091EB109091EC100F94F5A79F938F932B -:10B960007F936F932CEA35EC47E25EE36091E5103C -:10B970007091E6108091E7109091E8100F94DDB47B -:10B980009F938F937F936F938091E4108F93809117 -:10B99000E3108F938091E2108F938091E1108F9349 -:10B9A0001F930F931F930F9388E699E09F938F93B4 -:10B9B0000F9493AD2CEA35EC47E25EE36091F5100D -:10B9C0007091F6108091F7109091F8100F94F5A7F0 -:10B9D0009F938F937F936F932CEA35EC47E25EE35E -:10B9E0006091F1107091F2108091F3109091F41029 -:10B9F0000F94DDB49F938F937F936F938091F0109A -:10BA00008F938091EF108F938091EE108F938091A0 -:10BA1000ED108F931F930F931F930F9383E399E080 -:10BA20009F938F930F9493AD0FB6F894DEBF0FBE24 -:10BA3000CDBF8091FB101F928F931F930F931F9385 -:10BA40000F9320E030E040E752E460910C117091D8 -:10BA50000D1180910E1190910F110F94F5A79F93E6 -:10BA60008F937F936F9380910B118F9380910A1125 -:10BA70008F93809109118F93809108118F931F9359 -:10BA80000F931F930F93809107118F93809106114D -:10BA90008F93809105118F93809104118F9320E0F3 -:10BAA00030E040E752E46091001170910111809103 -:10BAB0000211909103110F94F5A79F938F937F9399 -:10BAC0006F938091FF108F938091FE108F938091E0 -:10BAD000FD108F938091FC108F931F930F931F93F2 -:10BAE0000F9382E398E09F938F930F9493AD0FB6DB -:10BAF000F894DEBF0FBECDBF809110118823E9F00E -:10BB0000809114118F93809113118F938091121152 -:10BB10008F93809111118F931F930F931F930F9306 -:10BB20008CE098E09F938F930F9493AD0FB6F894A9 -:10BB3000DEBF0FBECDBF0C9468681F930F938DEED0 -:10BB400097E09F938F930F9493AD0F900F900F906A -:10BB50000F900C946868E6E9FEE584918F018823D4 -:10BB600039F00E946EAD0F5F1F4FF8018491F7CF3F -:10BB7000EAE9FEE084918F01882311F40C9468684F -:10BB80000E946EAD0F5F1F4FF8018491F5CF8AE5DB -:10BB90000F94909B882309F489C00F94879B6B01B5 -:10BBA0007C0120E030E040E751EC0F943AB687FD8D -:10BBB00038C020E030E040EA50ECC701B6010F94F5 -:10BBC00088AE181674F1F7FAF094F7F8F094C09272 -:10BBD000DD10D092DE10E092DF10F092E010E6E986 -:10BBE000FEE584918F01882339F00E946EAD0F5FCE -:10BBF0001F4FF8018491F7CFE8E0F6E084918F01C0 -:10BC0000882339F00E946EAD0F5F1F4FF8018491B9 -:10BC1000F7CF8AE00E946EAD8AE00E946EAD0C9470 -:10BC20006868E6E9FEE584918F01882339F00E9477 -:10BC30006EAD0F5F1F4FF8018491F7CFE8E0F6E09B -:10BC400084918F01882339F00E946EAD0F5F1F4FE2 -:10BC5000F8018491F7CFECE2F6E084918F0188231C -:10BC600039F00E946EAD0F5F1F4FF8018491F7CF3E -:10BC700061EF7FEF8FEF9FEF0E94F7ADE4E2F6E018 -:10BC800084918F01882339F00E946EAD0F5F1F4FA2 -:10BC9000F8018491F7CF6BEF7FEF8FEF9FEF0E945A -:10BCA000F7AD8AE00E946EAD0C946868E6E9FEE5A7 -:10BCB00084918F01882339F00E946EAD0F5F1F4F72 -:10BCC000F8018491F7CFE8E0F6E084918F018823B2 -:10BCD00039F00E946EAD0F5F1F4FF8018491F7CFCE -:10BCE0008AE00E946EAD8091DD109091DE10A091EF -:10BCF000DF10B091E010BC01CD01905842E00E94ED -:10BD000011AE8AE00E946EAD0C9468680F9498831F -:10BD100085E40F94909B882329F00F94879B6B01F7 -:10BD20007C0105C0C12CD12CE12C00ECF02E8CE460 -:10BD30000F94909B81110F94879B8AE50F94909BA1 -:10BD4000882329F00F94879B2B013C011CC020E025 -:10BD500030E048EC51E460913D1070913E108091CC -:10BD60003F10909140100F9488AE87FF07C0412C80 -:10BD7000512C18ED612E11E4712E05C0412C512C6F -:10BD8000612CB0E47B2E88E50F94909B882339F0DA -:10BD90000F94879B6AAF7BAF8CAF9DAF0AC0812C9D -:10BDA000912CA3E5AA2EA3E4BA2E8AAE9BAEACAE2C -:10BDB000BDAE89E50F94909B882349F00F94879B33 -:10BDC00022966CAF7DAF8EAF9FAF229706C02296B2 -:10BDD0001CAE1DAE1EAE1FAE229780917B13882332 -:10BDE00011F40C94DC6E83E694E00E94A9A78823EA -:10BDF00011F40C94DC6E332433940F9498831092D6 -:10BE00002E0F8091C80F882329F060E086E190E032 -:10BE10000F94BE02909043022F969FAE2F972090D2 -:10BE20004402E091FE0CF0E0EE0FFF1FE757FA4EE0 -:10BE3000A080B1806496BFAEAEAE64972091BB196E -:10BE40003091BC1966963FAF2EAF66978091351042 -:10BE500090913610A0913710B091381026968CAF83 -:10BE60009DAFAEAFBFAF269789839A83AB83BC8368 -:10BE70008090391090903A10A0903B10B0903C10F8 -:10BE80002A968CAE9DAEAEAEBFAE2A978D829E82B4 -:10BE9000AF82B88620913D1030913E1040913F1006 -:10BEA000509140102E962CAF3DAF4EAF5FAF2E9706 -:10BEB00029873A874B875C87209141103091421047 -:10BEC00040914310509144102D873E874F87588BE7 -:10BED000C701B6010F94EFB3609341107093421005 -:10BEE00080934310909344104EEF5CE05F934F9328 -:10BEF000812C912C68EEA62E62E4B62E71E4C72E3A -:10BF000070E1D72E2E96ECACFDAC0EAD1FAD2E978A -:10BF10002A962CAD3DAD4EAD5FAD2A9726966CAD01 -:10BF20007DAD8EAD9FAD26970E9451870F9498836B -:10BF300020913D1030913E1040913F1050914010A3 -:10BF4000C301B2010F94EFB37B018C0160933D10EC -:10BF500070933E1080933F109093401020913910C1 -:10BF600030913A1040913B1050913C106091351047 -:10BF7000709136108091371090913810AEEFBCE080 -:10BF8000BF93AF93812C912CE0E7AE2EE1E4BE2E5F -:10BF90000E9451870F9498838AAC9BACACACBDAC2B -:10BFA0008092351090923610A0923710B0923810CF -:10BFB00022962CAD3DAD4EAD5FAD2297209339104A -:10BFC00030933A1040933B1050933C10E0903D105A -:10BFD000F0903E1000913F10109140104EEF5CE049 -:10BFE0005F934F93812C912CF8E4AF2EF2E4BF2E97 -:10BFF00022962CAD3DAD4EAD5FAD22976AAD7BADC7 -:10C000008CAD9DAD0E9451870F9498830F900F9037 -:10C010000F900F900F900F9080917B13811124C08F -:10C0200084E090E090932302809322020F9425886D -:10C030004B015C0180E091E10F949307CC24C39401 -:10C04000D12CE12CF12CD1100C94206F0F946B307B -:10C05000882311F40C94206F9FB7F894809102010B -:10C060008B7F809302019FBF1092B60680917B1355 -:10C07000882319F00F94B02502C00E94DCD40F94DD -:10C08000988380917B13811160C084E090E090934D -:10C0900023028093220241E060E089E192E10F9463 -:10C0A000A0078093B60681114BC00F941D3762E044 -:10C0B00080E00F946E3286E799E40F94953120E08A -:10C0C00030E048EC52E46091351070913610809168 -:10C0D0003710909138100F94EEB360933510709331 -:10C0E00036108093371090933810E0903D10F09008 -:10C0F0003E1000913F101091401020913910309166 -:10C100003A1040913B1050913C10EEEFFCE0FF9351 -:10C11000EF93812C912CE8E4AE2EE2E4BE2EF1E404 -:10C12000CF2EF0E1DF2E0E9451870F94988389EE85 -:10C1300091E10F94410881E00F9427370F900F9001 -:10C1400080917B13882309F477C0311071C08091EE -:10C150003F0E882329F060E080912D0E0F94752406 -:10C1600084E090E0909323028093220289E291E19F -:10C170000F949307FF24F39400E010E00F946B30CA -:10C18000811139C00F94BC7D81E00F94680E043F8B -:10C1900041E0140711F400E010E080910101846097 -:10C1A0008093010101151105A1F48091010790917F -:10C1B0000207009721F00197B9F4FF20A9F09FB77B -:10C1C000F894809102018460809302019FBFF12C5A -:10C1D0000BC00431110541F49FB7F894809102011E -:10C1E0008B7F809302019FBF0F5F1F4F84E090E021 -:10C1F0000F94BD12C3CF9FB7F894809102018B7F3B -:10C20000809302019FBF80913F0E882389F00F9495 -:10C210001D3762E080E00F946E3286E799E40F9458 -:10C22000953180E60F946A2460E080E00F945B21F2 -:10C23000832D0F94A3A456C00F941D3761E080E0B6 -:10C240000F946E3282E891E10F94953162E080E0C4 -:10C250000F946E328FE691E10F94953184E090E077 -:10C2600090932302809322020E946E9D0F946B3064 -:10C2700081111AC00F94BC7D81E00F94680E0E945A -:10C28000B99D882399F38091010790910207029745 -:10C2900020F488EE93E00F94185E82E390E00F9410 -:10C2A000BD1284E50F94524D0E940C9C82E090E0F8 -:10C2B00090932302809322020F94EF9B80910107B9 -:10C2C00090910207029720F484EF91E00F94185E9A -:10C2D00082E390E00F94BD1284E50F94524D80E00C -:10C2E0000F9427373110F1C01092B606A4E0CA2E81 -:10C2F000D12CB2E0AB2EB12C8091B606813009F47E -:10C30000E4C01092B606D0922302C09222020F948B -:10C310001D3760E080E00F946E3288EB91E10F945E -:10C32000953161E081E00F946E328FEB9FE20F94C4 -:10C33000953162E081E00F946E3284EA91E10F94CE -:10C34000953163E081E00F946E3282E991E10F94C0 -:10C35000953161E080E00F946E3288E694E00F94AE -:10C360001031E090BD190E2C000CFF0801E010E028 -:10C370008091B606811168C00F94BC7D81E00F9456 -:10C38000680E8091BD19082E000C990B9701281B8F -:10C39000390B37FF03C0319521953109253031051F -:10C3A0000CF444C08E159F0514F401501109E816D1 -:10C3B000F90634F40F5F1F4F0430110564F009C013 -:10C3C0000430110534F40115110529F401E010E0E1 -:10C3D00002C003E010E061E080E00F946E3289E576 -:10C3E00096E00F94103162E080E00F946E3289E5A0 -:10C3F00096E00F94103163E080E00F946E3289E58F -:10C4000096E00F941031602F80E00F946E3288E632 -:10C4100094E00F941031E090BD190E2C000CFF0831 -:10C4200064E670E080E090E00F940D870F946B302D -:10C43000882309F49DCF0093B60664EF71E080E095 -:10C4400090E00F940D8794CF0F941D370F94388A86 -:10C45000B0922302A09222028091B6068230F9F0B7 -:10C46000833041F50F9498830E946EEA0F941D3734 -:10C4700060E080E00F946E328BEC91E10F94953187 -:10C4800062E080E00F946E3286E799E40F94953174 -:10C4900087E99DE10F944E9C0F9498832DCF809156 -:10C4A0007B13882321F080E00F94A3A425CF0F9461 -:10C4B000EF9B22CF0F941D3762E080E00F946E3225 -:10C4C00089ED91E10F94953117CF81E00F942737D3 -:10C4D00066968EAD9FAD66979093BC198093BB19FD -:10C4E00031103FC020E030E040EA50E4609141105C -:10C4F0007091421080914310909144100F94EFB3CB -:10C5000060934110709342108093431090934410B5 -:10C51000E0903D10F0903E1000913F1010914010BF -:10C520002091391030913A1040913B1050913C10BD -:10C5300060913510709136108091371090913810BD -:10C54000EEEFFCE0FF93EF93812C912CA12CE0E423 -:10C55000BE2EF1E4CF2EF0E1DF2E0E9451870F9026 -:10C560000F90E0903D10F0903E1000913F10109120 -:10C5700040102D813E814F81588569817A818B8160 -:10C580009C81EEEF6E2EECE07E2E7F926F92812CDE -:10C59000912CF8E4AF2EF2E4BF2EA1E4CA2EA0E164 -:10C5A000DA2E0E9451870F949883E984FA840B85D0 -:10C5B0001C852D813E814F81588569817A818B81CF -:10C5C0009C817F926F92812C912CB0E7AB2EB1E4CD -:10C5D000BB2E0E9451870F949883CE010D960E9426 -:10C5E000D5BD80E1FE013196A5E3B0E101900D9249 -:10C5F0008A95E1F780E1E5E3F0E1A9ECBFE0019085 -:10C600000D928A95E1F72F969FAD2F979093430255 -:10C61000209244022F929F9384EE97E09F938F93F2 -:10C620008E01015E1F4F1F930F930F94ECAD60E0DE -:10C63000C8010E9465DB8FEB94E10F94EE511092DC -:10C64000410E1092400E0FB6F894DEBF0FBECDBF64 -:10C650003FC50E9478CE3CC583E50F94909B88230C -:10C6600009F436C50F94879B0F944EB56B017C017E -:10C670002B0186E799E40F94EE51E7E7FEE0849101 -:10C680008F01882339F00E946EAD0F5F1F4FF801B4 -:10C690008491F7CF0D2C000CEE08FF08C701B601FE -:10C6A0000E94F7AD8AE00E946EAD0F9425884B0181 -:10C6B0005C0110925A0E6091020D7091030D072ECD -:10C6C000000C880B990B0F948EAE20E030E0A9018E -:10C6D0000F9488AE811111C06091891570918A15EF -:10C6E000072E000C880B990B0F948EAE11E020E002 -:10C6F00030E0A9010F9488AE811110E0052C000CE8 -:10C700006608770882E7282E8EE0382E111115C0B2 -:10C7100080915A0E81116CC0C301B2010F948EAE8C -:10C720002091A10E3091A20E4091A30E5091A40E23 -:10C730000F943AB618168CF05BC0C301B2010F9487 -:10C740008EAE2091A10E3091A20E4091A30E509179 -:10C75000A40E0F9488AE87FF4BC00F942588DC0190 -:10C76000CB0188199909AA09BB09893E9340A10503 -:10C77000B10508F434C0E4E7FEE084915F0188234A -:10C7800041F00E946EADFFEFAF1ABF0AF501849130 -:10C79000F6CF6091A10E7091A20E8091A30E9091A0 -:10C7A000A40E41E00E9411AEF101849102E7A02E97 -:10C7B0000EE0B02E882341F00E946EADFFEFAF1A5D -:10C7C000BF0AF5018491F6CFC701B6010E94F7AD0B -:10C7D0008AE00E946EAD0F9425884B015C010F9496 -:10C7E000BC7D80E00F94680E80E00F94932F8ECF75 -:10C7F0008DE597E10F94EE516BC48FE30F94909BFE -:10C80000882309F4BCC00E9490A91A821982882347 -:10C8100081F00AE614E0D8018D918D01882319F08A -:10C820000E946EADF8CF8AE00E946EAD0EE714E074 -:10C830000AC005E914E0F80181918F01882399F37A -:10C840000E946EADF8CFD8018D918D01882319F02B -:10C850000E946EADF8CF8AE00E946EAD88248A9463 -:10C86000982C5401A3E24A2E512C612C712CB0EB70 -:10C870002B2EBFE03B2E1AAE69817A81072E000C69 -:10C88000880B990B0F948EAE2091851030918610F5 -:10C8900040918710509188100F94DDB46B017C019A -:10C8A0002AAD21110DC0EEE6FEE084918F018823B0 -:10C8B00059F00E946EAD0F5F1F4FF8018491F7CFC2 -:10C8C000C501B4010E94F7ADEBE6FEE084918F0153 -:10C8D000882339F00E946EAD0F5F1F4FF8018491DD -:10C8E000F7CFC301B2010E94F7ADE8E6FEE0849104 -:10C8F0008F01882339F00E946EAD0F5F1F4FF80142 -:10C900008491F7CF69817A81072E000C880B990BEF -:10C910000E94F7ADE5E6FEE084918F01882339F0AF -:10C920000E946EAD0F5F1F4FF8018491F7CF20E09A -:10C9300030E04AE754E4C701B6010F94F5A742E09E -:10C940000E9411AE8AE00E946EADFAADFF5FFAAFB1 -:10C95000F63009F4BDC3BE016F5F7F4FC1010E9475 -:10C960009EFDB2E02B0E311CE5E04E0E511C611C09 -:10C97000711CFFEF8F1A9F0AAF0ABF0A7DCF81E2B9 -:10C980000F94909B882309F44AC061E086EA9FE0F7 -:10C990000F9493B388E090E09A838983BE016F5F20 -:10C9A0007F4F80EB9FE00E94B8FD88E190E09A8382 -:10C9B0008983BE016F5F7F4F82EB9FE00E94B8FDCD -:10C9C00080E390E09A838983BE016F5F7F4F84EBA1 -:10C9D0009FE00E94B8FD80E590E09A838983BE01C4 -:10C9E0006F5F7F4F86EB9FE00E94B8FD88E790E085 -:10C9F0009A838983BE016F5F7F4F88EB9FE00E941F -:10CA0000B8FD09EA14E0D8018D918D01882319F051 -:10CA10000E946EADF8CF8AE00E946EAD59C38AE5E0 -:10CA20000F94909B882319F161E086EA9FE00F94B0 -:10CA300093B31A82198200EB1FE0BE016F5F7F4F34 -:10CA4000C8010E94B8FD0E5F1F4F0A3BBFE01B07E5 -:10CA5000A1F70AEB14E0F80181918F01882319F006 -:10CA60000E946EADF8CF8AE00E946EAD31C383E5BF -:10CA70000F94909B882309F4CEC00F94879B0F944A -:10CA80004EB57A83698389E40F94909B882309F4D7 -:10CA90001FC30F94879B0F9454B5653008F018C3DB -:10CAA000862F90E08852984FBE016F5F7F4F880FAE -:10CAB000991F0E94B8FD04EC14E0D8018D918D01FE -:10CAC000882319F00E946EADF8CF8AE00E946EAD07 -:10CAD0000EE714E0F80181918F01882319F00E947C -:10CAE0006EADF8CF8AE00E946EAD3EEA232E3FE0A5 -:10CAF000332E44244A94542C320153E2852E912C37 -:10CB0000A12CB12C1AAE1A821982FAADFF2331F092 -:10CB1000BE016F5F7F4FC1010E949EFD69817A81D6 -:10CB2000072E000C880B990B0F948EAE2091851068 -:10CB30003091861040918710509188100F94DDB489 -:10CB40006B017C012AAD21110DC0E1E6FEE084916C -:10CB50008F01882359F00E946EAD0F5F1F4FF801BF -:10CB60008491F7CFC301B2010E94F7ADEEE5FEE07C -:10CB700084918F01882339F00E946EAD0F5F1F4FA3 -:10CB8000F8018491F7CFC501B4010E94F7ADEBE540 -:10CB9000FEE084918F01882339F00E946EAD0F5F13 -:10CBA0001F4FF8018491F7CF69817A81072E000C1D -:10CBB000880B990B0E94F7ADE8E5FEE084918F01A8 -:10CBC000882339F00E946EAD0F5F1F4FF8018491EA -:10CBD000F7CF20E030E04AE754E4C701B6010F94F4 -:10CBE000F5A742E00E9411AE8AE00E946EADFAAD58 -:10CBF000FF5FFAAF25E0820E911CA11CB11C3FEF34 -:10CC0000431A530A630A730A42E0240E311CF630B9 -:10CC100009F079CF5DC2E7E4FEE084918F018823BB -:10CC200009F456C20E946EAD0F5F1F4FF801849148 -:10CC3000F6CF0F9498838BE40F94909B882399F000 -:10CC40000F94519B6B017C0120E030E0A9010F940F -:10CC50003AB687FD08C0C092180DD092190DE09227 -:10CC60001A0DF0921B0D82E50F94909B882361F0C2 -:10CC70000F94519B6B017C0120E030E0A9010F94DF -:10CC800088AE87FF89C006C0C12CD12C20E8E22ED7 -:10CC90002FEBF22E84E40F94909B882329F00F94BD -:10CCA000519B4B015C0106C0812C912C90E8A92E70 -:10CCB0009FEBB92E87E50F94909B882329F00F9462 -:10CCC000519B2B013C0106C0412C512C80E8682E61 -:10CCD0008FEB782E88E40F94909B882339F00F9483 -:10CCE000519B6AAF7BAF8CAF9DAF08C020E030E0B6 -:10CCF00040E85FEB2AAF3BAF4CAF5DAF20E030E0E8 -:10CD0000A901C501B4010F943AB687FD45C020E0E2 -:10CD100030E0A901C301B2010F943AB687FD3CC0CF -:10CD200020E030E0A9016AAD7BAD8CAD9DAD0F94E4 -:10CD30003AB687FD31C020E030E0A901C501B40159 -:10CD40000F9488AE882391F120E030E040E05FE36B -:10CD5000C501B4010F94F5A76B017C012AAD3BAD71 -:10CD60004CAD5DADC301B2010F94F5A74B015C0161 -:10CD7000A7019601C701B6010F94F5A72BED3FE07F -:10CD800049E450E40F94F5A79B01AC01C501B4013F -:10CD90000F94DDB46B017C0120E030E0A901C701F4 -:10CDA000B6010F943AB687FF04C00BC0C12CD12C3A -:10CDB0007601C092140DD092150DE092160DF092EE -:10CDC000170DE6E9FEE584918F01882339F00E9472 -:10CDD0006EAD0F5F1F4FF8018491F7CFE9EDF7E0DB -:10CDE00084918F01882339F00E946EAD0F5F1F4F31 -:10CDF000F8018491F7CF6091180D7091190D809111 -:10CE00001A0D90911B0D42E00E9411AE8AE00E9423 -:10CE10006EADE3EDF7E084918F01882339F00E9435 -:10CE20006EAD0F5F1F4FF8018491F7CFC090140DC6 -:10CE3000D090150DE090160DF090170D20E030E029 -:10CE4000A901C701B6010F9488AE882349F042E0DA -:10CE5000C701B6010E9411AE8AE00E946EAD38C1D2 -:10CE6000EEECF7E084918F01882311F40C94F445E3 -:10CE70000E946EAD0F5F1F4FF8018491F5CF0F94A4 -:10CE80007C9B0F948EAE6B017C0120E030E0A90109 -:10CE90000F9488AE87FD40C020E030EA40E854E4BB -:10CEA000C701B6010F943AB6181674F120E030E0CD -:10CEB00047E054E4C701B6010F943AB687FD2FC08E -:10CEC00020E030E04CE752E4C701B6010F94F5A72B -:10CED00020E030EA40E854E40F94DDB40F9454B5F8 -:10CEE000162F802F0F94BF9B612F802F0F94AE9B26 -:10CEF0000F5F043009F4ECC0D5018D915D010F94F2 -:10CF0000909B8823A9F3BBCFC12C10EAD12E10E847 -:10CF1000E12E14E4F12ED4CFC12CD12C760120E0E7 -:10CF200030E04CE752E4C701B6010F94F5A720E0CA -:10CF300034EB40E954E4D0CF85E40F94909B8823F0 -:10CF400009F4C6C00F94879B0F9454B56B017C0104 -:10CF50008B016830710569F06031710551F0603204 -:10CF6000710539F06034710521F06038710509F000 -:10CF7000AFC00F94988380E091E05C0100901307AC -:10CF800002C0B694A7940A94E2F7C6010E94BEC6F6 -:10CF90008093130720911C0240912002682F83E0A8 -:10CFA0000E94E1C640907510509076106090771006 -:10CFB00070907810A016B10670F5C801B5010F94F5 -:10CFC0008DB86B01E12CF12CC701B6010F948CAE2A -:10CFD0009B01AC016091891070918A1080918B1037 -:10CFE00090918C100F94F5A76093891070938A101C -:10CFF00080938B1090938C10A3019201C701B6010E -:10D000000F94A4B36093751070937610809377108B -:10D01000909378105DC0C501B8010F948DB86B0175 -:10D02000E12CF12CC701B6010F948CAE9B01AC0131 -:10D030006091891070918A1080918B1090918C1062 -:10D040000F94DDB46093891070938A1080938B10D5 -:10D0500090938C10C301B201A70196010F94B4B84C -:10D06000209375103093761040937710509378107A -:10D070002FC080917B13882329F085E40F94909B27 -:10D08000811187C70F945D6523C083E40F94909B43 -:10D0900090917B13882329F09923D1F00F94B02528 -:10D0A00017C09111FBCF0E94DCD412C0809187156C -:10D0B0009091881583569C4E9F938F9382E39EE0B8 -:10D0C0009F938F930F9493AD0F900F900F900F90AD -:10D0D00010922D0F10922C0F9CC284E50F94909B00 -:10D0E000882309F427C120912B0D30912C0DF901D3 -:10D0F00031968F01021B130B7F0181918032C9F39E -:10D100008930B9F3082E000C990B0F94F0B8F70191 -:10D110008083E0912B0DF0912C0DE00FF11F8081A9 -:10D1200090ED980F953008F45EC08F3309F442C03B -:10D13000883781F0833649F1E2E2FEE084918F0185 -:10D14000882309F4F3C00E946EAD0F5F1F4FF801F2 -:10D150008491F6CF80917B13882309F45AC240E072 -:10D1600050E067EA70E381ED92E10E94FDD5809383 -:10D170002C0E0F94988380912C0E805F0F946A245C -:10D1800061E081E00F945B2144C280917B1388238E -:10D1900009F43FC20F9498836CED75E080E090E055 -:10D1A0000F940D8780E30F946A2480912C0E809356 -:10D1B0002D0E4BC080917B1340E050E0882351F04E -:10D1C00067EA70E381ED92E10E94FDD580932C0E19 -:10D1D00011E010C067EB72E180EC92E10E94FDD596 -:10D1E00080932C0E06C00F94879B0F9454B56093C8 -:10D1F0002C0E10E00F94988380912C0E21E030E0EB -:10D20000082E01C0220F0A94EAF79091330F292BC0 -:10D210002093330F90917B139923D1F0805F0F946B -:10D220006A2461E081E00F945B216CED75E080E0A1 -:10D2300090E00F940D8780E30F946A2480912C0E68 -:10D2400080932D0E112309F4E4C10F943720E1C11E -:10D25000882309F432C0E6E9FEE584918F01882332 -:10D2600039F00E946EAD0F5F1F4FF8018491F7CF28 -:10D27000E0E2FEE084918F01882339F00E946EADD8 -:10D280000F5F1F4FF8018491F7CF60912C0E70E073 -:10D2900080E090E00E94F7AD8AE00E946EADE7EF7B -:10D2A000F5E084918F01882309F440C00E946EAD9F -:10D2B0000F5F1F4FF8018491F6CF86E40F94909B87 -:10D2C000882399F00F94879B6B017C0120E030E06C -:10D2D000A9010F943AB6181644F4C0927E02D09277 -:10D2E0007F02E0928002F0928102E6E9FEE58491FD -:10D2F0008F01882339F00E946EAD0F5F1F4FF80138 -:10D300008491F7CFE5EEF5E084918F01882339F021 -:10D310000E946EAD0F5F1F4FF8018491F7CF6091AF -:10D32000FE0C70E080E090E00E94F7AD8AE00E9481 -:10D330006EAD6FC184E40F94909B882309F408C1FB -:10D340000F94879B0F944EB56330710509F061C14E -:10D350008EE995E09F938F930F9493AD81E40F94A2 -:10D36000909B0F900F908823B9F080912B0D909196 -:10D370002C0DDC0111962C91283741F440E150E04E -:10D3800060E070E002960F941DAA04C00F94879B82 -:10D390000F944EB58B0102C000E010E083E40F94BF -:10D3A000909B882339F00F94879B0F944EB5262FBE -:10D3B000872F02C020E080E11F71A22EB82EB1E0BD -:10D3C000AB16B0E1BB0618F0A12CB0E1BB2EC50135 -:10D3D000800F911F8130904128F080E090E15C0146 -:10D3E000A01AB10A88E50F94909B882309F475C0B0 -:10D3F00020912B0D30912C0DA9014F5F5F4F9E01A5 -:10D400002F5F3F4F6901F901E12CF12C9A01D901FD -:10D410008C912F5F3F4F8823A1F140E1E416F10486 -:10D4200069F18032A1F38A3061F190ED980F9A3062 -:10D4300018F48295807F07C09FE9980F9630A8F472 -:10D440008295807F8057AD014E5F5F4F11969C9112 -:10D4500020ED290F2A3010F4822B0BC02FE9290F61 -:10D46000263018F49755892B04C0F194E194F10803 -:10D4700008C081936FEFE61AF60AC8CFA0E1EA2E42 -:10D48000F12C5701E114F10441F1812C912CD601CA -:10D490006D916D01C401800F911F0F9493B3BFEF85 -:10D4A0008B1A9B0AE814F90491F71F930F93FF92CC -:10D4B000EF9281E795E09F938F930F9493AD6091E6 -:10D4C000D1197091D2198AE090E00F940EAD0F90AF -:10D4D0000F900F900F900F900F906801E12CF12C9E -:10D4E000A114B10409F495C08D2D0F94A59B8C2D2A -:10D4F0000F94A59B6091D1197091D21980E290E0B0 -:10D500000F940EAD10E1EFEFCE1ADE0AEE0AFE0A1E -:10D51000C60101970F9463B3082F6091D1197091E0 -:10D52000D21980E290E00F940EAD802F0F94A59B4E -:10D530001150F1E0AF1AB10811F01111E4CF609170 -:10D54000D1197091D2198AE090E00F940EADC8CF36 -:10D55000E6E9FEE584918F01882339F00E946EADE3 -:10D560000F5F1F4FF8018491F7CFE1E1F6E084915E -:10D570008F01882339F00E946EAD0F5F1F4FF801B5 -:10D580008491F7CF009187151091881503561C4E92 -:10D59000D8018D918D01882319F00E946EADF8CFCE -:10D5A000EBE1FEE084918F01882309F4BFCE0E9455 -:10D5B0006EAD0F5F1F4FF8018491F6CFC090D50F6D -:10D5C000D090D60FE090D70FF090D80F2091411057 -:10D5D000309142104091431050914410C701B60160 -:10D5E0000F94EEB34B015C012DEC3CEC4CEC5DEB8D -:10D5F0000F9488AE87FD3AC02DEC3CEC4CEC5DE31B -:10D60000C501B4010F943AB618160CF438C00F9443 -:10D61000DAA081E090E090932302809322020F949D -:10D6200025886093FF0E7093000F8093010F9093F5 -:10D63000020FE0918715F0918815E656FC4E808127 -:10D64000813019F0863009F0C6C4EDE5F7E1849128 -:10D650008F01882339F00E946EAD0F5F1F4FF801D4 -:10D660008491F7CF8AE00E946EADB5C4E091FE0CC4 -:10D67000F0E0E752F04F8081811192C409C0E0913F -:10D68000FE0CF0E0E752F04F8081882309F4BFCF11 -:10D69000C0924110D0924210E0924310F092441098 -:10D6A00081E490E10E94D5BDE091FE0CF0E0E752EC -:10D6B000F04F908181E089270F94FCA48CC420E076 -:10D6C00030E040E85FE3609141107091421080913A -:10D6D0004310909144100F94EFB3609341107093F6 -:10D6E00042108093431090934410E0903D10F090CE -:10D6F0003E1000913F101091401020913910309150 -:10D700003A1040913B1050913C106091351070914F -:10D7100036108091371090913810EEEFFCE0FF93B7 -:10D72000EF93812C912CE8ECAE2EE3E4BE2EF1E4D5 -:10D73000CF2EF0E1DF2E0E9451870F900F900C94B6 -:10D74000594182E090E0909323028093220210924C -:10D75000470E1092460E0C949F450F947C9BAB0194 -:10D76000BC0140935B1950935C1960935D197093F1 -:10D770005E1986EA98E10E940EE0AACC0F94879B7E -:10D780000F944EB58B010C9462490F94988388E5F1 -:10D790000F94909B882319F0179A1092FF0C89E53B -:10D7A0000F94909B882319F0169A1092000D8AE529 -:10D7B0000F94909B85E40F94909B882311F40C9414 -:10D7C000DE4D149A0C94DE4D1A8219824AE050E024 -:10D7D000BE016F5F7F4FC7010F941DAA78A36F8FA3 -:10D7E00089819A818816990609F072CC4AE050E046 -:10D7F000BE016F5F7F4FC6010F941DAA7AA369A374 -:10D8000089819A816816790609F062CC4AE050E075 -:10D81000BE016F5F7F4FC5010F941DAA7CA36BA350 -:10D8200089819A810817190709F052CC8FE790E097 -:10D830009EA38DA35801EFEFAE1ABE0AD8018C91BA -:10D840008D3211F575016701BFEFCB1ADB0AF701C5 -:10D8500080810F94C451382E811102C07601F3CF1C -:10D86000EA18FB08DE2CC70199278330910569F57A -:10D8700043E050E06BED7BE5C5010F9466AC892B6E -:10D8800009F042C01EA21DA2332009F421CCCE0112 -:10D8900001960F941164882309F41ACCFE017F9637 -:10D8A000DE011196AE01495D5F4F219131918D915D -:10D8B0009D918217930708F44CC02817390708F484 -:10D8C00007CC4E175F0789F703CC8530910571F4BB -:10D8D00045E050E065ED7BE5C5010F9466AC892B12 -:10D8E00099F481E090E09EA38DA3CECF049761F4DC -:10D8F00044E050E060ED7BE5C5010F9466AC892BF8 -:10D9000019F482E090E0EFCF8EEF8E0D823008F0B8 -:10D91000DFCBD80111968C9111978F7D823509F05C -:10D92000D7CB12968C918F7D833409F0D1CBB2E0A6 -:10D93000DB1203C083E090E0D6CFF801838190ED45 -:10D94000980F9A3008F0C4CB082E000C990B8E97D4 -:10D95000CACF89E492E10F94930745E65DE062E067 -:10D9600080E00F941237D2011D912D01812F0F9469 -:10D97000C451811108C067EC76E0812F110F990B1B -:10D980000F940EADF0CF49E352E163E080E00F94D5 -:10D9900012378091010790910207029720F488EED8 -:10D9A00093E00F94185E82E390E00F94BD1284E53B -:10D9B0000F94524D84EF91E00F94BD1280910107B6 -:10D9C00090910207029720F488EE93E00F94185E7E -:10D9D00082E390E00F94BD1284E50F94524D80E0F5 -:10D9E00090E00F94729C81E00F9427370F941D37BD -:10D9F00080E00F94932F6CCBAB96CCACDDACEEAC4F -:10DA0000FFACAB97C80ED91EEA1EFB1EAB962CAD21 -:10DA10003DAD4EAD5FADAB97281B390B4A0B5B0B91 -:10DA20002A966CAD7DAD8EAD9FAD2A970F94A4B3B1 -:10DA3000A70196010F94B4B8DA01C901840D951DB0 -:10DA4000A61DB71D84319105A105B105E4F02C0197 -:10DA50003D018C3E9105A105B1052CF06BEE462EE3 -:10DA6000512C612C712C40E844165104610471045E -:10DA7000DCF05EEF852E912CA12CB12C841895083A -:10DA8000A608B7080AC034E1432E512C612C712C32 -:10DA900044E1842E912CA12CB12C2A968CAE9DAE03 -:10DAA000AEAEBFAE2A9706C02A964CAE5DAE6EAE45 -:10DAB0007FAE2A97E2E4FDE084918F01882339F05C -:10DAC0000E946EAD0F5F1F4FF8018491F7CFC30125 -:10DAD000B2010E94F7ADEDE3FDE084918F01882350 -:10DAE00039F00E946EAD0F5F1F4FF8018491F7CFA0 -:10DAF0002A966CAD7DAD8EAD9FAD2A970E94F7AD95 -:10DB0000E6E3FDE084918F01882339F00E946EAD39 -:10DB10000F5F1F4FF8018491F7CF42E06D966FAD14 -:10DB20006D976E967FAD6E976F968FAD6F97A0963F -:10DB30009FADA0970E9411AEEFE2FDE084918F01AE -:10DB4000882339F00E946EAD0F5F1F4FF80184915A -:10DB5000F7CF42E0A1966FADA197A2967FADA297B5 -:10DB6000A3968FADA397A4969FADA4970E9411AEE4 -:10DB70008AE00E946EAD8091310E9091320E039733 -:10DB800014F40C942A592A966CAD7DAD8EAD9FADE0 -:10DB90002A970F948EAE20E030E040E850E40F94D6 -:10DBA000F5A74B015C016D962FAD6D976E963FAD5D -:10DBB0006E976F964FAD6F97A0965FADA097A196A9 -:10DBC0006FADA197A2967FADA297A3968FADA397B5 -:10DBD000A4969FADA4970F94EEB320ED3FE049E4E7 -:10DBE00050E40F94F5A720E030E040E05FE30F94AD -:10DBF000F5A79B01AC01C501B4010F94DDB44B0145 -:10DC00005C01C701B6010F948EAE20E030E04AE718 -:10DC100054E40F94DDB46B017C01E9E2FDE08491F2 -:10DC20008F01882339F00E946EAD0F5F1F4FF801FE -:10DC30008491F7CF42E0C501B4010E9411AEE3E246 -:10DC4000FDE084918F01882339F00E946EAD0F5F53 -:10DC50001F4FF8018491F7CF42E0C701B6010E943F -:10DC600011AE8AE00E946EAD2AE939E949E15FE32D -:10DC7000C501B4010F94F5A74B015C016093200F1F -:10DC80007093210F8093220F9093230F9B01AC017F -:10DC90000F94EFB3A70196010F94DDB460931C0FAE -:10DCA00070931D0F80931E0F90931F0FA501940179 -:10DCB000C701B6010F94F5A720E030E040E05EE335 -:10DCC0000F94F5A76093180F7093190F80931A0F94 -:10DCD00090931B0FE5E1FDE084918F01882339F0DB -:10DCE0000E946EAD0F5F1F4FF8018491F7CF8AE05D -:10DCF0000E946EADEFE0FDE084918F01882339F042 -:10DD00000E946EAD0F5F1F4FF8018491F7CF6091B5 -:10DD1000200F7091210F8091220F9091230F42E0EC -:10DD20000E9411AE8AE00E946EADE9E0FDE08491B0 -:10DD30008F01882339F00E946EAD0F5F1F4FF801ED -:10DD40008491F7CF60911C0F70911D0F80911E0F71 -:10DD500090911F0F42E00E9411AE8AE00E946EADCA -:10DD6000E3E0FDE084918F01882339F00E946EADDD -:10DD70000F5F1F4FF8018491F7CF6091180F7091DA -:10DD8000190F80911A0F90911B0F42E00E9411AE63 -:10DD90008AE00E946EAD0C942A5980935C0F0C941B -:10DDA0004259E8961FAEE8970C94675984E690E0D4 -:10DDB0000F94BD120C94DF5A312C0C94FD5EE12CB3 -:10DDC000F12C80910101846080930101E114F10440 -:10DDD00009F04EC080910107909102070097F1F180 -:10DDE0000197D1F19FEFE91AF90AA1E0DA1609F4D7 -:10DDF00052C0DA1608F04AC084E090E00F94BD12D9 -:10DE00000F942588950184010054184D264F3F4FEB -:10DE1000061717072807390710F00C94236085EDC3 -:10DE200090E10F9493071F8E18A219A21AA2CE0197 -:10DE30004F960F947F760F949883149ADD24D39491 -:10DE40000F94BC7D81E00F94680EF4EFEF16F1E0C3 -:10DE5000FF0609F0B6CFB3CFCC2021F29FB7F894DC -:10DE6000809102018460809302019FBFC12CBACFD0 -:10DE700084E1E816F10409F0B5CF9FB7F8948091DA -:10DE800002018B7F809302019FBFACCFB2E0DB1613 -:10DE9000E1F00C94236084E090E00F94BD120F94A5 -:10DEA0006B30882369F2E091FE0CF0E0EE0FFF1F6B -:10DEB000E757FA4E64962EAD3FAD649731832083C9 -:10DEC0000E944DFD42E0D42EBBCF0091FE0C10E02D -:10DED000F801EE0FFF1FE757FA4E60817181072EA0 -:10DEE000000C880B990B0F948EAE000F111F000FC2 -:10DEF000111FF801E452F04F20813181428153819A -:10DF00000F94EEB32B013C0120E030E0A9010F9407 -:10DF10003AB618165CF420E030E040E85FE3C30155 -:10DF2000B2010F9488AE87FF16C00AC020E030E02F -:10DF300040E85FEBC301B2010F943AB618165CF4E7 -:10DF400080E091E10F9493070F9425884B015C01C9 -:10DF5000D12C0C94266064E081E00F946E32E09145 -:10DF6000FE0C34E0E39FF0011124E452F04F808175 -:10DF70009181A281B3818F8F98A3A9A3BAA3CE0167 -:10DF80004F960E9446A00F941031A4E1EA2EF12C86 -:10DF900057CF0F94879B0F9454B560932C0E72C883 -:10DFA0002DEC3CEC4CEC5DE3C501B4010F943AB6AA -:10DFB00018160CF46DCB2BCBA5019401F101662D45 -:10DFC000772D8F2F922D0F9488AE181614F40C9481 -:10DFD000AD3A0C94BD3AC958DF4F0FB6F894DEBF86 -:10DFE0000FBECDBFDF91CF911F910F91FF90EF90AA -:10DFF000DF90CF90BF90AF909F908F907F906F9069 -:10E000005F904F903F902F9008952F923F924F92A4 -:10E010005F926F927F928F929F92AF92BF92CF92B8 -:10E02000DF92EF92FF920F931F93CF93DF93CDB7C1 -:10E03000DEB7C95CD1090FB6F894DEBF0FBECDBF05 -:10E04000782E81E00F949C66711025C01092030D0C -:10E050001092020D19821A821B821C82CE01019637 -:10E060000F947F7661E080EC9FE00F9475B360E0E1 -:10E070008FEB9FE00F9475B360E08EEB9FE00F9401 -:10E0800075B360E08DEB9FE00F9475B360E08CEBAF -:10E090009FE00F9475B380E00F9427370F94F560DD -:10E0A0000F94FB2C1092FD0C1092FC0C83E0EFEF10 -:10E0B000FCE0DF011D928A95E9F781E00E94DBA573 -:10E0C000C855DF4F99838883C85AD04083E69CE1C6 -:10E0D0000F9493070E940AA640E050E061E080E0C0 -:10E0E00090E00F94DD6640E050E061E081E090E078 -:10E0F0000F94DD66E0903D10F0903E1000913F10CF -:10E10000109140102091391030913A1040913B10FD -:10E1100050913C10609135107091361080913710FD -:10E12000909138100F94BA590E94D2BC10922102DB -:10E1300020E030E040EA50E46091351070913610F4 -:10E1400080913710909138100F94EFB31B012C0180 -:10E150006093351070933610809337109093381079 -:10E1600020E030E040EA50E46091391070913A10BC -:10E1700080913B1090913C100F94EFB39B01AC0148 -:10E180006093391070933A1080933B1090933C1039 -:10E19000E0903D10F0903E1000913F101091401023 -:10E1A0008EEF9CE09F938F93812C912CA0EAAA2E56 -:10E1B000A1E4BA2EB1E4CB2EB0E1DB2EC201B10155 -:10E1C0000E9451870F9498830E9414A60F900F907D -:10E1D000882311F40C94E48389E29CE10F944108B4 -:10E1E000772089F089EF9BE10F94930763E080E04B -:10E1F0000F946E3261E070E080E090E00F94F530B3 -:10E2000083EF9BE110C083ED9BE10F94930762E0E5 -:10E2100080E00F946E3261E070E080E090E00F9457 -:10E22000F5308DEC9BE10F9495310F94D26671100F -:10E230002EC084E090E0909323028093220240E07D -:10E2400060E082EB9BE10F94A007882321F08AE82D -:10E250009BE10F94410884EF9AE10F94410882E01A -:10E2600090E0909323028093220283ED9BE10F9430 -:10E27000930762E080E00F946E3261E070E080E02E -:10E2800090E00F94F5308DEC9BE10F94953180E098 -:10E2900090E0A0EAB0E480933D1090933E10A093EC -:10E2A0003F10B09340106090210281E080932102E2 -:10E2B00084E00F94FF37E0903D10F0903E10009105 -:10E2C0003F10109140102091391030913A10409138 -:10E2D0003B1050913C106091351070913610809138 -:10E2E000371090913810EEEFFCE0FF93EF93812C04 -:10E2F000912CE0EAAE2EE1E4BE2EF1E4CF2EF0E167 -:10E30000DF2E0E9451870F9498830F946437609298 -:10E31000210282E00F9485830F900F9020E030E07F -:10E3200040EA50E40F9488AE81110C94E08377208A -:10E33000E9F0C855DF4F88819981C85AD0400E94C2 -:10E34000BAA50F94EA2E0F94FD2A0F949C328823CD -:10E3500011F40C9490830E94C6AC803F11F00C9491 -:10E36000DC8381E00E949AA90C94DC838AEF0E94EE -:10E370009AA960E070E088EF9FE00F948FB30F944C -:10E38000D26684ECEDE8F5E1DF011D928A95E9F7AC -:10E39000EAE0FFE184918F01882339F00E946EAD9D -:10E3A0000F5F1F4FF8018491F7CF61E070E080E0CC -:10E3B00090E00E94F7AD0E94A3AEBE016F5A7F4F5E -:10E3C00083ED9BE10F94810762968FAD6297843055 -:10E3D00020F083E062968FAF629780E090E0A0EA41 -:10E3E000B0E480933D1090933E10A0933F10B09303 -:10E3F00040102AEE3EE1C657DF4F39832883CA58C2 -:10E40000D0408CE895E1CE57DF4F99838883C2587E -:10E41000D040A0969FAF8EAFA097A8963FAF2EAFEB -:10E42000A89781E090E0A0E0B0E0AE968CAF9DAF01 -:10E43000AEAFBFAFAE970F94D26662966FAD6297E4 -:10E4400080E00F946E32AE966CAD7DAD8EAD9FAD1B -:10E45000AE970F94F5308DEC9BE10F94953165E507 -:10E4600075E585E591E40F948F2AA896EEADFFAD92 -:10E47000A89785919591A591B4918093351090932B -:10E480003610A0933710B0933810A896EEADFFADBC -:10E49000A897349685919591A591B4918093391060 -:10E4A00090933A10A0933B10B0933C1060E070E062 -:10E4B00088E492E40F948F2A00912D1010912E1071 -:10E4C00020912F10309130104091291050912A1036 -:10E4D00060912B1070912C10809125109091261036 -:10E4E000A0912710B09128103F932F931F930F9363 -:10E4F0007F936F935F934F93BF93AF939F938F934C -:10E5000086E79EE19F938F930F9493AD0F9498832A -:10E51000409125105091261060912710709128107D -:10E520008091291090912A10A0912B10B0912C105D -:10E53000C0902D10D0902E10E0902F10F090301041 -:10E5400021E00FB6F894DEBF0FBECDBF4131574278 -:10E550000CF420E08131974214F00C94E683822F72 -:10E5600090E0880F991FFC01E259F14EA590B490FC -:10E57000FC01EA59F14E85909490DF92CF929F92E0 -:10E580008F92BF92AF921F922F938DE49EE19F9343 -:10E590008F930F9493AD8DE69CE19F938F930F948F -:10E5A00093AD0F94A63A80916E008B7F80936E009E -:10E5B000EF9880916F008D7F80936F000FB6F89475 -:10E5C000A89580916000886180936000109260003F -:10E5D0000FBE1092FB0C1092FA0C8AED91E0909312 -:10E5E000F90C8093F80C88EB91E09093F70C8093F2 -:10E5F000F60C00E028EC30E0A601B401C5010F9450 -:10E60000F54D00912D1010912E1020912F1030916A -:10E6100030104091291050912A1060912B10709168 -:10E620002C108091251090912610A0912710B09168 -:10E6300028103F932F931F930F937F936F935F93B4 -:10E640004F93BF93AF939F938F938DE09DE19F93E3 -:10E650008F930F9493AD8091251090912610A091E7 -:10E660002710B0912810782E692E80912910909152 -:10E670002A10A0912B10B0912C10582E492EC0902A -:10E680002D10D0902E10E0902F10F09030100FB67B -:10E69000F894DEBF0FBECDBF44E8242E4CE1342EEB -:10E6A00095E0C91697EFD9060CF46FC01A8219824B -:10E6B0001F921F92A3E0AF93B4E8BF931F92E4E6CA -:10E6C000EF93DF92CF924F925F926F927F923F9241 -:10E6D0002F920F9493AD0FB6F894DEBF0FBECDBF4F -:10E6E00089819A81803D924030F089819A81803A77 -:10E6F000954058F512C0FE0131967F0100E010E010 -:10E7000024E833E0A601652D742D872D962D0F94F6 -:10E71000C16281110C94EB83E8CF9E012F5F3F4FC4 -:10E72000790100E010E02CE73CEFA60144565109C6 -:10E73000652D742D872D962D0F94C162882329F0A5 -:10E7400089819A8180539D4F1CC089819A8180372D -:10E75000984008F04AC0CE0101967C0104EB10E01D -:10E7600024E833E0A601485C5109652D742D872DFE -:10E77000962D0F94C1628823C1F189819A818056B8 -:10E780009A4F9A8389830C94EB8300912D101091FA -:10E790002E1020912F10309130104091291050915F -:10E7A0002A1060912B1070912C108091251090915F -:10E7B0002610A0912710B09128103F932F931F93FC -:10E7C0000F937F936F935F934F93BF93AF939F93F9 -:10E7D0008F938CEB9CE19F938F930F9493AD0FB627 -:10E7E000F894DEBF0FBECDBFD4C389819A81803437 -:10E7F0009B4098F4DE0111967D0104EB10E02CE7BC -:10E800003CEFA6014C525140652D742D872D962D5D -:10E810000F94C16281110C94D28480E0E981FA8165 -:10E82000882311F40C94EE8380912510909126108A -:10E83000A0912710B09128104091291050912A10D2 -:10E8400060912B1070912C1000912D1010912E10B2 -:10E8500020912F1030913010FF93EF931F930F935F -:10E860005F934F939F938F9389EE9CE19F938F9338 -:10E870000F9493AD40912D1050912E1060912F1058 -:10E880007091301000E028EC30E0B401C5010F9425 -:10E89000F54D85E08F9380E78F938DE19EE19F9307 -:10E8A0008F930F9493AD84E08F9388E38F938BE0E5 -:10E8B0009EE19F938F930F9493AD8091251090913B -:10E8C0002610A0912710B09128106A968CAF9DAFAA -:10E8D000AEAFBFAF6A976896CEACDFAC6897809159 -:10E8E000291090912A10A0912B10B0912C10E29633 -:10E8F0008CAF9DAFAEAFBFAFE29780912D109091DE -:10E900002E10A0912F10B09130106E968CAF9DAF4D -:10E91000AEAFBFAF6E971C0198E4291A310889E0A9 -:10E920008F9380E68F933F922F92E096AFADE09762 -:10E93000AF93AF96BFADAF97BF936896EFAD6897B3 -:10E94000EF936796FFAD6797FF9386E39DE19F93F3 -:10E950008F930F9493AD40912D1050912E10609194 -:10E960002F10709130107A0120E931E0E0966EAD01 -:10E970007FADE09768968EAD9FAD68970F94F54D8B -:10E98000E0962EAD3FADE0973450E4963FAF2EAF0A -:10E99000E4970FB6F894DEBF0FBECDBF812C912C4B -:10E9A000D601B450EC96BFAFAEAFEC97F601FC5F6A -:10E9B000C258DF4FF983E883CE57D040382D3170ED -:10E9C000A3963FAFA39780FC02C00C94F483EF960C -:10E9D0008FADEF97C158DF4F9881CF57D04000E0FF -:10E9E00020E931E0A701E4966EAD7FADE4970F9486 -:10E9F000F54DC0902910D0902A10E0902B10F09087 -:10EA00002C108091251090912610A0912710B09184 -:10EA1000281001E028EC30E0A101B6010F94F54D7B -:10EA2000C0902910D0902A10E0902B10F0902C105C -:10EA30008091251090912610A0912710B091281058 -:10EA40000FEF28EC30E040E659E0B6010F94F54DA9 -:10EA500080912D1090912E10A0912F10B091301018 -:10EA60007C01A3968FADA397882311F40C94FC83AB -:10EA700080910B01816080930B010000840195E07F -:10EA8000000F111F9A95E1F7A3969FADA3979923C5 -:10EA900011F40C94018480EC482E55245A94652C72 -:10EAA000752CC12CD12CA0E4E796AFAFE797A12C31 -:10EAB000B12C93B1A70142195309292F207194FF5A -:10EAC00002C00C94088488EE9FEF840F951F97FD79 -:10EAD00002C00C940C8480E090E0A80EB91E8091D6 -:10EAE0000B0121110C941684846080930B010000AB -:10EAF00021110C9419842E143F0434F484E00E94F4 -:10EB00003EBDB1E0EB1AF10881E00E943EBD8BE50D -:10EB100099E00197F1F7E7962FADE7972150E79637 -:10EB20002FAFE7972111C5CFA6E0B694A794AA9579 -:10EB3000E1F7A3963FADA397332311F40C942884F7 -:10EB40008FE190E08C199D09800F911FFC01EA571D -:10EB5000F84FA0828091251090912610A091271047 -:10EB6000B0912810840D951DA61DB71D809325100A -:10EB700090932610A0932710B0932810C7010F2C54 -:10EB8000000CAA0BBB0B80932D1090932E10A0931A -:10EB90002F10B09330108FEFC81AD80A90E2C91620 -:10EBA000D10409F080CF0A57184FE0E2BE2EF1E3FE -:10EBB000CF2EFDE1DF2ED8018D918D011F928F9315 -:10EBC000DF92CF920F9493ADBA940F900F900F9065 -:10EBD0000F90B110F0CF8FE29DE19F938F930F9430 -:10EBE00093ADBFEF8B1A9B0AE496EEADFFADE497B1 -:10EBF000E05CFF4FE496FFAFEEAFE4970F900F900D -:10EC0000F0E28F16910409F0D9CE76E8A72E7BE0CA -:10EC1000B72E86EA9BE0F501119211928E179F079D -:10EC2000D9F780E090E0DC0165E0AA0FBB1F6A9590 -:10EC3000E1F7AA57B84F40E0ED91F0E034E0F595E8 -:10EC4000E7953A95E1F7EE0FFF1FEA57F44F208161 -:10EC500031812F5F3F4F318320834F5F403261F717 -:10EC6000019680329105F9F696E8C92E9BE0D92EDF -:10EC700000E010E02EE6E22E2DE1F22ED6018C917E -:10EC800011969C91B2E0CB0ED11C9F938F931F9352 -:10EC90000F93FF92EF920F9493AD0F5F1F4F0F9062 -:10ECA0000F900F900F900F900F900031110531F7DA -:10ECB0008091880B9091890BE8E8FBE031E021E03E -:10ECC000419151918417950710F4322FCA012F5F9B -:10ECD0002031B1F7032F1F923F939F938F9385E9C4 -:10ECE0009DE19F938F930F9493ADE4EAFBE00F9027 -:10ECF0000F900F900F900F900F908EE03291229115 -:10ED00002A30310510F40C942B848295807F209159 -:10ED1000860B3091870B2037334010F00C943284EF -:10ED2000000F000F000F182F101B1F921F931F9230 -:10ED30008F931F920F938EE79DE19F938F930F9474 -:10ED400093AD86E8482E87E0582E0FB6F894DEBFC4 -:10ED50000FBECDBFF201202F30E0012F10E08081E7 -:10ED600090E02817390710F00C943584821B930B20 -:10ED7000982F80E0B8010F948DB86F3F710519F09E -:10ED800010F06FEF70E06193AE16BF0641F700E040 -:10ED900010E0A9E7AA2EADE1BA2EB7E7CB2EBDE170 -:10EDA000DB2EC801F5E0880F991FFA95E1F7DC0129 -:10EDB000AA57B84F7D01912CF70181917F011F92D5 -:10EDC0008F93BF92AF920F9493AD93940F900F9047 -:10EDD0000F900F90F0E29F12EFCFDF92CF920F943F -:10EDE00093AD0F5F1F4F0F900F9000321105C9F6C2 -:10EDF00083EF9DE12EED3BE0A6ECBBE0FC014591ED -:10EE000054914D935D9302962A173B07B9F7612CF5 -:10EE1000712C812C912C10E000E050E060E070E05B -:10EE2000B62E26EC3BE0E4963FAF2EAFE497A0E091 -:10EE3000B0E080E090E040E020E030E07D01E60ED0 -:10EE4000F71E1701260C371CEEEFAE2EA40E411153 -:10EE50000C943984FEEFFF2EF20EE7E0EF1510F070 -:10EE60000C943F842F5F3F4F2C30310581F74F5F6B -:10EE70009096E4962EAD3FADE4972E5F3F4FE4961B -:10EE80003FAF2EAFE4974C30B9F6881699061CF4C4 -:10EE90004C01052F1B2D6F5F7F4F6431710509F009 -:10EEA000BFCF5F5F30E2630E711C543109F0B6CF03 -:10EEB0009F928F921F920F931F921F9389EA9DE159 -:10EEC0009F938F930F9493AD0FB6F894DEBF0FBE50 -:10EED000CDBF93E48916910414F40C9474841F92AA -:10EEE0000F931F921F938AED9DE19F938F930F9431 -:10EEF00093AD1A5FE12EF12CA0E1EA1AF108B6E019 -:10EF0000EE0CFF1CBA95E1F76896EEADFFAD689781 -:10EF1000EE0EFF1E0A5FC02ED12CF0E1CF1AD108F1 -:10EF200016E0CC0CDD1C1A95E1F7E0962EAD3FAD56 -:10EF3000E097C20ED31E6C963FAD6C973F936B96D5 -:10EF40008FAD6B978F93DF92CF92FF92EF9289EC08 -:10EF50009DE19F938F930F9493AD00E028EC30E0F8 -:10EF60006C964EAD5FAD6C97B601C7010F94F54D31 -:10EF70000FB6F894DEBF0FBECDBF81E0F201119253 -:10EF80002F01F6EF4F16FCE05F06C1F781110C94DC -:10EF9000778410E086E39EE19F938F930F9493AD67 -:10EFA0000E948F9580916E00846080936E00EF9A2E -:10EFB00080916F00826080936F0098E288E10FB6C5 -:10EFC000F894A895809360000FBE90936000109213 -:10EFD000FB0C1092FA0C1092F90C1092F80C109293 -:10EFE000F70C1092F60C0F900F90112311F40C9463 -:10EFF000188320E030E0A901A096AEADBFADA09788 -:10F0000011966D917D918D919C9114970F94F5A718 -:10F0100020913510309136104091371050913810B2 -:10F020000F94EFB3A096EEADFFADA097618372830E -:10F0300083839483C0903910D0903A10E0903B10B5 -:10F04000F0903C1020E030E0A90165817681878155 -:10F0500090850F94F5A7A70196010F94EFB3A096A2 -:10F06000AEADBFADA09715966D937D938D939C9398 -:10F07000189720E030E040E850ECC701B6010F944B -:10F0800088AE87FF0CC080E090E0A0E8B0EC8093F1 -:10F09000391090933A10A0933B10B0933C1020E0AD -:10F0A00030E040E450E460913D1070913E1080915A -:10F0B0003F10909140100F94EFB360933D10709308 -:10F0C0003E1080933F1090934010AE968CAD9DAD56 -:10F0D000AEADBFADAE970196A11DB11DAE968CAF82 -:10F0E0009DAFAEAFBFAFAE97A896AEADBFADA89780 -:10F0F0001896A896BFAFAEAFA897A096EEADFFAD9D -:10F10000A0973896A096FFAFEEAFA097AE968CADC5 -:10F110009DADAEADBFADAE970597A105B10509F0A8 -:10F120008AC980E090E00F94BD1220E030E040E911 -:10F1300050EC60919115709192158091931590917A -:10F1400094150F9488AE87FF43C0E9EEFEE18491E9 -:10F150008F01882339F00E946EAD0F5F1F4FF801B9 -:10F160008491F7CF8AE00E946EADE7EBFEE18491D7 -:10F170008F01882339F00E946EAD0F5F1F4FF80199 -:10F180008491F7CF609191157091921580919315AC -:10F190009091941542E00E9411AEE3EBFEE1849160 -:10F1A0008F01882339F00E946EAD0F5F1F4FF80169 -:10F1B0008491F7CF42E060E070E080E990EC0E943B -:10F1C00011AE0E94A3AEF2E0AF96FFAFAF9703C0BF -:10F1D000AF961FAEAF971092BD151092BE1510924C -:10F1E000BF151092C0151092C1151092C215109241 -:10F1F000C3151092C41524E6E3962FAFE397A296A9 -:10F200001CAE1DAE1EAE1FAEA2976A961CAE1DAE02 -:10F210001EAE1FAE6A97CE01019664969FAF8EAF69 -:10F220006497DE01AF5BBF4F6696BFAFAEAF669728 -:10F230006A966CAD7DAD8EAD9FAD6A970F94DAB4D2 -:10F24000AA966CAF7DAF8EAF9FAFAA976A966CAD52 -:10F250007DAD8EAD9FAD6A970F9468B7C457DF4FF1 -:10F26000688379838A839B83CC58D040A2966CAD07 -:10F270007DAD8EAD9FADA2970F94DAB4C057DF4F2E -:10F28000688379838A839B83C059D040A2966CADF2 -:10F290007DAD8EAD9FADA2970F9468B7CC56DF4F72 -:10F2A000688379838A839B83C459D0406496EEAD8A -:10F2B000FFAD6497A0E4EA2E1192EA94E9F766960E -:10F2C000AEADBFAD6697E0E11D92EA95E9F780E04B -:10F2D00090E00F94BD128091BD159091BE15A09144 -:10F2E000BF15B091C015C655DF4F88839983AA8397 -:10F2F000BB83CA5AD0408091C1159091C215A0918C -:10F30000C315B091C415C255DF4F88839983AA8372 -:10F31000BB83CE5AD040DE01AF5BBF4FC856DF4F34 -:10F32000B983A883C859D040FE013196AC96FFAF8F -:10F33000EEAFAC9700E0CC56DF4F88819981AA816F -:10F34000BB81C459D040B058EA968CAF9DAFAEAFE8 -:10F35000BFAFEA97C057DF4F88819981AA81BB81EF -:10F36000C059D040B058EE968CAF9DAFAEAFBFAF96 -:10F37000EE97C457DF4F88819981AA81BB81CC5811 -:10F38000D040B058C258DF4F88839983AA83BB838B -:10F39000CE57D040AC962EAC3FACAC9710E07CE89A -:10F3A000472E75E1572EE4E07E2EC12CD12C76013C -:10F3B000013011F40C94FA84113011F40C94068588 -:10F3C000002311F1023081F4D20111962D913D916B -:10F3D0004D915C911497C258DF4F688179818A8181 -:10F3E0009B81CE57D0400BC0F201258136814781E9 -:10F3F0005085EE966CAD7DAD8EAD9FADEE970F94C2 -:10F40000F5A74B015C0106C0812C912C60E8A62E6B -:10F410006FE3B62E112301F1123081F4D20111965F -:10F420002D913D914D915C911497C258DF4F6881A9 -:10F4300079818A819B81CE57D0400BC0F201258112 -:10F44000368147815085EE966CAD7DAD8EAD9FAD1A -:10F45000EE970F94F5A704C060E070E080E89FE3AA -:10F460009B01AC01C501B4010F94F5A79B01AC0150 -:10F47000C701B6010F94EFB36B017C010023E1F1EA -:10F480001123D1F1023011F00C94DA84D2011196DB -:10F490002D913D914D915C911497AA966CAD7DADE7 -:10F4A0008EAD9FADAA970F94F5A74B015C0111306B -:10F4B00011F40C94F484123011F00C94E784D2010E -:10F4C00011962D913D914D915C911497AA966CAD3A -:10F4D0007DAD8EAD9FADAA970F94F5A79B01AC01B2 -:10F4E000C501B4010F94F5A79B01AC01C701B6019A -:10F4F0000F94EFB36B017C017A94F8E04F0E511C2E -:10F50000711056CFD101CD92DD92ED92FD921D0189 -:10F510001F5F143009F043CF4CE8242E45E1342E10 -:10F52000EAEEFEE16C96FFAFEEAF6C97CA57DF4F85 -:10F530001882C658D040C456DF4F1882CC59D040EC -:10F54000C056DF4F1882C05AD04010E0002321F18E -:10F55000013049F1023081F4D10111962D913D9194 -:10F560004D915C911497C258DF4F688179818A81EF -:10F570009B81CE57D0400BC0F10125813681478158 -:10F580005085EE966CAD7DAD8EAD9FADEE970F9430 -:10F59000F5A74B015C010AC0812C912C30E8A32E09 -:10F5A0003FE3B32E03C0812C912C5401D10111965D -:10F5B0004D905D906D907C901497A3019201AA9656 -:10F5C0006CAD7DAD8EAD9FADAA970F94F5A76B0185 -:10F5D0007C01D10115968D919D910D90BC91A02D2E -:10F5E000A6968CAF9DAFAEAFBFAFA6976C96EEADB3 -:10F5F000FFAD6C9785919591A591B491CC55DF4F56 -:10F6000088839983AA83BB83C45AD040A6962CAD25 -:10F610003DAD4EAD5FADA697CC56DF4F6881798189 -:10F620008A819B81C459D0400F94F5A79B01AC01FE -:10F63000C701B6010F94EEB3C655DF4F288139815B -:10F640004A815B81CA5AD0400F94EFB3CC55DF4F4B -:10F65000288139814A815B81C45AD0400F94EEB32E -:10F66000A50194010F94F5A7CA57DF4F2881C6580A -:10F67000D040C456DF4F3881CC59D040C056DF4F00 -:10F680004881C05AD040512F0F94EFB3CA57DF4F73 -:10F69000688379838A839B83C658D0400023A9F06E -:10F6A0000130B9F00230D9F0A6962CAD3DAD4EAD8B -:10F6B0005FADA697EA966CAD7DAD8EAD9FADEA9736 -:10F6C0000F94F5A76B017C010AC0C12CD12C7601E7 -:10F6D00006C0C12CD12C20E8E22E2FE3F22E6C962E -:10F6E000EEADFFAD6C97349685909590A590B49053 -:10F6F000A3019201C457DF4F688179818A819B8180 -:10F70000CC58D0400F94F5A72B013C01A6962CAD08 -:10F710003DAD4EAD5FADA697C057DF4F6881798193 -:10F720008A819B81C059D0400F94F5A79B01AC0101 -:10F73000C301B2010F94EFB3C255DF4F2881398165 -:10F740004A815B81CE5AD0400F94EFB3A50194015A -:10F750000F94EEB3A70196010F94F5A7CA57DF4F98 -:10F76000288139814A815B81C658D0400F94EFB31C -:10F77000CA57DF4F6883C658D040C456DF4F7883DE -:10F78000CC59D040C056DF4F8883C05AD040192F83 -:10F790006C96AEADBFAD6C9718966C96BFAFAEAF22 -:10F7A0006C97B8E02B0E311CECEA2E16E5E13E0614 -:10F7B00009F0CCCEDC01CB01B058C856DF4FE88150 -:10F7C000F981C859D04081939193A193B193C856C0 -:10F7D000DF4FF983E883C859D0400F5FAC962EAD58 -:10F7E0003FADAC97205F3F4FAC963FAF2EAFAC978D -:10F7F000043009F0CFCD25968CAD9DADAEADBFAD3B -:10F800002597AA968CAF9DAFAEAFBFAFAA978D815B -:10F810009E81AF81B885AE968CAF9DAFAEAFBFAFC6 -:10F82000AE9789859A85AB85BC85A6968CAF9DAF32 -:10F83000AEAFBFAFA6978D859E85AF85B889EA9696 -:10F840008CAF9DAFAEAFBFAFEA9789819A81AB8194 -:10F85000BC81EE968CAF9DAFAEAFBFAFEE97299651 -:10F860008CAD9DADAEADBFAD2997C258DF4F88833B -:10F870009983AA83BB83CE57D04089899A89AB8963 -:10F88000BC89C457DF4F88839983AA83BB83CC5834 -:10F89000D040898D9A8DAB8DBC8DC057DF4F88834A -:10F8A0009983AA83BB83C059D0408D8D9E8DAF8D27 -:10F8B000B8A1CC56DF4F88839983AA83BB83C459F0 -:10F8C000D0408D899E89AF89B88DC856DF4F888317 -:10F8D0009983AA83BB83C859D0402D968CAD9DAD2A -:10F8E000AEADBFAD2D97CA57DF4F88839983AA83EA -:10F8F000BB83C658D04089A19AA1ABA1BCA1C45674 -:10F90000DF4F88839983AA83BB83CC59D0408DA1D4 -:10F910009EA1AFA1B8A5C056DF4F88839983AA8363 -:10F92000BB83C05AD0408DA59EA5AFA5B8A9CC5524 -:10F93000DF4F88839983AA83BB83C45AD04089A5AB -:10F940009AA5ABA5BCA5CE54DF4F88839983AA8323 -:10F95000BB83C25BD04061968CAD9DADAEADBFADFB -:10F960006197CA54DF4F88839983AA83BB83C65BA0 -:10F97000D04089A99AA9ABA9BCA9C654DF4F8883F6 -:10F980009983AA83BB83CA5BD0408DA99EA9AFA9E6 -:10F99000B8ADC254DF4F88839983AA83BB83CE5B03 -:10F9A000D04089AD9AADABADBCADCE53DF4F8883AF -:10F9B0009983AA83BB83C25CD04021968CAD9DAD58 -:10F9C000AEADBFAD2197CA53DF4F88839983AA8319 -:10F9D000BB83C65CD04014E6C12CD12C7601460115 -:10F9E000570126013701A3019201AE966CAD7DADA2 -:10F9F0008EAD9FADAE970F94F5A79B01AC01AA9673 -:10FA00006CAD7DAD8EAD9FADAA970F94EEB32B017B -:10FA10003C01A5019401A6966CAD7DAD8EAD9FAD68 -:10FA2000A6970F94F5A79B01AC01C301B2010F94F7 -:10FA3000EEB32B013C01A7019601EA966CAD7DADBA -:10FA40008EAD9FADEA970F94F5A79B01AC01C30162 -:10FA5000B2010F94EEB3EE962CAD3DAD4EAD5FAD61 -:10FA6000EE970F94DDB46E966CAF7DAF8EAF9FAF07 -:10FA70006E97C457DF4F288139814A815B81CC580A -:10FA8000D0400F94F5A79B01AC01C258DF4F6881AD -:10FA900079818A819B81CE57D0400F94EEB32B01A0 -:10FAA0003C01A5019401C057DF4F688179818A81AB -:10FAB0009B81C059D0400F94F5A79B01AC01C301B5 -:10FAC000B2010F94EEB34B015C01A7019601CC5635 -:10FAD000DF4F688179818A819B81C459D0400F941E -:10FAE000F5A79B01AC01C501B4010F94EEB3C85654 -:10FAF000DF4F288139814A815B81C859D0400F94FA -:10FB0000DDB42B013C01C456DF4F288139814A8185 -:10FB10005B81CC59D0406E966CAD7DAD8EAD9FAD06 -:10FB20006E970F94F5A79B01AC01CA57DF4F688110 -:10FB300079818A819B81C658D0400F94EEB34B01E6 -:10FB40005C01C056DF4F288139814A815B81C05AF0 -:10FB5000D040C301B2010F94F5A79B01AC01C501D0 -:10FB6000B4010F94EEB34B015C01A7019601CC5593 -:10FB7000DF4F688179818A819B81C45AD0400F947C -:10FB8000F5A79B01AC01C501B4010F94EEB3CE54AF -:10FB9000DF4F288139814A815B81C25BD0400F945D -:10FBA000DDB44B015C01C654DF4F288139814A81A5 -:10FBB0005B81CA5BD0406E966CAD7DAD8EAD9FAD66 -:10FBC0006E970F94F5A79B01AC01CA54DF4F688173 -:10FBD00079818A819B81C65BD0400F94EEB36B0123 -:10FBE0007C01C254DF4F288139814A815B81CE5B21 -:10FBF000D040C301B2010F94F5A79B01AC01C7012E -:10FC0000B6010F94EEB36B017C01CE53DF4F288118 -:10FC100039814A815B81C25CD040C501B4010F9437 -:10FC2000F5A79B01AC01C701B6010F94EEB3CA530F -:10FC3000DF4F288139814A815B81C65CD0400F94B7 -:10FC4000DDB46B017C01115009F0CDCE6E962CAD68 -:10FC50003DAD4EAD5FAD6E97C655DF4F6881798182 -:10FC60008A819B81CA5AD0400F94EFB36093BD152F -:10FC70007093BE158093BF159093C015A301920198 -:10FC8000C255DF4F688179818A819B81CE5AD040ED -:10FC90000F94EFB36093C1157093C2158093C31591 -:10FCA0009093C415A50194016A966CAD7DAD8EAD9F -:10FCB0009FAD6A970F94EFB36A966CAF7DAF8EAF2E -:10FCC0009FAF6A97A7019601A2966CAD7DAD8EADF0 -:10FCD0009FADA2970F94EFB3A2966CAF7DAF8EAF9E -:10FCE0009FAFA297E3969FADE3979150E3969FAFA6 -:10FCF000E39791119DCA6A966CAD7DAD8EAD9FADB7 -:10FD00006A970F94DAB46093AD157093AE15809333 -:10FD1000AF159093B0156A966CAD7DAD8EAD9FAD6D -:10FD20006A970F9468B76093B1157093B21580937A -:10FD3000B3159093B415A2966CAD7DAD8EAD9FAD0D -:10FD4000A2970F9468B7DC01CB01B0588093B5152A -:10FD50009093B615A093B715B093B815A2966CAD55 -:10FD60007DAD8EAD9FADA2970F94DAB46093B915B7 -:10FD70007093BA158093BB159093BC156A962CAD01 -:10FD80003DAD4EAD5FAD6A97A2966CAD7DAD8EADCB -:10FD90009FADA2970F94EEB36B017C01E894F7F846 -:10FDA000B701A60180E69FE00F9487B32FE132E40C -:10FDB00049E05BE3C701B6010F943AB618166CF43C -:10FDC00025E33AEF4EE85BE3C701B6010F943AB67C -:10FDD000181634F001E010E005C000E010E002C0A9 -:10FDE00002E010E025E33AEF4EE85BE36A966CAD83 -:10FDF0007DAD8EAD9FAD6A979F770F943AB618167A -:10FE00007CF025E33AEF4EE85BE3A2966CAD7DAD66 -:10FE10008EAD9FADA2979F770F943AB6181614F443 -:10FE200002E010E08091AD159091AE15A091AF1554 -:10FE3000B091B015AE968CAF9DAFAEAFBFAFAE97E1 -:10FE40008091B5159091B615A091B715B091B815E0 -:10FE5000A6968CAF9DAFAEAFBFAFA6978091BD15F4 -:10FE60009091BE15A091BF15B091C015E6968CAFCC -:10FE70009DAFAEAFBFAFE6978091B1159091B2152F -:10FE8000A091B315B091B415EA968CAF9DAFAEAF0B -:10FE9000BFAFEA978091B9159091BA15A091BB15A3 -:10FEA000B091BC15EE968CAF9DAFAEAFBFAFEE97E5 -:10FEB0008091C1159091C215A091C315B091C41540 -:10FEC000C258DF4F88839983AA83BB83CE57D04023 -:10FED000AAEEBEE16C96BFAFAEAF6C979CE8292E40 -:10FEE00095E1392EF10181809280A380B4808581D3 -:10FEF0009681A781B085AA968CAF9DAFAEAFBFAFFC -:10FF0000AA976C96EEADFFAD6C97C590D590E59035 -:10FF1000F490A5019401AE966CAD7DAD8EAD9FAD14 -:10FF2000AE970F94F5A72B013C01AA962CAD3DADE1 -:10FF30004EAD5FADAA97A6966CAD7DAD8EAD9FAD73 -:10FF4000A6970F94F5A79B01AC01C301B2010F94D2 -:10FF5000EFB3E6962CAD3DAD4EAD5FADE6970F9499 -:10FF6000EFB39B01AC01C701B6010F94EEB36B0177 -:10FF70007C016C96EEADFFAD6C9734964590559034 -:10FF800065907490EA962CAD3DAD4EAD5FADEA97AD -:10FF9000C501B4010F94F5A74B015C01EE962CADA1 -:10FFA0003DAD4EAD5FADEE97AA966CAD7DAD8EAD1D -:10FFB0009FADAA970F94F5A79B01AC01C501B401B1 -:10FFC0000F94EFB3C258DF4F288139814A815B819A -:10FFD000CE57D0400F94EFB39B01AC01C301B201E7 -:10FFE0000F94EEB34B015C01A7019601C701B60166 -:10FFF0000F94F5A76B017C01A5019401C501B40123 -:020000021000EC -:100000000F94F5A79B01AC01C701B6010F94EFB3A4 -:100010000F9473B72DEC3CEC4CE45FE30F943AB6CD -:10002000181614F40EEF1FEFB8E02B0E311C6C966F -:10003000EEADFFAD6C9738966C96FFAFEEAF6C9758 -:100040008CEAE82E85E1F82EE214F30409F04ACF99 -:100050000115110509F07AC1A2962CAD3DAD4EAD4A -:100060005FADA2976A966CAD7DAD8EAD9FAD6A9780 -:100070000F94EFB320E030E040E05FE30F94F5A78A -:100080006B017C010F94DAB42B013C016093AD1538 -:100090007093AE158093AF159093B015C701B6015C -:1000A0000F9468B7A2966CAF7DAF8EAF9FAFA2974B -:1000B0006093B1157093B2158093B3159093B415F6 -:1000C000DC01CB01B058AA968CAF9DAFAEAFBFAFED -:1000D000AA978093B5159093B615A093B715B093D2 -:1000E000B8154092B9155092BA156092BB1570922E -:1000F000BC151092BD151092BE151092BF1510922E -:10010000C0151092C1151092C2151092C31510920D -:10011000C4156E961CAE1DAE1EAE1FAE6E976A96CF -:100120001CAE1DAE1EAE1FAE6A97CE57DF4FA88124 -:10013000B981C258D04011968D909D90AD90BC90E1 -:10014000149715968D919D910D90BC91A02DAE9612 -:100150008CAF9DAFAEAFBFAFAE97C657DF4FE88154 -:10016000F981CA58D040C590D590E590F490A5018A -:100170009401C301B2010F94F5A7A6966CAF7DAFB1 -:100180008EAF9FAFA697AE962CAD3DAD4EAD5FAD99 -:10019000AE97AA966CAD7DAD8EAD9FADAA970F942C -:1001A000F5A79B01AC01A6966CAD7DAD8EAD9FAD64 -:1001B000A6970F94EFB39B01AC01C701B6010F9452 -:1001C000EEB32091BD153091BE154091BF155091F1 -:1001D000C0150F94EFB36B017C016093BD15709354 -:1001E000BE158093BF159093C01520E030E040E825 -:1001F0005FE36A966CAD7DAD8EAD9FAD6A970F944F -:10020000EFB36A966CAF7DAF8EAF9FAF6A97C6575C -:10021000DF4FE881F981CA58D04034968591959195 -:10022000A591B491A6968CAF9DAFAEAFBFAFA69788 -:10023000A5019401A2966CAD7DAD8EAD9FADA29748 -:100240000F94F5A74B015C01AE962CAD3DAD4EADC4 -:100250005FADAE97C301B2010F94F5A79B01AC014E -:10026000C501B4010F94EFB39B01AC01A6966CAD30 -:100270007DAD8EAD9FADA6970F94EEB32091C115C5 -:100280003091C2154091C3155091C4150F94EFB32E -:100290004B015C016093C1157093C2158093C31527 -:1002A0009093C41520E030E040E85FE36E966CADBB -:1002B0007DAD8EAD9FAD6E970F94EFB36E966CAF24 -:1002C0007DAF8EAF9FAF6E97CE57DF4FA881B981BC -:1002D000C258D0401896CE57DF4FB983A883C25872 -:1002E000D040C657DF4FE881F981CA58D0403896D0 -:1002F000C657DF4FF983E883CA58D0402A163B0619 -:1003000009F013CF6A962CAD3DAD4EAD5FAD6A9747 -:10031000C701B6010F94DDB46093BD157093BE158F -:100320008093BF159093C0156E962CAD3DAD4EAD2C -:100330005FAD6E97C501B4010F94DDB46093C11534 -:100340007093C2158093C3159093C4154090AD155A -:100350005090AE156090AF157090B015C090B91563 -:10036000D090BA15E090BB15F090BC158091B115F6 -:100370009091B215A091B315B091B415A2968CAF1F -:100380009DAFAEAFBFAFA2978091B5159091B61556 -:10039000A091B715B091B8156A968CAF9DAFAEAF6E -:1003A000BFAF6A97A7019601C301B2010F94F5A7E9 -:1003B0004B015C016A962CAD3DAD4EAD5FAD6A97C9 -:1003C000A2966CAD7DAD8EAD9FADA2970F94F5A7B3 -:1003D0009B01AC01C501B4010F94EEB34B015C016C -:1003E0009B01AC01C701B6010F94DDB46B017C0128 -:1003F0006A966CAD7DAD8EAD9FAD6A979058A501A4 -:1004000094010F94DDB46A966CAF7DAF8EAF9FAF51 -:100410006A97A2966CAD7DAD8EAD9FADA2979058B8 -:10042000A50194010F94DDB4CE57DF4F6883798323 -:100430008A839B83C258D040A5019401C301B201B5 -:100440000F94DDB44B015C014090BD155090BE157A -:100450006090BF157090C0158091C1159091C21524 -:10046000A091C315B091C415A2968CAF9DAFAEAF4D -:10047000BFAFA297C092AD15D092AE15E092AF1566 -:10048000F092B015CE57DF4F88819981AA81BB8148 -:10049000C258D0408093B1159093B215A093B31574 -:1004A000B093B4156A968CAD9DADAEADBFAD6A97F5 -:1004B0008093B5159093B615A093B715B093B81562 -:1004C0008092B9159092BA15A092BB15B092BC1546 -:1004D000C701B6019058A30192010F94F5A76B01D3 -:1004E0007C01A2962CAD3DAD4EAD5FADA2976A9654 -:1004F0006CAD7DAD8EAD9FAD6A970F94F5A79B0156 -:10050000AC01C701B6010F94EEB36093BD157093B3 -:10051000BE158093BF159093C015CE57DF4F6881ED -:1005200079818A819B81C258D0409058A301920161 -:100530000F94F5A76B017C01A2962CAD3DAD4EAD9D -:100540005FADA297C501B4010F94F5A79B01AC0163 -:10055000C701B6010F94EEB36093C1157093C21535 -:100560008093C3159093C41580E090E00F94BD1262 -:1005700017FD53C04DEB55E165EB75E18DEA95E153 -:100580000F94782B4091BD155091BE156091BF1509 -:100590007091C01585EE9FE00F9487B34091C1150F -:1005A0005091C2156091C3157091C41589EE9FE0FA -:1005B0000F9487B34091AD155091AE156091AF1572 -:1005C0007091B0158DED9FE00F9487B34091B115F8 -:1005D0005091B2156091B3157091B41581EE9FE002 -:1005E0000F9487B34091B5155091B6156091B7152A -:1005F0007091B81585ED9FE00F9487B34091B915C0 -:100600005091BA156091BB157091BC1589ED9FE0B2 -:100610000F9487B30F94FD2A09C00E3F9FEF19076F -:1006200029F4AF96AFADAF97A23049F038010BC0B7 -:10063000AF961FAEAF9766246A94762C04C0BEEFC7 -:100640006B2E77247A94C855DF4F88819981C85AD8 -:10065000D0400E94BAA580E090E0A0EAB0E4809388 -:100660003D1090933E10A0933F10B0934010209106 -:10067000391030913A1040913B1050913C106091EC -:100680003510709136108091371090913810EEEF40 -:10069000FCE0FF93EF93812C912CE0EAAE2EE1E495 -:1006A000BE2EF1E4CF2EF0E1DF2EE12CF12C00EA9A -:1006B00010E4F7D30F9498830F900F9077FC22C02B -:1006C00020E030E046E153E460913D1070913E102F -:1006D00080913F10909140100F94EFB360933D10C4 -:1006E00070933E1080933F109093401065E575E540 -:1006F00085E591E40F948F2A82E39AE10F944108F3 -:100700000F949C3281E00F94273782E00F94932F4F -:10071000BFEF6B167B0631F485EF99E10F9441082A -:1007200010E04BC0EEEF6E16EFEF7E0681F4AF9651 -:10073000FFADAF97FF2329F0F23031F08EEA98E158 -:10074000EDCF83E399E1EACF83EF98E1E7CFAF966E -:10075000EFACAF97E11007C023E06216710498F088 -:1007600083E399E117C0AF963FADAF97323019F4EC -:1007700080EB99E102C086E699E10F9441081614D6 -:10078000170454F309C0F301EE0FFF1FE553FD4FAB -:10079000808191810F9441086720609409F286EE70 -:1007A0000E949AA98FE59FE00F9463B3813021F0F6 -:1007B00087E59AE10F94410811E00F9464372BC14B -:1007C00086E19FE10F94410810E025C183E0821B80 -:1007D000282F0C94AF7281E00C940E74F0E9CF1ABC -:1007E000F1E0DF0A0C945073EB968FADEB97EC962B -:1007F0009FADEC970C94EF7480910B018E7F0C945D -:100800003B75B0E44B2E512C612C712C0C9451751E -:1008100087E190E00C9465758F3F910509F014F421 -:100820000C946D758FEF90E00C946D758B7F0C942C -:100830007575E0E6EE16E9E0FE0614F00C9484759A -:1008400084E00E943EBDFFEFEF1AFF0A0C9484750E -:10085000C6010C94A4758150883011F00C947E76FA -:100860000C94857600E00C94937680E090E00C94F4 -:10087000B8764B3011F40C942A77222311F02B30E8 -:1008800029F4F7E0FA1510F40C9432777101E20EB6 -:10089000F31EF701EA57F84FF081A396FFAFA39735 -:1008A000E496EEADFFADE497E080F180CC24C394F4 -:1008B000D12C022E02C0CC0CDD1C0A94E2F7EC20F5 -:1008C000FD20EF2831F0A396FFADA397F13148F05A -:1008D00005C0A396EFADA397E13118F401960C94EF -:1008E000327701970C94327780E00C94BE7784EFD6 -:1008F00091E00F943B4F882311F40C94C97714E0D6 -:10090000812C912C5401C12CD12C760188EE93E0DE -:100910000F943B4F882311F40C94C97780912510D4 -:1009200090912610A0912710B0912810092E000C4C -:10093000AA0BBB0BC80ED91EEA1EFB1E8091291004 -:1009400090912A10A0912B10B0912C10092E000C20 -:10095000AA0BBB0B880E991EAA1EBB1E1150B1F626 -:1009600040902D1050902E1060902F1070903010ED -:10097000C501B40122E096958795779567952A95EC -:10098000D1F732E0F694E794D794C7943A95D1F72B -:1009900000E028EC30E0A201C6010F94F54D11E013 -:1009A0000C94CA7729813A812059374F3A83298399 -:1009B0000C940E74F2012581368147815085EA96A8 -:1009C0006CAD7DAD8EAD9FADEA970C94537AF2017C -:1009D0002581368147815085EA966CAD7DAD8EAD1F -:1009E0009FADEA970C946C7A60E070E080E89FE33A -:1009F0000C946E7A112311F40C947C7A812C912C36 -:100A000050E8A52E5FE3B52E0C94577A01110C9493 -:100A1000427A0C947C7A81E00F94273780E00F941F -:100A20009C66812FC753DF4F0FB6F894DEBF0FBE11 -:100A3000CDBFDF91CF911F910F91FF90EF90DF908D -:100A4000CF90BF90AF909F908F907F906F905F906E -:100A50004F903F902F9008952F923F924F925F9228 -:100A60006F927F928F929F92AF92BF92CF92DF92BE -:100A7000EF92FF920F931F93CF93DF93CDB7DEB723 -:100A80006A970FB6F894DEBF0FBECDBF1C012801D8 -:100A90003901FC01E45BFF4F80809180A280B3802C -:100AA0009A01AB01C501B4010F94F5A70F94C6B428 -:100AB0000F9454B56B017C01A3019201C501B401EF -:100AC0000F94F5A70F94C6B40F9454B528E7C21637 -:100AD000D104E104F10428F448E7C42ED12CE12C20 -:100AE000F12CD101D7968D909D90AD90BC90DA9766 -:100AF000C986DA86EB86FC868C149D04AE04BF049E -:100B000020F489869A86AB86BC8668377105810594 -:100B1000910520F468E770E080E090E06B017C01D3 -:100B200086169706A806B90610F475016401F1014E -:100B3000ED5BFF4F408051806280738049825A8212 -:100B40006B827C8245284628472841F4412C512C51 -:100B50003201439449825A826B827C8229853A858C -:100B60004B855C85CA01B9010F94A4B36D877E875C -:100B70008F87988BA5019401C501B4010F94A4B38C -:100B80004B015C01A7019601C701B6010F94A4B304 -:100B9000698B7A8B8B8B9C8B49805A806B807C8095 -:100BA000440C551C661C771C4D825E826F827886D1 -:100BB000D501C4010197A109B1094D845E846F84F8 -:100BC000788884199509A609B7094D805E806F80E1 -:100BD0007884480E591E6A1E7B1EC301B2012D8106 -:100BE0003E814F8158850F94B3B329013A01C50165 -:100BF000B40129893A894B895C89621B730B840B88 -:100C0000950B2D813E814F8158850F94B3B3DA0146 -:100C1000C901840D951DA61DB71DF101808891881D -:100C2000A288B38888159905AA05BB0528F4881AF7 -:100C3000990AAA0ABB0A9CC029813A814B815C812E -:100C400082E0220F331F441F551F8A95D1F7D5012B -:100C5000C40181709927AA27BB2789839A83AB8314 -:100C6000BC832401350176946794579447944F8A46 -:100C7000588E698E7A8E4D845E846F8478888989D7 -:100C80009A89AB89BC8984159505A605B705C0F17D -:100C9000D301C20180959095A095B09549885A8856 -:100CA0006B887C88840D951DA61DB71DBC01CD01E8 -:100CB000620F731F841F951F49805A806B807C8050 -:100CC00045284628472841F04D805E806F80788413 -:100CD000640D751D861D971D0F94B3B38F89988D74 -:100CE000A98DBA8D820F931FA41FB51F2401350152 -:100CF00088159905AA05BB05C0F52C013D0135C035 -:100D00006D857E858F85988949885A886B887C880F -:100D1000641975098609970949805A806B807C801F -:100D200045284628472841F04D805E806F807884B2 -:100D3000640D751D861D971D0F94B3B34F88588C95 -:100D4000698C7A8C420E531E641E751ED501C40137 -:100D5000481459046A047B0410F4D301C20124012D -:100D60003501481A590A6A0A7B0A812C912C5401D0 -:100D70008FB7F894F101E55BFF4F908191111FC08F -:100D8000D1015A964D925D926D927C925D97840C42 -:100D9000951CA61CB71CF101868E978EA0A2B1A24D -:100DA00049845A846B847C84DB964D925D926D926B -:100DB0007C92DE97FF96C082D182E282F3828FBF5F -:100DC0006A960FB6F894DEBF0FBECDBFDF91CF910C -:100DD0001F910F91FF90EF90DF90CF90BF90AF9059 -:100DE0009F908F907F906F905F904F903F902F904B -:100DF00008950F931F93CF93C82F0F94CA828AEE42 -:100E00000F947C820F949A82811103C00F94C18247 -:100E100035C08C2F0F947C820F949A82882371F1B5 -:100E20000F94C1820F94CA828BEE0F947C820F9430 -:100E30009A82882319F1599A28E02A95F1F7519856 -:100E400087E090E0C0E0589A28E02A95F1F729B1B0 -:100E500021FB002700F910E09801082E01C0220FA5 -:100E60000A94EAF7C22B589828E02A95F1F70197DF -:100E700050F7519A0F94C1828C2F06C08FEF809348 -:100E80001D0D80931C0D80E0CF911F910F9108954F -:100E9000CF93C82F0F941020C150E1F7CF910D943C -:100EA0001B202F923F924F925F926F927F928F9270 -:100EB0009F92AF92BF92CF92DF92EF92FF920F93E9 -:100EC0001F93CF93DF93CDB7DEB7C358D1090FB6C9 -:100ED000F894DEBF0FBECDBF69A37AA38BA39CA3FA -:100EE0002DA33EA34FA358A7E496ECAEFDAE0EAFE4 -:100EF0001FAFE497E696DFAECEAEE6978BA699A637 -:100F0000AFA6B8AAC756DF4F88809980C959D0408C -:100F10009AAE89AE809100078F5FA6968FAFA69795 -:100F2000803119F4A6961FAEA697A6969FACA697F9 -:100F3000092D990C110B8091FF0690E008171907F5 -:100F400009F452C0BE016B5D7F4FCE0181960E94B5 -:100F5000C3A749A05AA06BA07CA020917D1030911E -:100F60007E1040917F1050918010C301B2010F9408 -:100F7000F5A70F94E7B6AA966CAF7DAF8EAF9FAF83 -:100F8000AA978DA09EA0AFA0B8A420918110309107 -:100F900082104091831050918410C501B4010F94C8 -:100FA000F5A70F94E7B6AE966CAF7DAF8EAF9FAF4F -:100FB000AE9780918C15882369F1A5019401C30136 -:100FC000B2010F948E77E4962CAD3DAD4EAD5FAD82 -:100FD000E4970F94EFB320918510309186104091E3 -:100FE00087105091881024C01092260D0F94BC7D5C -:100FF00080E00F94680E80E00F94932F8091FF069D -:1010000090E00817190791F38091260D81110C9437 -:10101000759598CF2091851030918610409187105A -:1010200050918810E4966CAD7DAD8EAD9FADE49788 -:101030000F94F5A70F94E7B66F966CAF7DAF8EAFA8 -:101040009FAF6F97E696AEADBFADE697CD90DD90C2 -:10105000ED90FC902091891030918A1040918B1076 -:1010600050918C10C701B6010F94F5A70F94E7B605 -:1010700069966CAF7DAF8EAF9FAF69972091591085 -:1010800030915A1040915B1050915C10C301B20135 -:101090000F94EEB32B013C0120915D1030915E1056 -:1010A00040915F1050916010C501B4010F94EEB3F0 -:1010B0004B015C01A3019201C301B2010F94F5A79A -:1010C0002B013C01A5019401C501B4010F94F5A7C2 -:1010D0009B01AC01C301B2010F94EFB30F9473B73E -:1010E000C058DF4F688379838A839B83C058D04080 -:1010F00020916510309166104091671050916810F2 -:10110000C701B6010F94EEB3A5966CAF7DAF8EAF5D -:101110009FAFA5978091751090917610A091771050 -:10112000B091781069968CAC9DACAEACBFAC6997B1 -:1011300088169906AA06BB0609F4C4C0E091FE0C05 -:1011400004E0E09FF0011124E452F04F20912402CA -:1011500030912502409126025091270260817181D1 -:10116000828193810F9488AE87FF33C0809275107F -:1011700090927610A0927710B0927810C09265107D -:10118000D0926610E0926710F0926810E6E9FEE5F2 -:1011900084918F01882339F00E946EAD0F5F1F4F3D -:1011A000F8018491F7CFECEAFFE184918F01882365 -:1011B00039F00E946EAD0F5F1F4FF8018491F7CF99 -:1011C0008AE00E946EADA5961CAE1DAE1EAE1FAE8F -:1011D000A5978091751090917610A0917710B0919D -:1011E000781069968CAC9DACAEACBFAC6997881A90 -:1011F000990AAA0ABB0AC501B401B7FE07C09095B7 -:101200008095709561957F4F8F4F9F4F0F948EAE55 -:101210006B017C0120E030EC4BEE53E460918910CF -:1012200070918A1080918B1090918C100F94F5A77B -:101230009B01AC01C701B6010F943AB618160CF029 -:1012400041C06996ACACBDACCEACDFAC6997A092A6 -:101250007510B0927610C0927710D0927810E69602 -:10126000EEADFFADE69780819181A281B38180933D -:10127000651090936610A0936710B0936810E6E92C -:10128000FEE584918F01882339F00E946EAD0F5FD7 -:101290001F4FF8018491F7CFEEE8FFE184918F01B1 -:1012A000882339F00E946EAD0F5F1F4FF8018491C3 -:1012B000F7CF8AE00E946EADA5961CAE1DAE1EAEA5 -:1012C0001FAEA59780910007282E312CF7E58F9F40 -:1012D000C00111248A57984FFC01EB5AFF4F11822D -:1012E00010823A9710828090691090906A10A090B6 -:1012F0006B10B0906C1021968CAE9DAEAEAEBFAEB2 -:101300002197AA964CAD5DAD6EAD7FADAA974819F9 -:1013100059096A097B0977FF07C070956095509558 -:1013200041955F4F6F4F7F4F87E5829DF001839D11 -:10133000F00D1124EA57F84F408351836283738381 -:1013400040906D1050906E1060906F107090701003 -:10135000AE960CAD1DAD2EAD3FADAE97041915097F -:101360002609370937FF07C030952095109501955C -:101370001F4F2F4F3F4FE7E5E29DC001E39D900DCA -:101380001124FC01EA57F84F048315832683378321 -:10139000A0907110B0907210C0907310D090741023 -:1013A000A9AABAAACBAADCAA6F968CAD9DADAEADA8 -:1013B000BFAD6F978A199B09AC09BD09B7FF07C07C -:1013C000B095A095909581959F4FAF4FBF4FF7E592 -:1013D000BF2EB29CF001B39CF00D1124EA57F84FD8 -:1013E00080879187A287B387C0907510D0907610C0 -:1013F000E0907710F0907810CDAADEAAEFAAF8AEB0 -:1014000069968CAC9DACAEACBFAC69978C189D084E -:10141000AE08BF08B7FE08C0B094A0949094809422 -:10142000811C911CA11CB11CE7E5EE2EE29CF00191 -:10143000E39CF00D1124EA57F84F84869586A68622 -:10144000B78688159905AA05BB0514F4D501C40112 -:101450004A015B0180179107A207B30744F04817C0 -:1014600059076A077B0754F44C015D0107C0401718 -:1014700051076207730714F44801590187E5829DFB -:10148000F001839DF00D1124EA57F84F808A918A6C -:10149000A28AB38A06E080169104A104B10414F470 -:1014A0000C947595DF01A95BBF4F8091BB1990919A -:1014B000BC198C01990F220B330B0D931D932D93A7 -:1014C0003C931397AA968CAC9DACAEACBFACAA97DC -:1014D0002196CCACDDACEEACFFAC21978C149D0416 -:1014E000AE04BF0414F0108E02C081E0808FAE966F -:1014F000ECACFDAC0EAD1FADAE97E414F5040605E3 -:1015000017055CF487E5829DF001839DF00D1124A1 -:10151000EA57F84F808D8260808F89A89AA8ABA87F -:10152000BCA86F96CCACDDACEEACFFAC6F97C8142A -:10153000D904EA04FB045CF487E5829DF001839DF5 -:10154000F00D1124EA57F84F808D8460808F6996E2 -:10155000ECACFDAC0EAD1FAD69978DA89EA8AFA8F1 -:10156000B8ACE814F9040A051B055CF487E5829D14 -:10157000F001839DF00D1124EA57F84F808D8860AB -:10158000808FA9ADBAAD8C9197E5929DF001939DA6 -:10159000F00D1124EA57F84F818F452B462B472B2E -:1015A00009F0179887E5829DF001839DF00D1124C5 -:1015B000EA57F84F84819581A681B781892B8A2BC0 -:1015C0008B2B09F0169887E5829DF001839DF00D25 -:1015D0001124EA57F84F80859185A285B385892B20 -:1015E0008A2B8B2B09F0159887E5829DF001839D4E -:1015F000F00D1124EA57F84F84859585A685B785A7 -:10160000892B8A2B8B2B11F40C946F958091230DD1 -:10161000882319F081508093230D8091240D882315 -:1016200019F081508093240D8091250D882319F0A5 -:1016300081508093250DE9ADFAAD8081813061F054 -:1016400030F0823089F480E28093250D08C0149830 -:1016500080E28093230D08C080E28093240D809166 -:10166000230D811128C0149A87E5829DF001839D86 -:10167000F00D1124EA57F84F84849584A684B7842A -:1016800089AE9AAEABAEBCAE89288A288B2819F5F4 -:10169000E090B910F090BA100091BB101091BC10FE -:1016A0002BA539A54FA558A9B701C8010F943AB683 -:1016B00018163CF522C087E5829DF001839DF00D50 -:1016C0001124EA57F84F84849584A684B78489AEA0 -:1016D0009AAEABAEBCAEE090B510F090B6100091F3 -:1016E000B7101091B8109701A8016BA579A58FA527 -:1016F00098A90F9488AE87FF04C0EBA6F9A60FA7A0 -:1017000018AB8091691090916A10A0916B10B09104 -:101710006C10AA96ACACBDACCEACDFACAA97A81A44 -:10172000B90ACA0ADB0AC601B5010F948EAE209130 -:101730007D1030917E1040917F10509180100F9459 -:10174000DDB421966CAF7DAF8EAF9FAF21976983DB -:101750007A838B839C83AE966CAD7DAD8EAD9FAD51 -:10176000AE9764197509860997090F948EAE20917A -:1017700081103091821040918310509184100F9409 -:10178000DDB44B015C016D837E838F8398876F96F8 -:101790006CAD7DAD8EAD9FAD6F97C9A8DAA8EBA8F3 -:1017A000FCA86C197D098E099F090F948EAE2091BB -:1017B00085103091861040918710509188100F94B9 -:1017C000DDB46B017C0169877A878B879C8769967A -:1017D0006CAD7DAD8EAD9FAD69970DA91EA92FA9EA -:1017E00038AD601B710B820B930B0F948EAE209162 -:1017F000891030918A1040918B1050918C100F9469 -:10180000DDB46D877E878F87988B27E5229DF00159 -:10181000239DF00D1124EA57F84F20813181428138 -:10182000538125962CAF3DAF4EAF5FAF2597263045 -:10183000310541055105D4F4048115812681378194 -:1018400006301105210531058CF4008511852285AE -:101850003385063011052105310544F4DC01CB0147 -:10186000BF7786A797A7A0ABB1AB2EC021966CAD72 -:101870007DAD8EAD9FAD21970F94F2A72B013C015A -:10188000C501B4010F94F2A79B01AC01C301B201E1 -:101890000F94EFB34B015C01C701B6010F94F2A79F -:1018A0009B01AC01C501B4010F94EFB30F9473B762 -:1018B00027E5229DF001239DF00D1124EA57F84FF2 -:1018C00066A777A780AB91AB87E5829DF001839DEA -:1018D000F00D1124EA57F84F46A457A460A871A848 -:1018E000A301920160E070E080E89FE30F94DDB413 -:1018F0002BA539A54FA558A90F94F5A76B017C011D -:10190000809100079091FF06891B8F708DAF90E04A -:101910000297069708F042C0A701960160E074E2C2 -:1019200084E799E40F94DDB40F94E7B64B015C01B2 -:101930008091BD109091BE10A091BF10B091C010C9 -:1019400088169906AA06BB0648F588199909AA09B6 -:10195000BB09BC01CD01660F771F881F991FCDAC55 -:101960000C2D10E020E030E0A90198010F94B3B3F2 -:10197000CA01B9010F948CAE0F94E7B6680D791DBA -:101980008A1D9B1D0F948CAE9B01AC0160E074E23C -:1019900084E799E40F94DDB46B017C01A30192010B -:1019A000C701B6010F94F5A729966CAF7DAF8EAF36 -:1019B0009FAF299787E5829D8001839D100D11249B -:1019C0000A57184F29968CAC9DACAEACBFAC29978A -:1019D000D80192968D929D92AD92BC929597509619 -:1019E0006D917D918D919C9153970F948CAE6BA7C7 -:1019F0007CA78DA79EA79B01AC01C701B6010F94E0 -:101A0000F5A70F94C6B40F9454B52D966CAF7DAF67 -:101A10008EAF9FAF2D97F80167AB70AF81AF92AFDC -:101A20008090220D8DAA8E010F5F1F4F63961FAF0E -:101A30000EAF6397005F1F4FA1961FAF0EAFA19728 -:101A400080902B0290902C026B969FAE8EAE6B977F -:101A500065961FAF0EAF659700E010E019A61FA6B0 -:101A600020E828AB3FE339AB6396AEADBFAD6397DB -:101A70002D913D914D915D916396BFAFAEAF639750 -:101A8000C701B6010F94F5A76596EEADFFAD65975A -:101A900061937193819391936596FFAFEEAF6597D4 -:101AA0004B015C01E894B7F86B96AEADBFAD6B9798 -:101AB0002D913D914D915D916B96BFAFAEAF6B9700 -:101AC00061962CAF3DAF4EAF5FAF6197C501B401DA -:101AD0000F943AB6181614F5A501940161966CADF1 -:101AE0007DAD8EAD9FAD61970F94DDB45B014C0170 -:101AF00029A53FA548A959A90F943AB6181624F06C -:101B0000A9A6BFA688AA99AA81E090E0002E01C0EC -:101B1000880F0A94EAF78DA8882A8DAA0F5F1F4FB5 -:101B20000430110509F0A0CF9DA89092220D20E06D -:101B300030E040E85FE369A57FA588A999A90F94E3 -:101B400088AE87FF4CC07E0101E2E00EF11CA19639 -:101B50000EAD1FADA19729A53FA548A959A9D80148 -:101B60006D917D918D919C910F94F5A7F8016193F2 -:101B70007193819391938F01EE15FF0561F787E5CE -:101B8000829D8001839D100D11240A57184F2996BC -:101B90002CAD3DAD4EAD5FAD299769A57FA588A958 -:101BA00099A90F94F5A7D80192966D937D938D9383 -:101BB0009C9395972D966CAD7DAD8EAD9FAD2D9779 -:101BC0000F948CAE29A53FA548A959A90F94F5A754 -:101BD0000F9454B5F80167AB70AF81AF92AFA3011A -:101BE00092016BA57CA58DA59EA50F94DDB42B015C -:101BF0003C0125968CAC9DACAEACBFAC259789283A -:101C00008A288B2891F587E5829D8001839D100DA0 -:101C100011240A57184FF80184819581A681B78154 -:101C2000892B8A2B8B2B09F580859185A285B3851D -:101C3000892B8A2B8B2BC9F42091B1103091B210D3 -:101C40004091B3105091B410C301B2010F94F5A7A5 -:101C50000F94C6B40D5B1F4F0F9454B5D8016D930C -:101C60007D938D939C9313972EC12091AD1030914D -:101C7000AE104091AF105091B010C301B2010F945B -:101C8000F5A70F94C6B40F9454B527E5229D8001A3 -:101C9000239D100D11240753184FF80160837183A1 -:101CA00082839383C0905F0DD090600DE090610DB2 -:101CB000F090620D0F948CAE4B015C0125966CADDB -:101CC0007DAD8EAD9FAD25970F948EAE9B01AC017F -:101CD000C501B4010F94F5A72BA53CA54DA55EA5A4 -:101CE0000F94DDB44B015C01C701B6010F948CAEBB -:101CF0009B01AC01C501B4010F943AB6181654F417 -:101D0000D801CD92DD92ED92FC9213978DA980615E -:101D10008093220D8090630D9090640DA090650DCE -:101D2000B090660D87E5829D8001839D100D112482 -:101D30000A57184FF801ED5BFF4FFAA7E9A760813A -:101D40007181828193810F948CAE6B017C01D801EB -:101D500014966D917D918D919C9117970F948EAEF5 -:101D60009B01AC01C701B6010F94F5A72BA53CA5BB -:101D70004DA55EA50F94DDB46B017C01C501B401D6 -:101D80000F948CAE9B01AC01C701B6010F943AB61B -:101D900018165CF4E9A5FAA580829182A282B3822A -:101DA0008091220D80628093220D80906B0D909027 -:101DB0006C0DA0906D0DB0906E0D87E5829D800139 -:101DC000839D100D11240753184FD8016D917D91FB -:101DD0008D919C910F948CAE6B017C0169AD7AADB5 -:101DE0008BAD9CAD0F948EAE9B01AC01C701B601CB -:101DF0000F94F5A72BA53CA54DA55EA50F94DDB4CA -:101E00006B017C01C501B4010F948CAE9B01AC0148 -:101E1000C701B6010F943AB6181654F4F80180823F -:101E20009182A282B3828091220D80648093220DE0 -:101E30008090670D9090680DA090690DB0906A0D2C -:101E400087E5829D8001839D100D11240A57184F4C -:101E500098012D5B3F4F3AA729A7D9016D917D913C -:101E60008D919C910F948CAE6B017C01F801608583 -:101E70007185828593850F948EAE9B01AC01C7015D -:101E8000B6010F94F5A72BA53CA54DA55EA50F9413 -:101E9000DDB46B017C01C501B4010F948CAE9B01D4 -:101EA000AC01C701B6010F943AB6181664F4A9A59F -:101EB000BAA58D929D92AD92BC9213978091220DFE -:101EC00080688093220D87E5829D8001839D100D9F -:101ED00011240A57184FF801ED5BFF4F60817181A3 -:101EE000828193810F948CAE6B017C01A3019201DE -:101EF0000F94DDB4EE966CAF7DAF8EAF9FAFEE97D3 -:101F0000F80162AB73AB84AB95AB2DEB37E346E0E6 -:101F100051E4C701B6010F94F5A70F944EB5D8014F -:101F200054966D937D938D939C93579792968C9036 -:101F3000929789AA93969C9093979DAA9496AC9019 -:101F40009497A9AE9596BC902296BFAE229701ECCD -:101F500010E1C258DF4F19830883CE57D0402E01BD -:101F600011E2410E511C01EC10E1A1966EAC7FAC68 -:101F7000A1978BA699A6AFA6B8AA26961FAE2697BC -:101F8000D3018D909D90AD90BD903D01E894B7F840 -:101F9000F801C190D190E190F1908F01A7019601D5 -:101FA000C501B4010F943AB618160CF03EC026963F -:101FB000FFAD2697FF2389F12BA539A54FA558A979 -:101FC000C501B4010F94F5A74B015C01A70196016F -:101FD00069A97DA989AD22969FAD22970F94F5A797 -:101FE0006B017C019B01AC01C501B4010F943AB6B1 -:101FF0001816DCF4A5019401C701B6010F94DDB4F5 -:102000009B01AC016BA579A58FA598A90F94F5A7A5 -:102010006BA779A78FA798AB08C0CBA6D9A6EFA6C8 -:10202000F8AA21E026962FAF26976414750409F0CC -:10203000A7CF87E5829DF001839DF00D1124EA571B -:10204000F84F16AA0DAD023008F4A5C11091551035 -:102050002A961FAF2A97809056102E968FAE2E97F5 -:102060009090571062969FAE6297A0905810649619 -:10207000AFAE649727E137EB41ED58E3612F782D40 -:10208000892D9A2D0F943AB618160CF084C1212F81 -:10209000382D492D5A2D69A97DA989AD22969FAD6C -:1020A00022970F9488AE87FF1DC0212F382D492D10 -:1020B0005A2D69A97DA989AD22969FAD22970F94CB -:1020C000DDB4EA966CAF7DAF8EAF9FAFEA97B9A84B -:1020D000BDAE0DA9C9AC2696CFAE269722961FADF0 -:1020E00022972AC029A93DA949AD22965FAD229722 -:1020F0002A966FAD2A972E967FAD2E9762968FAD5A -:10210000629764969FAD64970F94DDB4EA966CAFC6 -:102110007DAF8EAF9FAFEA972A96DFAC2A97DDAEF0 -:102120002E960FAD2E976296EFAC62972696EFAE85 -:10213000269764961FAD649725E430E1E0963FAFA3 -:102140002EAFE097412C512C80E8682E8FE3782E3B -:102150006A961FAE6A97E096AEADBFADE097CD90A0 -:10216000DD90ED90FD90E096BFAFAEAFE097A19609 -:10217000EEADFFADA19781909190A190B190A19605 -:10218000FFAFEEAFA1972A962FAD2A972E963FADBF -:102190002E9762964FAD629764965FAD649769A97A -:1021A0007DA989AD22969FAD22970F9488AE87FFB7 -:1021B0000CC0EA962CAD3DAD4EAD5FADEA97C701C0 -:1021C000B6010F94F5A76B017C016A96FFAD6A9783 -:1021D000FF2381F0A3019201C701B6010F94F5A777 -:1021E0006B017C01A3019201C501B4010F94F5A715 -:1021F0004B015C01A5019401C701B6010F943AB6E9 -:1022000020E030E0A90118160CF5C501B4010F94C7 -:102210003AB618164CF020E030E0A901C701B6012B -:102220000F9488AE87FF05C0A5019401C701B601D0 -:1022300020C0B7FAB094B7F8B094A5019401C701D3 -:10224000B6010F943AB618163CF124C0C501B4018A -:102250000F9488AE87FD09C020E030E0A901C701D6 -:10226000B6010F943AB618164CF4A7019601C501B1 -:10227000B4010F94EEB36B017C010EC0F7FAF09439 -:10228000F7F8F094A7019601C501B4010F9488AE48 -:1022900087FD02C075016401C258DF4FA881B98172 -:1022A000CE57D0408D909D90AD90BD90C258DF4FDD -:1022B000B983A883CE57D040A5019401C701B601C8 -:1022C0000F943AB6181694F4A7019601C501B4010B -:1022D0000F94DDB49B01AC01C301B2010F94F5A7CB -:1022E0002B013C01B1E06A96BFAF6A97E5E5F0E1EA -:1022F000E0968EAC9FACE097E815F90509F02BCF7E -:102300006A969FAC6A97992081F0A30192016DAD06 -:10231000702F26968FAD2697912F0F94F5A76DAF4E -:10232000072F26968FAF2697192F24EA30E74DE71F -:102330005FE36DAD702F26968FAD2697912F0F948A -:10234000F5A76B017C0120911E0D30911F0D40916E -:10235000200D5091210D0F9488AE87FF2EC02BA524 -:1023600039A54FA558A9C701B6010F9488AE87FFBC -:1023700024C087E5829DF001839DF00D1124EA576A -:10238000F84F84E086ABABA4ADAE09A5BFA42696FA -:10239000BFAE269711C087E5829DF001839DF00DA9 -:1023A0001124EA57F84F84E086ABCBA4CDAE09A543 -:1023B000DFA42696DFAE269718A927E5229DC00147 -:1023C000239D900D11249C012A57384F79018DAD22 -:1023D000902F2696AFAD2697B12FF90182A793A72C -:1023E000A4A7B5A72BA539A54FA558A96BA579A575 -:1023F0008FA598A90F94F5A74B015C01EE966CADE3 -:102400007DAD8EAD9FADEE9790589B01AC010F94C2 -:10241000EFB3D7019E962D913D914D915C91D1974F -:102420000F94F5A79B01AC01C501B4010F94EEB365 -:102430000F9473B76B017C019B01AC016DAD702FE4 -:1024400026968FAD2697912F0F9488AE87FD05C0F5 -:102450004C2C7D2C5E2C6F2C06C04DAC702E26961D -:102460005FAC2697612E87E5829DF001839DF00D7C -:102470001124EA57F84F842D972DA52DB62D86A34C -:1024800097A3A0A7B1A716A99601A70169A97DA93D -:1024900089AD22969FAD22970F9488AE181614F43A -:1024A00021E001C023E037E5329DC001339D900D4E -:1024B00011248A57984F122BFC0116AB20E1FE0124 -:1024C0007196A5E4B0E101900D922A95E1F749A932 -:1024D0005DA969AD22967FAD229740935510509328 -:1024E000561060935710709358104BA559A56FA5BF -:1024F00078A940931E0D50931F0D6093200D70938B -:10250000210DDC011C96CD90DD90ED90FC901F9785 -:10251000C114D104E104F10409F441C04D915D916D -:102520006D917C911397452B462B472B51F41496B4 -:102530008D919D910D90BC91A02D892B8A2B8B2B79 -:1025400071F120E030E0A9016091180D7091190D32 -:1025500080911A0D90911B0D0F9488AE8823F9F08D -:1025600087E5829DF001839DF00D1124EA57F84F15 -:1025700080899189A289B389C816D906EA06FB0623 -:1025800071F011E020E030E0A901A5966CAD7DADC1 -:102590008EAD9FADA5970F943AB618160CF010E0CB -:1025A00087E5829DF001839DF00D1124EA52F84FDA -:1025B0001083112309F46AC0C090140DD090150D3A -:1025C000E090160DF090170D2DEB37E346E855E33C -:1025D000C701B6010F9488AE87FF12C0C058DF4F05 -:1025E000288139814A815B81C058D040A5966CAD65 -:1025F0007DAD8EAD9FADA5970F94DDB46B017C01D1 -:1026000087E5829D8001839D100D11240A57184F84 -:10261000F80167A970AD81AD92AD0F948CAE9B01AE -:10262000AC0169A97DA989AD22969FAD22970F942F -:10263000DDB44B015C012091180D3091190D4091D2 -:102640001A0D50911B0DC701B6010F94F5A79B0100 -:10265000AC01C501B4010F94F5A720918910309108 -:102660008A1040918B1050918C100F94F5A720E0A8 -:1026700030E040E853E40F94F5A70F94E7B6F80173 -:10268000EF5AFF4F608371838283938327E5229DF6 -:10269000C001239D900D11248C010A57184F780119 -:1026A000045B1F4FD701D7966D917D918D919C91C1 -:1026B000DA970F948CAE29A93DA949AD22965FAD5A -:1026C00022970F94DDB4F801608371838283938332 -:1026D0000BA519A52FA538A9442D572D652D762DAD -:1026E000C7010E942C85F70180899189A289B3894D -:1026F00081159048A105B10538F4D701D6968C9183 -:10270000D6978860D6968C93A6968FACA697809223 -:102710000007AA96ACACBDACCEACDFACAA97A09239 -:102720006910B0926A10C0926B10D0926C10AE9685 -:10273000CCACDDACEEACFFACAE97C0926D10D092DD -:102740006E10E0926F10F09270106F96ECACFDACD2 -:102750000EAD1FAD6F97E0927110F0927210009362 -:1027600073101093741069968CAC9DACAEACBFAC7A -:1027700069978092751090927610A0927710B0921F -:10278000781089A19AA1ABA1BCA180935910909314 -:102790005A10A0935B10B0935C108DA19EA1AFA1C5 -:1027A000B8A580935D1090935E10A0935F10B093D6 -:1027B0006010E496ECACFDAC0EAD1FADE497E0927A -:1027C0006110F09262100093631010936410E6960B -:1027D000EEADFFADE69780819181A281B3818093B8 -:1027E000651090936610A0936710B0936810709076 -:1027F000FF068091000787198F70833008F493C01B -:1028000010910007111101C010E11150F7E51F9F51 -:10281000C00111249C012A57384F5901111101C0E0 -:1028200010E1115037E5139FC0011124AC014A5744 -:10283000584F7A01711609F47FC0D701D6960C91D2 -:1028400002FF05C080910007811B8F706DC0F701EA -:1028500082A493A4C4A4D5A49401A60166A177A1DF -:1028600080A591A50F9488AE882309F44EC001FD80 -:1028700043C0D50196962D903D904D905C909997D0 -:10288000A2019101B401C6010F9488AE1816A4F5F7 -:10289000A2019101C201B1010F94F5A71B012C0106 -:1028A000F70182A993A9A4A9B5A9BC01CD019058AB -:1028B0009B01AC010F94EFB3D7019E962D913D91F2 -:1028C0004D915C91D1970F94F5A79B01AC01C2018A -:1028D000B1010F94EEB30F9473B7562E672E5C01BF -:1028E000262F372FAC01B401C6010F9488AE87FDA7 -:1028F00003C0852C962C6501C401D601F70186A37F -:1029000097A3A0A7B1A7016006AB111101C010E108 -:102910001150F7E51F9FC001112457019C012A5750 -:10292000384F790187CF172D823030F4809100071E -:102930008111B4C080E1B2C037E5139FC0011124FA -:10294000AC014A57584F5A011F5F103109F410E08B -:10295000F12E57E5159FC0011124DC01AA57B84F8D -:102960006D01F50186A981FD68C046A057A060A44D -:1029700071A4D60196969C9096979796EC9097970F -:1029800098960C91989799961C91292D3E2DA80107 -:10299000C301B2010F9488AE87FF4FC0A30192011B -:1029A000C301B2010F94F5A72B013C01F50182A9E7 -:1029B00093A9A4A9B5A9BC01CD0190589B01AC0174 -:1029C0000F94EFB3D5019E962D913D914D915C9161 -:1029D000D1970F94F5A79B01AC01C301B2010F94ED -:1029E000EEB30F9473B7562E672E782E892E262FAE -:1029F000372F482F592F692D7E2DC8010F9488AE8F -:102A000087FF04C0592C6E2C702E812E252D362D5B -:102A1000472D582D692D7E2DC8010F9488AE88232F -:102A200061F0852D962DA72DB82DF60186A397A3CD -:102A3000A0A7B1A786A9816086ABD501D6969C9147 -:102A4000D697F60186A9892B80FF14C006A117A18D -:102A500020A531A596964D915D916D917C919997A8 -:102A6000C5010E942C85D501D6968C91D6978E7F74 -:102A7000D6968C9381E08F0D803109F480E0F82E9A -:102A8000B7E58B9FC00111248A57984F209100070A -:102A90005601F21609F44ACF6C0163CF8150E7E585 -:102AA0008E02C00111248C010A57184F7801D801F9 -:102AB00096964D915D916D917C9199970BA519A575 -:102AC0002FA538A9C7010E942C85F70186A98E7F02 -:102AD00086AB80916F00826080936F0006C019AE54 -:102AE0001AAE1BAE1CAE0C94488BCD57DF4F0FB601 -:102AF000F894DEBF0FBECDBFDF91CF911F910F9134 -:102B0000FF90EF90DF90CF90BF90AF909F908F900D -:102B10007F906F905F904F903F902F9008954F92CD -:102B20005F926F927F928F929F92AF92BF92CF925D -:102B3000DF92EF92FF92CF9380916F008D7F809311 -:102B40006F0080E00F9477836093691070936A1030 -:102B500080936B1090936C1081E00F947783609357 -:102B60006D1070936E1080936F109093701082E0D0 -:102B70000F94778360937110709372108093731029 -:102B80009093741083E00F94778360937510709323 -:102B90007610809377109093781080E00F9485835F -:102BA00060933510709336108093371090933810DF -:102BB00081E00F9485836093391070933A1080936D -:102BC0003B1090933C1082E00F94858360933D10FE -:102BD00070933E1080933F109093401083E00F94C9 -:102BE00085836093411070934210809343109093BB -:102BF000441080918C15882331F120913910309147 -:102C00003A1040913B1050913C10609135107091FA -:102C1000361080913710909138100F948E779B0169 -:102C2000AC0160913D1070913E1080913F109091E9 -:102C300040100F94EEB360933D1070933E1080935C -:102C40003F10909340100F944A83C0914D11CC23B4 -:102C500009F49AC0C0FF34C020913511309136116B -:102C600040913711509138116091351070913610A4 -:102C700080913710909138100F94EEB36093351017 -:102C8000709336108093371090933810209139113B -:102C900030913A1140913B1150913C1160913910A3 -:102CA00070913A1080913B1090913C100F94EEB3CC -:102CB0006093391070933A1080933B1090933C10BE -:102CC000C1FF62C08090351090903610A0903710F0 -:102CD000B0903810C0903910D0903A10E0903B106E -:102CE000F0903C1020910C0D30910D0D40910E0D87 -:102CF00050910F0DC501B4010F94F5A72B013C01B4 -:102D00002091100D3091110D4091120D5091130D25 -:102D1000C701B6010F94F5A79B01AC01C301B20135 -:102D20000F94EFB32B013C012091040D3091050D60 -:102D30004091060D5091070DC501B4010F94F5A700 -:102D40004B015C012091080D3091090D40910A0D55 -:102D500050910B0DC701B6010F94F5A79B01AC0173 -:102D6000C501B4010F94EFB3609335107093361022 -:102D700080933710909338104092391050923A1047 -:102D800060923B1070923C1080E1E5E3F0E1A9EC29 -:102D9000BFE001900D928A95E1F7109255101092C4 -:102DA0005610109257101092581010924510109211 -:102DB000461010924710109248101092491010922D -:102DC0004A1010924B1010924C1010924D1010920D -:102DD0004E1010924F1010925010109251101092ED -:102DE0005210109253101092541081E08093260DCF -:102DF000CF91FF90EF90DF90CF90BF90AF909F90DA -:102E00008F907F906F905F904F900895CF938091B7 -:102E10001D0D813311F080E02CC080911C0D813993 -:102E2000D1F782E00E94F98690911D0D9F3F99F3A2 -:102E300087FF1EC084E00E94F986C82F82E10E94AD -:102E4000F98690911D0D9F3F31F390E0982F8827D0 -:102E500088279F708C2B93FD90512091C71930913A -:102E6000C819A901481B590B5093C8194093C71999 -:102E700081E0CF910895CF93DF9380911D0D813331 -:102E800011F080E050C080911C0D8139D1F782E0B3 -:102E90000E94F986C82F87E10E94F9868093C9199C -:102EA00084E10E94F9868093CA1980911D0D8F3F9D -:102EB00041F3C7FF37C083E00E94F986D82F84E032 -:102EC0000E94F986C82F82E10E94F98690911D0D1B -:102ED0009F3FB9F290E09C0144E0220F331F4A95D6 -:102EE000E1F722273F702D2B982F882788279F7086 -:102EF0008C2B33FD305193FD90514091C519509169 -:102F0000C619240F351F3093C6192093C519209177 -:102F1000C7193091C819A901481B590B5093C819FA -:102F20004093C71981E0DF91CF9108950F931F93CC -:102F3000CF93DF931F921F92CDB7DEB7519A509A6D -:102F4000599A589A14E688E08A95F1F71150D9F702 -:102F500080E00E94F98680931D0D81E00E94F98631 -:102F600080931C0D90911D0D913389F4813979F472 -:102F70001982BE016F5F7F4F8DE00F9484768111BF -:102F800017C08FEF80931D0D80931C0D11C080E042 -:102F90000E94F98680931D0D81E00E94F98680933E -:102FA0001C0D90911D0D9133A1F5813991F5E0CF64 -:102FB00080EF8A83BE016E5F7F4F8EE00F94847630 -:102FC000811105C08FEF80931D0D80931C0D8DE046 -:102FD0000E94F9861F928F938AE79FE19F938F93B8 -:102FE00009E117E01F930F930F94F1AC8EE00E945C -:102FF000F9861F928F9386E69FE19F938F931F938D -:103000000F930F94F1AC0FB6F894DEBF0FBECDBF97 -:1030100011E0812F0F900F90DF91CF911F910F91B1 -:1030200008952F923F924F925F926F927F928F926C -:103030009F92AF92BF92CF92DF92EF92FF920F9347 -:103040001F93CF93DF93CDB7DEB7C151D1400FB6F9 -:10305000F894DEBF0FBECDBF06E51FE1C12CD12C19 -:1030600076018091C00087FD10C00F940E208FEF75 -:10307000C81AD80AE80AF80A91E8C91694E8D906E5 -:103080009EE1E906F10469F7A1C19091C600F8013B -:10309000849198139BC10F940E200F5F1F4FFFE187 -:1030A00005361F07F1F608E41FE1F80184910F943B -:1030B00007200F5F1F4FFFE105361F07B1F70F9481 -:1030C00029200F94635188E1809360001092600082 -:1030D000412C00E010E0512CCE0101966C0122241D -:1030E0002394312C0F941020813499F40F941020E4 -:1030F000F82E0F941B2092E8F91202C082E004C05F -:10310000E1E8FE1204C086E00F9407205BC183E073 -:10311000FBCF823411F484E103C0853421F485E0CF -:103120000E9448874FC18535D1F40F941020082F95 -:103130000F941020802B082F10E00F941020182BD4 -:103140000F941020182B17FF04C0F52DF1605F2E8F -:1031500003C0852D8E7F582E000F111F31C186357B -:10316000A1F40F9410208D3459F40F9410200F9473 -:103170001020952D9170880F582E592A81E001C09A -:1031800083E00E94488780E0BFCF843609F0A7C063 -:103190000F941020E82E0F941020682E0F9410200A -:1031A000F82E0F941020712C762C66247E288F29FF -:1031B000682A0F941020CF5EDE4F8883C151D14022 -:1031C000FE0131967F014F0153010F941020F4014D -:1031D00081934F01F1E0AF1AB108B9F70F941B20AA -:1031E000CF5EDE4F8881C151D140853409F4FFCFD5 -:1031F0004801A12CB12CA52801151105B9F5842D84 -:1032000090E0002E02C0959587950A94E2F780FD24 -:103210002DC00F9455510F945E51C35FDE4F8882CD -:103220009982AA82BB82CD50D140459888ED0F94F7 -:103230004F51C15FDE4F8881CF50D1400F944F5125 -:10324000C25FDE4F8881CE50D1400F944F51C35F93 -:10325000DE4F8881CD50D1400F944F51459AC10126 -:10326000002E01C0880F0A94EAF7482A0F9455519E -:103270000F945E51C75FDE4F88829982AA82BB821B -:10328000C950D140459882E00F944F51C55FDE4F41 -:103290008881CB50D1400F944F51C65FDE4F88815B -:1032A000CA50D1400F944F51C75FDE4F8881C9503B -:1032B000D1400F944F516E0C7F1CE614F70431F08F -:1032C000F70181917F010F944F51F7CF459A0F94E9 -:1032D0005551459884E00F944F51459A73C08437F7 -:1032E00009F05AC04801A12CB12CA5280F94102038 -:1032F000782E0F941020E82E0F941020F82E0F94A3 -:1033000010202E2D30E0322F222737298F297901E6 -:10331000E82A0F9410200F941B200F945551CB5F77 -:10332000DE4F88829982AA82BB82C550D1404598DF -:1033300083E00F944F51C95FDE4F8881C750D14061 -:103340000F944F51CA5FDE4F8881C650D1400F9411 -:103350004F51CB5FDE4F8881C550D1400F944F5104 -:103360005601AE0CBF1C46018A149B0439F08FEF46 -:103370000F944F51F40181934F01F6CF459A5601B6 -:10338000C5018C199D098E159F05E0F4F501819109 -:103390005F010F940720F4CF853751F40F941B2061 -:1033A0008EE10F94072088E90F94072081E0ACCECE -:1033B000813531F4F8E1F093600088E0809360009B -:1033C0000F941B2080E10F9407208CCECF5EDE4F40 -:1033D0000FB6F894DEBF0FBECDBFDF91CF911F9126 -:1033E0000F91FF90EF90DF90CF90BF90AF909F90A4 -:1033F0008F907F906F905F904F903F902F900895A7 -:1034000060E080918E130F94DC8561E080918E13D3 -:103410000F94DC8560E080918E130F94DC858BE83F -:1034200091E00197F1F7089581E00F947F790D9471 -:103430004E32CF92DF92EF92FF920F931F93CF9372 -:10344000DF9395EDE92E96E0F92EC0E0D0E0082F4D -:1034500010E0670161E0F70181917F010F940A8616 -:10346000B8010C2E02C0759567950A94E2F7617059 -:10347000F60180810F94DC852196C430D10549F78F -:10348000DF91CF911F910F91FF90EF90DF90CF9040 -:10349000B7CFCF92DF92EF92FF920F931F93CF930C -:1034A000DF93182F80918F130F94DC8580918D13FB -:1034B0008F3F19F060E00F94DC8580919213C12F4B -:1034C000D0E084FF27C035EDE32E36E0F32E00E098 -:1034D00010E0670161E0F70181917F010F940A8696 -:1034E000BE01002E02C0759567950A94E2F76170DF -:1034F000F60180810F94DC850F5F1F4F08301105A6 -:1035000041F7DF91CF911F910F91FF90EF90DF90E6 -:10351000CF9076CFCE0124E0959587952A95E1F757 -:1035200088DF812FDF91CF911F910F91FF90EF9056 -:10353000DF90CF907ECF60E0ACCF982F8A3071F4CF -:1035400080919013843018F08FEF809390136091E6 -:1035500090136F5F80E00F946E3220C1E09184136E -:10356000E11104C08B3109F017C11BC0E230C8F073 -:10357000F0E0EC57FC4E80838091851320ED290FFD -:103580002A3060F421E030E00090841302C0220F62 -:10359000331F0A94E2F78160822B01C08E7F8093F3 -:1035A00085134091841381E0840F8093841350E04D -:1035B0004830510508F0EDC0FA018827EE58FF4F5A -:1035C0008F4F0D94D0B89B3109F0E3C0E7C0109243 -:1035D00085139B3509F0DDC0E1C0923309F4DEC0EC -:1035E0009F3309F4DBC08091851370C080918613EE -:1035F000823331F08F3359F4923309F0CAC0CEC010 -:103600009A3429F40F941D3710929013C2C0809100 -:10361000851382FFBEC09B3309F058C0BFC08091A4 -:1036200086138F3349F480918713823309F0B1C038 -:10363000953309F0AEC0B2C08091851382FFA9C056 -:10364000209187132B3311F480FDA8C083FFA1C004 -:103650009B3309F09EC0A2C0609186136F33F9F4CA -:1036600080918713823309F094C080918813853349 -:1036700009F08FC0983651F09C3609F08AC08091CD -:103680008C138D7F80938C13886007C080918C137E -:10369000982F926090938C138A604DDF7AC080914E -:1036A000851382FF76C0209187132B3341F484FF6A -:1036B00006C0983459F46053809188133CC083FF4E -:1036C00068C0909188139B3309F063C080FF61C08C -:1036D00065C02091851322FF5CC0809187138B33D6 -:1036E000A1F4322F3073303381F4983471F4609147 -:1036F0008613605380918813880F8056982F990FF6 -:10370000990F890F9091891340C023FF42C03091D7 -:1037100088133B33F1F525FF3CC0983471F4609178 -:103720008613660F6056962F990F990F690F805375 -:10373000680F8091891380532AC020FF2AC02EC0B1 -:1037400080918513282F2C702C3019F52091881327 -:103750002B33F9F480768036E1F49834D1F460911B -:103760008613660F6056862F880F880F680F80912A -:1037700087138053680F80918913880F8056982F84 -:10378000990F990F890F90918A139053890F0F9475 -:103790006E321092841302C061E07BDE81E00895F6 -:1037A000CCDE80E090E008951092BE198091041064 -:1037B0008B7F80930410089520914002222359F1B9 -:1037C000FC01808D83FF03C0719561957109809123 -:1037D000F30D9091F40D680F791F7093F40D6093C1 -:1037E000F30D8091F50D9091F60D6817790734F47B -:1037F000919581959109861797076CF08091030147 -:1038000084FF04C0809105018F7E03C08091050173 -:103810008061809305010895809140028823C9F05A -:10382000809141028823A9F08091510D882389F06D -:1038300080917B13811104C08EE491E20F94BBADA3 -:1038400010924A0D1092510D81E08093280210923F -:10385000420D0895CF93C82F811101C0DDDFC093C1 -:1038600041026C2F87E09FE0CF910D9475B31092C9 -:10387000400260E087E69FE00F9475B31092420229 -:1038800008951F920F920FB60F9211240BB60F924C -:103890001F932F933F934F935F936F937F938F93D8 -:1038A0009F93AF93BF93CF93DF93EF93FF93909149 -:1038B000030180910707892784FFFAC080910301E3 -:1038C000809307078091540D8111F2C081E08093AD -:1038D000540DC091F30DD091F40D1092F40D10928F -:1038E000F30D78941091420D8091410D882311F0D1 -:1038F000C2DA01C08BDA811110C0B9DF81E0809398 -:103900007A131F928F938FE890E29F938F930F9477 -:1039100093AD0F900F900F900F908091C7199091D9 -:10392000C8191C161D060CF0AEC097FF08C02091E8 -:10393000420D222311F02E5F21C021E01FC000970D -:1039400031F02091420D2223D9F0215017C020914F -:10395000520D3091530D1216130624F42091420D8E -:10396000222371F02091F50D3091F60D35952795B4 -:103970002C173D072CF42091420D2F5F2093420D10 -:103980002091410D222309F47EC02091400D222375 -:1039900031F021502093400D1092420D74C02091BF -:1039A000F50D3091F60D40913B0D6091390D709100 -:1039B0003A0DC217D30769F518161906A4F4209119 -:1039C0003E0D30913F0D8217930784F4280F391F65 -:1039D00037FF02C02F5F3F4F3595279530933F0D3E -:1039E00020933E0D03C0009709F058C020913C0D74 -:1039F00030913D0D2817390764F4280F391F37FF20 -:103A000002C02F5F3F4F3595279530933D0D209392 -:103A10003C0D4F5F40933B0DC60FD71FD0933A0D1F -:103A2000C093390D1816190654F42091370D3091B2 -:103A3000380D280F391F3093380D2093370D4091E2 -:103A4000420D141770F4242F30E0211B31096091CE -:103A5000350D7091360D260F371F3093360D20939C -:103A6000350D2091340D241710F44093340D4091FE -:103A7000CA192091320D3091330D240F311D30932E -:103A8000330D2093320D9093530D8093520D10926D -:103A9000C8191092C7191092540D0AC04F5F409375 -:103AA0003B0DC60FD71FD0933A0DC093390DC7CF2A -:103AB000FF91EF91DF91CF91BF91AF919F918F9146 -:103AC0007F916F915F914F913F912F911F910F9037 -:103AD0000BBE0F900FBE0F901F9018958091400263 -:103AE000882309F445C080914102882309F440C02D -:103AF0008091510D81113CC089D9811114C0B7DE6C -:103B000081E080937A131092510D1F9283E08F937E -:103B10008FE890E29F938F930F9493AD0F900F9047 -:103B20000F900F90089580917B13811104C08DE157 -:103B300091E20F94BBAD8091C7199091C8199093F1 -:103B40004C0D80934B0D1092490D10924A0D0F941D -:103B5000258860934D0D70934E0D80934F0D90937B -:103B6000500D1092280281E08093510D1092420D69 -:103B700008950F931F93CF9380914002882309F4F7 -:103B80006CC080914102882309F467C0C091510D37 -:103B9000C11102C0A3DF73C00F94258800914D0DA1 -:103BA00010914E0D20914F0D3091500DDC01CB0145 -:103BB000801B910BA20BB30B4997A105B10508F42B -:103BC0004CC00F94258860934D0D70934E0D8093DB -:103BD0004F0D9093500D1AD9811112C048DE81E02B -:103BE00080937A131F9282E08F938FE890E29F93E5 -:103BF0008F930F9493AD0F900F900F900F902DC057 -:103C00004091C7195091C81980914B0D90914C0D5E -:103C10009A01281B390B8091490D2115310591F02E -:103C20003CF090914A0D290F20934A0D8D5F03C0FF -:103C3000823018F082508093490D50934C0D409380 -:103C40004B0D05C0882319F081508093490D809158 -:103C5000490D811104C010924A0DC0E010C08C3093 -:103C6000E0F380914A0D8531C0F380917B13882366 -:103C700019F081E80F946A24CFDD109241028C2F55 -:103C8000CF911F910F910895CF9380917B13811154 -:103C900030C04CD9C82F1F928F938CE790E29F932E -:103CA0008F930F9493AD0F900F900F900F90CC23A4 -:103CB00019F010927A1303C081E080937A1361E0C7 -:103CC000C11101C060E06093400281E0809328024E -:103CD0001092410D1092420D1092530D1092520D00 -:103CE00087E69FE00F9475B3809140028093420273 -:103CF0002CC01CD9C82F1F928F9389E690E29F9306 -:103D00008F930F9493AD0F900F900F900F90CC2343 -:103D100019F010927A1303C081E080937A13C1E006 -:103D2000C093400281E096DD109241021092410D55 -:103D30001092420D1092530D1092520D61E087E6E1 -:103D40009FE00F9475B3C093420280914002CF91DF -:103D50000895CF93DF93EAD8C82F1F928F9386E5FB -:103D600090E29F938F930F9493AD87E69FE00F941B -:103D700063B3D82F87E09FE00F9463B391E00F9077 -:103D80000F900F900F90811101C090E0909341022D -:103D900085ED9EE00F9463B391E0813009F090E0EF -:103DA0009093310D2AE037ED43E25FE36091891093 -:103DB00070918A1080918B1090918C100F94F5A7C0 -:103DC0000F944EB57093F60D6093F50DC11104C0BC -:103DD00081E080937A1306C010927A13DD2311F0EC -:103DE00053DF01C044DD80914002811103C088E3AC -:103DF00090E202C082E490E29F938F938AE490E283 -:103E00009F938F930F9493AD0F900F900F900F90FF -:103E1000DF91CF91089584E190E29F938F930F9467 -:103E200093AD81E0809328021092420D0F900F9085 -:103E300080913F0E882329F060E070E0CB010C9464 -:103E4000DBE6089587EF9FE19F938F930F9493ADE7 -:103E50000F900F9080913F0E811107C020E030E05D -:103E6000A901CA01B9010C945CE80895FC018081A4 -:103E700091818436910524F164E670E00F94A1B835 -:103E8000CB012AE030E0B9010F94A1B8805D8093A6 -:103E9000B31980819181B9010F94A1B8CB01B90107 -:103EA0000F94A1B8805D8093B41980819181B9018C -:103EB0000F94A1B8805D8093B5191092B6191FC0F8 -:103EC0008A3091059CF02AE030E0B9010F94A1B846 -:103ED000605D6093B31980819181B9010F94A1B89D -:103EE000805D8093B4191092B51909C06AE070E042 -:103EF0000F94A1B8805D8093B3191092B41983EB2D -:103F000099E10895FC012081318137FF07C08DE2DE -:103F10008093B31931952195310914C024363105A8 -:103F200074F0C90164E670E00F94A1B8CB016AE0B7 -:103F300070E00F94A1B8805D8093B31906C080E251 -:103F40008093B3192A30310564F0EAE0F0E0C9014A -:103F5000BF010F94A1B8CB01BF010F94A1B8805D40 -:103F600001C080E28093B419C9016AE070E00F9447 -:103F7000A1B8805D8093B5191092B61983EB99E1D1 -:103F800008958F929F92AF92BF92CF92DF92EF925D -:103F9000FF92CF9320E030E048EC52E4FC016081D6 -:103FA0007181828193810F94F5A70F944EB54B01D7 -:103FB0005C0197FD12C020E137E240E050E00F9431 -:103FC000B4B8CA01B9012AE030E040E050E00F94F3 -:103FD000B4B8605D6093B31903C08DE28093B319E8 -:103FE000640197FE04C0CC24DD24C818D9080D2C28 -:103FF000000CEE08FF08C701B60128EE33E040E0F0 -:1040000050E00F94B4B88AE0882E912CA12CB12CEA -:10401000CA01B901A50194010F94B4B8605D609321 -:10402000B419C701B60124E630E040E050E00F9437 -:10403000B4B8CA01B901A50194010F94B4B8605D88 -:104040006093B5198EE28093B619C701B601A50138 -:1040500094010F94B4B8C62FCA01B901A501940107 -:104060000F94B4B8605D6093B719C05DC093B81980 -:104070001092B91983EB99E1CF91FF90EF90DF9007 -:10408000CF90BF90AF909F908F900895CF93DF9384 -:104090001F921F92CDB7DEB7FC01608171818281D2 -:1040A00093810F944EB57A836983CE0101962ADFFE -:1040B0000F900F90DF91CF9108950E94F030809182 -:1040C0009713811102C00E943CDC1092971308954F -:1040D000CF939C014091871550918815809195133D -:1040E000909196134817590739F4E0919813F0917D -:1040F00099131E161F06A4F1C62FFC01E20FF31F31 -:10410000BF0163597F4F8417950728F481E0461754 -:10411000570738F525C06E3E714000F13496EE3EEB -:10412000F14018F449365105C8F423593F4F42175E -:104130005307B0F04DEE51E0481B590B60E070E0C2 -:1041400086569C4E0F940EB9CC2309F0F894109229 -:10415000961310929513CC2309F0789481E001C056 -:1041600080E0CF91089520919813309199132115F3 -:104170003105A9F1809187159091881540E050E0B4 -:10418000FC01E656FC4EA081A23021F461817281CF -:10419000460F571F2150310929F1FC01E356FC4E0F -:1041A000CF018A599341A191A111FACF01968D3E79 -:1041B000E1E09E0738F4FC01E656FC4EE081EE2378 -:1041C000A9F3DECF8D3EE1E09E07D1F6EAE9F3E107 -:1041D000CF018A599341A191AA23D1F3D1CF80E095 -:1041E00090E00895CA0108952F923F924F925F92F6 -:1041F0006F927F928F929F92AF92BF92CF92DF92F7 -:10420000EF92FF920F931F93CF93DF93CDB7DEB75B -:104210006E970FB6F894DEBF0FBECDBF61E08FE59D -:1042200090E056DF882309F48CC42091F10D309181 -:10423000F20D8091EF0D9091F00D821B930B8F7713 -:1042400099278F379105A1F43093F00D2093EF0D4E -:10425000E8EEFFE184918F01882339F00E946EAD72 -:104260000F5F1F4FF8018491F7CF8AE00E946EAD77 -:1042700009E811E244E2F42E8091EF0D9091F00DE7 -:104280002091F10D3091F20D821B930B8F779927BE -:10429000892B09F4BDC180913F0E8111B9C10E94E3 -:1042A000CAACE82E0F94258860936016709361164F -:1042B00080936216909363160F942588E7FCDCCFF9 -:1042C0002091931330919413FAE0EF1639F04DE0FA -:1042D000E41621F02F3531050CF47FC1211531058D -:1042E00019F41092480D2DC4C0909513D0909613D8 -:1042F000C601039626563C4EF901E80FF91F1082BD -:104300002091480D21114FC11092440D1092450D7E -:104310001092460D1092470DFC01E656FC4E5F01CF -:1043200067E773E0CF010F946BB9892B09F07DC06B -:10433000F50180818E3409F078C04AE050E060E0F9 -:1043400070E0C60182569C4E0F941DAA6093440DE6 -:104350007093450D8093460D9093470D80902D0DE1 -:1043600090902E0DA0902F0DB090300D24013501AE -:10437000FFEF4F1A5F0A6F0A7F0AC0909513D09023 -:104380009613641575058605970509F4E6C163EE75 -:104390007FE1C60183569C4E0F948EAC892B09F0A9 -:1043A000DCC1E4E7FEE584918F01882339F00E94A7 -:1043B0006EAD0F5F1F4FF8018491F7CFEAEEF0E288 -:1043C00084918F01882339F00E946EAD0F5F1F4FDB -:1043D000F8018491F7CFC501B4010E94F7AD8AE0DE -:1043E0000E946EAD0F94DF121092941310929313EB -:1043F000A8C3E0912B0DF0912C0D1082E091951344 -:10440000F0919613E656FC4EF3828091440D909104 -:10441000450DA091460DB091470D80932D0D9093C1 -:104420002E0DA0932F0DB093300D80919513909188 -:1044300096139C0123563C4E6901F90180818E340C -:1044400061F1843251F16AE270E0C9010F9433B92D -:10445000892B19F1E4E7FEE584918F01882339F077 -:104460000E946EAD0F5F1F4FF8018491F7CFE0EC13 -:10447000F0E284918F01811109C060912D0D70913E -:104480002E0D80912F0D9091300DA7CF0E946EAD13 -:104490000F5F1F4FF8018491EECF67E470E0C60113 -:1044A0000F9433B990932C0D80932B0D009791F1BD -:1044B00020918016211109C02AE030E030933E0798 -:1044C00020933D0721E020933C0720915E0F22239B -:1044D00009F14AE050E060E070E001960F941DAAF7 -:1044E00064307105B8F4F801849139E8C32E31E2E3 -:1044F000D32E882341F00E946EADFFEFCF1ADF0A62 -:10450000F6018491F6CF8AE00E946EAD8FE791E2CA -:104510000F94EE51C0909513D090961396012356A8 -:104520003C4E590169E175E0C9010F943EB9892BF0 -:1045300029F462E088E094E00F940A0E8091440D23 -:104540009091450DA091460DB091470D892B8A2B76 -:104550008B2B11F086E001C081E0F601E656FC4E9F -:104560008083F50101900020E9F73197EA19FB09F2 -:1045700034E0C30ED11CEC0DFD1DED3E41E0F4070F -:1045800029F0F0939613E093951304C010929613BC -:10459000109295138091981390919913019690938E -:1045A00099138093981310929413109293138091FF -:1045B000EF0D9091F00D2091F10D3091F20D821BD5 -:1045C000930B8F779927892B09F4BBC261E08FE5A4 -:1045D00090E07EDD811150CEB4C25BE3E51203C0F2 -:1045E00081E08093480D8091480D811145CEC9012D -:1045F00001969093941380939313809195139091C7 -:10460000961386569C4EFC01E20FF31FE38234CED4 -:104610008091C80F882309F461C00F942588009108 -:104620006016109161162091621630916316DC01BC -:10463000CB01801B910BA20BB30B81329340A105E0 -:10464000B10508F44BC08091931390919413181600 -:1046500019060CF043C040919513509196139A019E -:104660002D5F3F4F86569C4EDC01A20FB31F1C925C -:10467000D901A656BC4EFD0101900020E9F7319703 -:10468000EA1BFB0B4C5F5F4FE40FF51FED3E21E093 -:10469000F20729F0F0939613E093951304C010925B -:1046A00096131092951380919813909199130196F7 -:1046B00090939913809398131092941310929313DC -:1046C000EAEDFFE184918F01882309F43AC20E9448 -:1046D0006EAD0F5F1F4FF8018491F6CF8091801669 -:1046E000882309F42EC28091931390919413892BFF -:1046F00009F027C28091981390919913892B11F496 -:104700001092430D02E08CE3482E512C612C712C49 -:1047100090E8892E9EEE992E96E3A92EB12C24E0E6 -:10472000222E312C40915B1950915C1960915D19DA -:1047300070915E198091531990915419A091551957 -:10474000B0915619481759076A077B0708F0F9C155 -:104750008091430D8111F5C15BC0960123563C4EFB -:1047600069016AE270E0C9010F9433B990932C0D8E -:1047700080932B0D0097D9F4E4E7FEE584918F0137 -:10478000882339F00E946EAD0F5F1F4FF8018491AE -:10479000F7CFEFEFF1E284918F01882309F41BCE6C -:1047A0000E946EAD0F5F1F4FF8018491F6CFF601A6 -:1047B000E12CE817F90719F02191E226FACF4AE037 -:1047C00050E060E070E0CF0101960F941DAA2E2DFD -:1047D00030E02617370709F40CCEE4E7FEE58491B4 -:1047E0008F01882339F00E946EAD0F5F1F4FF801D3 -:1047F0008491F7CFE9E2F2E284918F01882309F4F2 -:104800003CCE0E946EAD0F5F1F4FF8018491F6CF32 -:104810008091AE189091AF18A091B018B091B118D6 -:1048200080935B1990935C19A0935D19B0935E1906 -:1048300086EA98E10E9435E3182F8A30B1F01D30E6 -:10484000A1F0133211F01A3321F42091480D2223E4 -:1048500061F020919313309194132F3531052CF48E -:104860008F3FFFEF9F0709F050C140915B195091B6 -:104870005C1960915D1970915E1980915319909146 -:104880005419A0915519B0915619481759076A073C -:104890007B0708F4B4C0EDEAF0E284916F0188234D -:1048A00041F00E946EADFFEFCF1ADF0AF60184914E -:1048B000F6CF8AE00E946EAD0F942588C090500E0E -:1048C000D090510EE090520EF090530EDC01CB01CF -:1048D0008C199D09AE09BF09C0904C0ED0904D0EA9 -:1048E000E0904E0EF0904F0E9C01AD012C193D0949 -:1048F0004E095F0969017A0110924C0E10924D0E1B -:1049000010924E0E10924F0ECA01B90128EE33E0FC -:1049100040E050E00F94B3B36091480E7091490E9F -:1049200080914A0E90914B0E0F943E0DC701B60137 -:1049300020E63AEE40E050E00F94B3B3CA01B9016B -:10494000A30192010F94B3B37F936F93C701B60194 -:10495000A50194010F94B3B33F932F9346EC5FE10D -:104960005F934F93E1E0F0E0EC0FFD1FFF93EF93B7 -:104970000F94ECADE6E9FEE584910FB6F894DEBF46 -:104980000FBECDBF6F01811105C0AE014F5F5F4FFC -:104990006A0108C00E946EAD5FEFC51AD50AF60124 -:1049A0008491F1CFF60181916F01882319F00E9463 -:1049B0006EADF8CF8AE00E946EADCE0101960F94E5 -:1049C00060530F94634610925F198091811688237B -:1049D00019F00F940E7A06C00F94BB48809181168F -:1049E0008111F7CF8091C80F882349F060E086E0FD -:1049F00090E00F94BE023092021020920110133208 -:104A000019F481E08093430D809193139091941356 -:104A1000009719F41092480D85CE2091A9182223F1 -:104A200049F040915B1950915C1960915D1970914A -:104A30005E1903C040E050E0BA012091270D30918B -:104A4000280DE1E0F0E0E21BF30B9F01240F351F7E -:104A5000A0919513B0919613FD01E656FC4E00838C -:104A600021833283A356BC4EFD01E80FF91F10824B -:104A7000FD0101900020E9F73197EA1BFB0BF89448 -:104A80008091981390919913019690939913809324 -:104A90009813EC5F80919513909196138E0F911D52 -:104AA00090939613809395132091A918222349F08F -:104AB00040915B1950915C1960915D1970915E197C -:104AC00003C040E050E0BA014F5F5F4F6F4F7F4F30 -:104AD0004093270D5093280D6093290D70932A0D54 -:104AE0008D3E914021F41092961310929513789474 -:104AF0001092480D109294131092931361E08FE579 -:104B000090E0E6DA81110ECE1CC01B3321F481E067 -:104B10008093480D07CE4091480D411103CEA90165 -:104B20004F5F5F4F509394134093931340919513AD -:104B30005091961346565C4EFA01E20FF31F8383A1 -:104B4000F1CD6E960FB6F894DEBF0FBECDBFDF91EC -:104B5000CF911F910F91FF90EF90DF90CF90BF907A -:104B6000AF909F908F907F906F905F904F903F900D -:104B70002F90089510922102409172135091731357 -:104B8000609174137091751340937E0250937F026D -:104B90006093800270938102909344028093430259 -:104BA0000F9425886093FF0E7093000F8093010F80 -:104BB0009093020F08951F93CF93DF93182F809146 -:104BC0007E0290917F02A0918002B0918102809339 -:104BD000721390937313A0937413B0937513C091D1 -:104BE0004302D091440284E690E090934402809383 -:104BF00043020F9425886093FF0E7093000F8093FB -:104C0000010F9093020F10932102CE01DF91CF91FB -:104C10001F91089580E1E5E3F0E1A9ECBFE0019088 -:104C20000D928A95E1F708952F923F924F925F92ED -:104C30006F927F928F929F92AF92BF92CF92DF92AC -:104C4000EF92FF920F931F93CF93DF931F92CDB7F5 -:104C5000DEB70F941D374CE35DE261E080E00F9416 -:104C6000123780912102898381E080932102E6E45A -:104C7000FDE54490552441940CF4509484E00F9445 -:104C8000FF3710923D1010923E1010923F1010927C -:104C900040102091391030913A1040913B105091C2 -:104CA0003C10E5E3F0E16081718182819381E12C28 -:104CB000F12C87010F94BA59ADDFE0E4FDE5659171 -:104CC0007591859194912DEC3CEC4CE85FE30F9449 -:104CD000F5A76B017C01B201052C000C880B990B28 -:104CE0000F948EAE9B01AC01C701B6010F94F5A7DE -:104CF00029EC622E2FE0722EF3012085318542854A -:104D000053850F94EFB37B018C01F30160877187AA -:104D10008287938780E090E0A8E4B4E480937E02E9 -:104D200090937F02A0938002B09381022481358109 -:104D3000468157816081718182819381EEEF2E2EB1 -:104D4000ECE03E2E3F922F92F5E58F2E982CA82C6A -:104D5000F1E4BF2EA5EDCA2EAFE0DA2E0E945187F6 -:104D60000F9498830F9464371092210210923D1093 -:104D700010923E1010923F10109240102091391066 -:104D800030913A1040913B1050913C10E5E3F0E136 -:104D90006081718182819381E12CF12C87010F94D4 -:104DA000BA5938DF8AE0849DB001859D700D1124C9 -:104DB000072E000C880B990B0F948EAEF301208503 -:104DC0003185428553850F94EFB37B018C01F3014C -:104DD000608771878287938780E090E0A8ECB3E4D6 -:104DE00080937E0290937F02A0938002B093810211 -:104DF00024813581468157816081718182819381CF -:104E00003F922F92B5E58B2E982CB5EDAB2EB0E4EA -:104E1000BB2E0E9451870F949883F981F093210251 -:104E200080E090E0A4E5B3E480933D1090933E10C1 -:104E3000A0933F10B09340102091391030913A1058 -:104E400040913B1050913C10E5E3F0E160817181AD -:104E500082819381E12CF12C04E513E40F94BA597B -:104E600081E00F900F900F900F900F90DF91CF91F6 -:104E70001F910F91FF90EF90DF90CF90BF90AF9078 -:104E80009F908F907F906F905F904F903F902F906A -:104E90000895CF92DF92EF92FF920F931F93CF93DB -:104EA000DF93EC01CC0FDD1FCC0FDD1FFE01EE53B5 -:104EB000FC4D2591359145915491FE01EF52FF4EE5 -:104EC000C080D180E280F3808E010B5C1F4EC70151 -:104ED000B6010F94EFB3F8016083718382839383EB -:104EE000FE01EA54FC4D25913591459154918E0176 -:104EF0000A591D4FC701B6010F94EFB3F801608343 -:104F0000718382839383FE01E655FC4D2591359193 -:104F100045915491C65ADD4FC701B6010F94EFB3C6 -:104F2000688379838A839B83DF91CF911F910F914F -:104F3000FF90EF90DF90CF90089510920C021092A6 -:104F4000390760E089E69FE00F9475B310920B0279 -:104F500008952091871530918815BC01C9018356A9 -:104F60009C4E0F946BB99C0190932C0D80932B0D4C -:104F700081E0232B09F480E00895FC0123812111B5 -:104F80000C94CAE308953F924F925F926F927F9282 -:104F90008F929F92AF92BF92CF92DF92EF92FF9249 -:104FA0000F931F93CF93DF9330904D11332009F46B -:104FB00080C08B01EC0131FE54C088809980AA80AA -:104FC000BB80FB01C080D180E280F380209145113D -:104FD000309146114091471150914811C501B401DB -:104FE0000F94F5A72B013C012091491130914A11F2 -:104FF00040914B1150914C11C701B6010F94F5A788 -:105000009B01AC01C301B2010F94EFB32B013C0132 -:1050100020913D1130913E1140913F11509140112E -:10502000C501B4010F94F5A74B015C01209141111A -:10503000309142114091431150914411C701B60182 -:105040000F94F5A79B01AC01C501B4010F94EFB318 -:10505000688379838A839B83F801408251826282CC -:10506000738230FE26C02091351130913611409167 -:10507000371150913811688179818A819B810F9411 -:10508000EFB3688379838A839B83209139113091B0 -:105090003A1140913B1150913C11F80160817181AE -:1050A000828193810F94EFB3F801608371838283CF -:1050B0009383DF91CF911F910F91FF90EF90DF903D -:1050C000CF90BF90AF909F908F907F906F905F90A8 -:1050D0004F903F9008952F923F924F925F926F9220 -:1050E0007F928F929F92AF92BF92CF92DF92EF9278 -:1050F000FF921F93CF93DF93CDB7DEB72A970FB6FA -:10510000F894DEBF0FBECDBF9A8789871B01FC01D3 -:1051100080819181A281B38189839A83AB83BC838F -:10512000FB0180819181A281B3818D839E83AF83B6 -:10513000B887BE016B5F7F4FCE01019624DF20E070 -:1051400030E0A90169817A818B819C810F9488AEBE -:1051500087FF06C019821A821B821C8211E001C0DF -:1051600010E020E030E040E850EC6D817E818F81DE -:1051700098850F9488AE87FF09C080E090E0A0E892 -:10518000B0EC8D839E83AF83B88711E020E030E0E0 -:105190004FE753E469817A818B819C810F943AB601 -:1051A00018164CF480E090E0AFE7B3E489839A836B -:1051B000AB83BC8311E020E030E844E553E46D812B -:1051C0007E818F8198850F943AB618164CF480E052 -:1051D00090E8A4E5B3E48D839E83AF83B88703C0D2 -:1051E000112309F484C0CD80DE80EF80F8848980AB -:1051F0009A80AB80BC8070904D1171100CC0E98515 -:10520000FA8580829182A282B382F101C082D1822A -:10521000E282F3826BC070FE1CC020913511309188 -:1052200036114091371150913811C501B4010F94D6 -:10523000EEB34B015C012091391130913A1140914C -:105240003B1150913C11C701B6010F94EEB36B01B5 -:105250007C0171FE4BC02091040D3091050D4091F1 -:10526000060D5091070DC501B4010F94F5A72B0150 -:105270003C012091080D3091090D40910A0D50918B -:105280000B0DC701B6010F94F5A79B01AC01C3013B -:10529000B2010F94EFB3E985FA856083718382834D -:1052A000938320910C0D30910D0D40910E0D509176 -:1052B0000F0DC501B4010F94F5A74B015C012091BE -:1052C000100D3091110D4091120D5091130DC70129 -:1052D000B6010F94F5A79B01AC01C501B4010F9471 -:1052E000EFB3F101608371838283938311E0812F97 -:1052F0002A960FB6F894DEBF0FBECDBFDF91CF91D7 -:105300001F91FF90EF90DF90CF90BF90AF909F9054 -:105310008F907F906F905F904F903F902F90089567 -:1053200086EA9FE00F9463B391E0811101C090E0A1 -:10533000892F0895682F87EF9FE00D9475B34F92E2 -:105340005F926F927F928F929F92AF92BF92CF9215 -:10535000DF92EF92FF920F931F93CF93DF93C82FAB -:105360000F941D37C23009F49FC02CF4CC23D9F020 -:10537000C13079F1FAC2C33009F4F9C0C43009F080 -:10538000F4C20F941D3760E080E00F946E3288E61F -:1053900094E00F941031C1E1D2E007EA1FE0C12C84 -:1053A000D12C76015AC18091010790910207029792 -:1053B00040F49FB7F89480910201846080930201C9 -:1053C0009FBF2FEF81EE94E0215080409040E1F7A5 -:1053D000C3C08091010790910207029740F49FB7E4 -:1053E000F894809102018460809302019FBFEFEFE7 -:1053F000F1EE24E0E150F0402040E1F700C0000071 -:105400009FB7F894809102018B7F809302019FBF28 -:1054100040E050E0BA018DEE9FE00F9487B340E08A -:1054200050E0BA0181EF9FE00F9487B360E086E619 -:105430009FE00F9475B360E088E69FE00F9475B32A -:1054400060E085E69FE00F9475B360E084E69FE03E -:105450000F9475B360E070E085E09FE00F948FB328 -:1054600060E070E083E09FE00F948FB360E070E055 -:1054700081E09FE00F948FB360E070E08FEF9EE0DB -:105480000F948FB3DF91CF911F910F91FF90EF9009 -:10549000DF90CF90BF90AF909F908F907F906F9054 -:1054A0005F904F900C94D5F980EF44DF61E08FE579 -:1054B0009FE00F9493B310922A071092290710923D -:1054C000C80F60E084EC9FE00F9475B369E277E069 -:1054D00081EC9FE00E94B8FD40E050E0BA018DEE03 -:1054E0009FE00F9487B340E050E0BA0181EF9FE066 -:1054F0000F9487B360E070E085E09FE00F948FB376 -:1055000060E070E083E09FE00F948FB360E070E0B4 -:1055100081E09FE00F948FB360E070E08FEF9EE03A -:105520000F948FB30E94449E81E00E942A9C809138 -:10553000010790910207029740F49FB7F894809179 -:1055400002018460809302019FBF8FEF91EEE4E03F -:1055500081509040E040E1F700C000009FB7F89410 -:10556000809102018B7F809302019FBFFEC18CE975 -:1055700093E20F9495314BE853E262E081E00F949F -:1055800012378091010790910207029740F49FB76C -:10559000F894809102018460809302019FBFFFEF25 -:1055A00021EE84E0F15020408040E1F700C000008F -:1055B0009FB7F894809102018B7F809302019FBF77 -:1055C00010925E0D10925D0D44E853E263E083E0BB -:1055D0000F94123763E083E00F946E3260915D0D9B -:1055E00070915E0D072E000C880B990B0F94F5300F -:1055F000C0E0D0E009E210E06FEFCE010F9475B388 -:10560000CE01B8010F94A1B8892B09F580915D0DE9 -:1056100090915E0D019690935E0D80935D0D4DE728 -:1056200053E263E083E00F94123763E083E00F946A -:105630006E3260915D0D70915E0D072E000C880B2F -:10564000990B0F94F5308BE793E20F9495312196E7 -:10565000C11590E1D90781F688C16C2D81E00F94C6 -:105660006E328EE195E00F941031C701B6010F94B0 -:10567000F53088E295E00F941031BE01C8010E9418 -:105680009EFD68817981229660537109072E000C76 -:10569000880B990B0F94F530EFEFCE1ADE0AEE0A65 -:1056A000FE0A0E5F1F4FF4E0CF16D104E104F104AF -:1056B000A1F6C091BD190C2E000CDD0B00E010E02E -:1056C0000F94BC7D81E00F94680E8091BD19082E67 -:1056D000000C990B9E01281B390B37FF03C0319535 -:1056E00021953109233031050CF44DC08C179D07ED -:1056F00014F401501109C817D90734F40F5F1F4F74 -:10570000043011056CF00AC0043011053CF40F3F61 -:105710002FEF120729F400E010E002C003E010E0D0 -:1057200060E080E00F946E3289E596E00F941031CE -:1057300061E080E00F946E3289E596E00F941031BD -:1057400062E080E00F946E3289E596E00F941031AC -:1057500063E080E00F946E3289E596E00F9410319B -:10576000602F80E00F946E3288E694E00F94103141 -:10577000C091BD190C2E000CDD0B64E670E080E0DA -:1057800090E00F940D870F946B30882309F498CF25 -:105790000F941D374801012E000CAA08BB086801B0 -:1057A000CC0CDD1CC6018F5E9D4F3C017C010F942B -:1057B000BC7D81E00F94680E61E081E00F946E3251 -:1057C0008EE195E00F941031C501B4010F94F530CE -:1057D00088E295E00F94103161E08DE00F946E3215 -:1057E000F3016081718160537109072E000C880BF1 -:1057F000990B0F94F5308091BD19082E000C990B70 -:105800009E01281B390B37FF03C0319521953109C3 -:10581000233031050CF43FC08C179D07D4F4F701F9 -:105820008081918101979183808361E08DE00F9465 -:105830006E32F7016081718160537109072E000C8F -:10584000880B990B0F94F530C091BD190C2E000CEC -:10585000DD0B8091BD19082E000C990BC817D907D4 -:10586000D4F4F7018081918101969183808361E076 -:105870008DE00F946E32F701608171816053710980 -:10588000072E000C880B990B0F94F530C091BD19B1 -:105890000C2E000CDD0B64E670E080E090E00F94CD -:1058A0000D870F946B30882309F481CFB6016F5EAA -:1058B0007D4FC6018955904F0E94B8FD40E061E0E0 -:1058C0008DE593E20F94A007882309F44EC081E090 -:1058D0000F9427370F941D37C091BD190C2E000C63 -:1058E000DD0B602F80E00F946E3288E694E00F9419 -:1058F000103181E1E82E82E0F82E97EAC92E9FE070 -:10590000D92E412C512C3201642D81E00F946E323E -:105910008EE195E00F941031C301B2010F94F53080 -:1059200088E295E00F941031B701C6010E949EFDF8 -:10593000F70160817181F2E0EF0EF11C6053710993 -:10594000072E000C880B990B0F94F5302FEF421A9D -:10595000520A620A720A82E0C80ED11C94E049160B -:1059600051046104710481F6ABCEDF91CF911F9198 -:105970000F91FF90EF90DF90CF90BF90AF909F90EE -:105980008F907F906F905F904F90089587EF9FE08A -:105990000D9463B32091F10D3091F20D8091EF0DD4 -:1059A0009091F00D8217930771F0F901E159F24FD0 -:1059B00080812F5F3F4F2F7733273093F20D209355 -:1059C000F10D90E008958FEF9FEF08951F920F92D1 -:1059D0000FB60F9211240BB60F922F933F934F9354 -:1059E0006F937F938F939F93EF93FF938091C80062 -:1059F00084FF03C08091CE001DC04091CE008091F5 -:105A00008B158130B9F42091EF0D3091F00DC90163 -:105A100001968F7799276091F10D7091F20D86179D -:105A2000970741F0F901E159F24F40839093F00D4F -:105A30008093EF0DFF91EF919F918F917F916F91E7 -:105A40004F913F912F910F900BBE0F900FBE0F9073 -:105A50001F9018951F920F920FB60F9211240BB63C -:105A60000F922F933F934F936F937F938F939F93B7 -:105A7000EF93FF938091C00084FF03C08091C60024 -:105A80001DC04091C60080918B15811117C02091D7 -:105A9000EF0D3091F00DC90101968F779927609134 -:105AA000F10D7091F20D8617970741F0F901E15958 -:105AB000F24F40839093F00D8093EF0DFF91EF91A3 -:105AC0009F918F917F916F914F913F912F910F9067 -:105AD0000BBE0F900FBE0F901F90189590918B15D5 -:105AE000911107C09091C00095FFFCCF8093C60034 -:105AF0000895913031F49091C80095FFFCCF8093C8 -:105B0000CE000895EBDF80E090E008958F929F92A1 -:105B1000AF92BF92CF92DF92EF92FF920F931F93BB -:105B2000CF93DF93CDB7DEB7A0970FB6F894DEBF63 -:105B30000FBECDBF6115710581059105A1F480E30C -:105B4000A0960FB6F894DEBF0FBECDBFDF91CF9108 -:105B50001F910F91FF90EF90DF90CF90BF90AF908B -:105B60009F908F90BBCF8E010F5F1F4FC12CD12C08 -:105B70007601842E912CA12CB12C2FEFC21AD20ABF -:105B8000E20AF20AA50194010F94B3B3F8016193FC -:105B90008F01B901CA01611571058105910569F788 -:105BA000F1E0CF1AD108E108F108FE01EC0DFD1D6E -:105BB00081818A3010F4805D01C0895C8FDFC1145F -:105BC000D104E104F10461F7A0960FB6F894DEBFAA -:105BD0000FBECDBFDF91CF911F910F91FF90EF903E -:105BE000DF90CF90BF90AF909F908F900895CF920D -:105BF000DF92EF92FF926B017C0197FF0AC08DE26A -:105C00006DDFF094E094D094C094C11CD11CE11CD1 -:105C1000F11C4AE0C701B601FF90EF90DF90CF90F2 -:105C200075CF8F929F92AF92BF92CF92DF92EF92F9 -:105C3000FF920F931F93CF93DF936B017C01C42FCF -:105C400020E030E0A9010F9488AE87FF06C08DE206 -:105C500045DFF7FAF094F7F8F094D0E060E070E0F8 -:105C600080E09FE3DC1741F020E030E040E251E4C7 -:105C70000F94DDB4DF5FF6CF9B01AC01C701B60125 -:105C80000F94EFB36B017C010F9454B54B015C0191 -:105C90004AE03CDFCC2381F107E115E0F801819176 -:105CA0008F01882311F01ADFF9CFC501B4010F94D9 -:105CB0008CAE9B01AC01C701B6010F94EEB320E09E -:105CC00030E040E251E40F94F5A74B015C010F94E2 -:105CD0004EB56B01770FEE08FF08C701B60187DFED -:105CE000C701B6010F948EAE9B01AC01C501B40192 -:105CF0000F94EEB3C15019F7DF91CF911F910F911F -:105D0000FF90EF90DF90CF90BF90AF909F908F90DB -:105D10000895CF92DF92EF92FF92CF93DF93EC0141 -:105D20006A017B01FE018491882319F0D7DE219658 -:105D3000F9CF42E0C701B601DF91CF91FF90EF901C -:105D4000DF90CF906ECF8DE0C9DE8AE0C7CECF93D3 -:105D5000DF93EC018991882311F0C0DEFBCFDF9146 -:105D6000CF91F1CFCF92DF92EF92FF920F931F93DB -:105D7000CF937C018B01C42FCC2319F16801F8016A -:105D800061918F01C7010F9475B3C7010F9463B37D -:105D9000C150F6019081891781F0E0E5F3E284912A -:105DA0008F01882331F09ADE0F5F1F4FF801849135 -:105DB000F8CF8AE093DE80E005C0FFEFEF1AFF0A1C -:105DC000DBCF81E0CF911F910F91FF90EF90DF909B -:105DD000CF900895CF93DF934CEB50E064E972E2EB -:105DE00089E790E10F942AAC0E9477BD0F944F820F -:105DF00080E090E0A0E8BFE380930002909301026E -:105E0000A0930202B09303020F94DA0CE6E9FEE5D8 -:105E10008491EF01882329F061DE2196FE018491AF -:105E2000F9CFE2E7F2E28491EF01882329F056DE10 -:105E30002196FE018491F9CF8AE0DF91CF914ECE79 -:105E40004F925F926F927F928F929F92AF92BF928A -:105E5000CF92DF92EF92FF920F931F93CF93DF9336 -:105E600000D01F92CDB7DEB78091E1029091E2029F -:105E7000A091E302B091E40289839A83AB83BC834F -:105E800004E110E045E0F42E59E7C52E50E1D52E8F -:105E9000FA94FF2049F0C8010F9463B3F60181938F -:105EA0006F010F5F1F4FF4CF43E050E069E770E1EF -:105EB000CE0101960F944EB9892B09F007C139E73D -:105EC000E32E30E1F32E04E110E0C8010F9463B338 -:105ED000F70181937F010F5F1F4F003D1105A9F767 -:105EE00020E030E040E251E46091C1107091C210B6 -:105EF0008091C3109091C4100F943AB6181664F4B0 -:105F000080E090E0A0E2B1E48093C1109093C210D1 -:105F1000A093C310B093C41020E030E040E251E4FD -:105F20006091C5107091C6108091C7109091C810F3 -:105F30000F943AB6181664F480E090E0A0E2B1E461 -:105F40008093C5109093C610A093C710B093C8104B -:105F50000F94DA0C09E710E1C80154E040E020E0BA -:105F600030E0F901E456FF4FE80FF91F60816F3F01 -:105F700009F041E02F5F3F4F2430310591F7FC01DC -:105F8000E455FF4FC080D180E280F380CF20CE2047 -:105F9000CD20C09409F041E0515004965111DFCF5B -:105FA000411110C040E150E060E373E285E191E10E -:105FB0000F942AAC40E150E060E473E285E291E1A5 -:105FC0000F942AAC85E1E82E81E1F82E94EC892E1D -:105FD00099E0992EA12CB12C20EC422E23E0522ED8 -:105FE000612C712C20E030E048E453E4F80164892E -:105FF0007589868997890F943AB618164CF480E013 -:1060000090E0A8E4B3E4F801848B958BA68BB78B62 -:1060100020E030E048EC52E4F70160817181828138 -:1060200093810F943AB618164CF480E090E0A8ECF7 -:10603000B2E4F70180839183A283B383F80184A142 -:1060400095A1A6A1B7A1853C9940A105B10528F06D -:10605000F80184A295A2A6A2B7A2F701808991892E -:10606000A289B389813C9340A105B10528F0F701CD -:10607000408A518A628A738A0C5F1F4FF4E0EF0EE8 -:10608000F11C20E10138120709F0ACCF0E9477BD66 -:106090000F944F82E6E9FEE584918F01882331F069 -:1060A0001DDD0F5F1F4FF8018491F8CFE8E5F2E2A4 -:1060B00084918F01882331F011DD0F5F1F4FF801AC -:1060C0008491F8CF8AE00ADD91E015C083DE84E197 -:1060D00090E00F9463B38F3F69F485E190E00F94F3 -:1060E00063B38F3F39F486E190E00F9463B391E09E -:1060F0008F3F09F090E0892F0F900F900F900F9035 -:10610000DF91CF911F910F91FF90EF90DF90CF9093 -:10611000BF90AF909F908F907F906F905F904F90C7 -:106120000895CF93DF936BE275E089E790E10F94D8 -:1061300047B94CEB69E770E184E190E013DE6FE270 -:1061400075E089E790E10F9447B944E069E770E1B1 -:1061500084E190E007DEE6E9FEE58491EF01882323 -:1061600029F0BCDC2196FE018491F9CFE8E4F2E24B -:106170008491EF01882329F0B1DC2196FE018491FE -:10618000F9CF8AE0DF91CF91A9CC80918B15811155 -:106190000EC08091C00087FF2EC08091C00084FF98 -:1061A00003C08091C60008954091C6000DC0809143 -:1061B000C80087FF20C08091C80084FF03C0809181 -:1061C000CE0008954091CE002091EF0D3091F00D5A -:1061D000C90101968F7799276091F10D7091F20DA9 -:1061E0008617970741F0F901E159F24F40839093E8 -:1061F000F00D8093EF0D08951F920F920FB60F923E -:1062000011240BB60F92CF92DF92EF92FF920F9371 -:106210001F932F933F934F935F936F937F938F932E -:106220009F93AF93BF93EF93FF93CF93DF9300D0F0 -:1062300000D0CDB7DEB78091050790910607892B76 -:1062400009F408C190912A0E80E020910507309151 -:106250000607232B81F0891771F0439A20910507D7 -:106260003091060721503109309306072093050726 -:106270008F5F4398EACF4091090190E02091280E6A -:106280003091290E46FD09C040913002413049F459 -:106290006901C81AD90AC6010BC0409130024130C9 -:1062A00019F4820F931F04C07901E81AF90AC70193 -:1062B0009093290E8093280E8091050790910607F0 -:1062C000892BB9F08091260E9091270E909389002A -:1062D000809388008091240E9091250E2091260EA7 -:1062E0003091270E821B930B9093250E8093240EE2 -:1062F00098C08091240E9091250E97FDABC090938D -:106300008900809388008DC009811A81B80180E0DE -:1063100090E04AE0FBDB17DD84E690E0A0E0B0E02F -:106320008093180E9093190EA0931A0EB0931B0E23 -:10633000E0916619F0916719DF01AF5ABF4FA701CD -:106340009601442755276D917D918D919C910F94D5 -:10635000A4B3DC01CB0161E1B695A795979587952C -:106360006A95D1F79093170E8093160E86A983FF36 -:1063700058C18089918996958795919581959109C4 -:106380009093130E8093120E90930F0E80930E0E27 -:1063900090930B0E80930A0E9093070E8093060E37 -:1063A0001092020E1092030E1092040E1092050E1F -:1063B000808D8093010E80FF64C180910B0181600C -:1063C00080930B018FEF80932D028091010E81FF4E -:1063D0005FC180910B018D7F80930B018FEF8093C4 -:1063E0002E028091010E82FF5AC180910B018460C0 -:1063F00080930B018FEF80932F028091010E83FF1A -:1064000055C18FEF80933002E0916619F0916719C2 -:10641000309709F054C180911807813011F00C9425 -:1064200026BB209188003091890080918400909152 -:10643000850040962817390710F00C94B1BC809164 -:106440008400909185004096909389008093880005 -:106450000C94B1BCE0916619F09167193097A1F6E0 -:10646000909100078091FF06981769F0E091FF0670 -:1064700007E5E09FF0011124EA57F84FDF01A55B23 -:10648000BF4F81E08C93F0936719E09366193097C2 -:1064900009F40EC11092290E1092280E809140022C -:1064A0008823E9F08091F30D9091F40D18161906E8 -:1064B00024F4808D83FD06C012C0892B81F0808D6D -:1064C00083FD0DC08091030184FF04C0809105010C -:1064D0008F7E03C080910501806180930501109239 -:1064E000200E1092210E1092220E1092230E109266 -:1064F0001F0EE0916619F0916719C3ACD4ACE5ACFE -:10650000F6ACDA82C982D0921E0EC0921D0E41E412 -:10651000C4164CE9D40630F451E2C5165EE4D50643 -:1065200078F004C060E47CE97A83698389819A8188 -:1065300096958795969587959A83898384E00BC075 -:10654000A981BA81A131B74248F086011695079515 -:106550001A83098382E080931C0E0CC081E0809333 -:106560001C0E29813A812032310520F440E250E0AE -:106570005A83498309811A81005211091A830983B8 -:10658000011528E01207E8F0E12FFF27EE0FFF1FAB -:10659000EE0FFF1FCF018253984DFC0132964591BB -:1065A0005491AA27059F9001049F210D3A1F06943C -:1065B0002A1F3A1F1124FC0185919491821B930B91 -:1065C00022C089819A81969587958C7F82539C4DB4 -:1065D000FC0125913491FC013296459154916981D9 -:1065E0007A8167707727649FC001659F900D749FC3 -:1065F000900D1124E3E096958795EA95E1F7A901BE -:10660000481B590BCA018436910508F087CE05EE68 -:1066100012E0D8018D918D01882309F475CE5EDAE0 -:10662000F8CF80899189A289B389B695A795979566 -:106630008795B095A095909581959F4FAF4FBF4F8F -:106640008093120E9093130EA093140EB093150E18 -:1066500080930E0E90930F0EA093100EB093110E18 -:1066600080930A0E90930B0EA0930C0EB0930D0E18 -:106670008093060E9093070EA093080EB093090E18 -:106680008FCE80910B018E7F80930B0181E09BCE9A -:1066900080910B01826080930B0181E0A0CE8091FC -:1066A0000B018B7F80930B0181E0A5CE81E0AACE08 -:1066B00080ED97E09093890080938800A5CE80912B -:1066C00021023091DB0F882309F449C12091010E8A -:1066D0009091060120FF35C092FD02C090E02EC0CF -:1066E0009091000E992311F40C948ABB4081518142 -:1066F000628173811416150616061706FCF4409184 -:106700002510509126106091271070912810409309 -:106710002B0750932C0760932D0770932E0741E0B1 -:106720004093380740895189628973894093020EEA -:106730005093030E6093040E7093050E9093000E19 -:1067400033C092FD02C090E02DC09091FF0D9923BF -:1067500009F4E2C7408151816281738114161506E4 -:1067600016061706FCF440912510509126106091F2 -:1067700027107091281040932B0750932C0760939B -:106780002D0770932E0741E04093380740895189C7 -:10679000628973894093020E5093030E6093040E36 -:1067A0007093050E9093FF0D9091060121FF34C068 -:1067B00097FD02C090E02DC09091FE0D992309F441 -:1067C000ADC744815581668177811416150616067A -:1067D0001706FCF44091291050912A1060912B105B -:1067E00070912C1040932F0750933007609331071E -:1067F0007093320741E0409337074089518962899D -:1068000073894093020E5093030E6093040E7093AD -:10681000050E9093FE0D33C097FD02C090E02DC091 -:106820009091FD0D992309F47BC7448155816681C0 -:1068300077811416150616061706FCF440912910E8 -:1068400050912A1060912B1070912C1040932F07BB -:1068500050933007609331077093320741E04093C3 -:10686000370740895189628973894093020E50939A -:10687000030E6093040E7093050E9093FD0D90919E -:10688000180722FF2AC031116DC0913041F4909158 -:106890007F0F92FD04C083B18295817007C01C995F -:1068A00005C08091060186FB882780F98093FC0D46 -:1068B0008091FC0D882309F493C09091FB0D9923DE -:1068C00009F48EC0408551856285738514161506BE -:1068D000160617060CF465C083C0913039F4809118 -:1068E0007F0F82FD03C01092FA0D07C08091060150 -:1068F00086FB882780F98093FA0D8091FA0D882312 -:1069000061F19091F90D992341F14085518562859E -:1069100073851416150616061706FCF440912D1003 -:1069200050912E1060912F107091301040933307CA -:1069300050933407609335077093360791E0909336 -:10694000DA0F40895189628973894093020E50930E -:10695000030E6093040E7093050E8093F90D33239C -:1069600009F440C080911807813041F480917F0F75 -:1069700082FD04C083B18295817009C01C9906C054 -:106980008091060186FB882780F901C081E0809311 -:10699000FC0D8091FC0D882319F19091FB0D99233A -:1069A000F9F040912D1050912E1060912F107091A0 -:1069B000301040933307509334076093350770933A -:1069C000360791E09093DA0F408951896289738983 -:1069D0004093020E5093030E6093040E7093050EC5 -:1069E0008093FB0D109206071092050786A9198265 -:1069F00083FF9CC280911C0E1981181708F09CC25D -:106A0000C4DBE0916619F091671920813181809192 -:106A1000120E9091130E820F931F9093130E80937A -:106A2000120E181619066CF5409AE0916619F0914D -:106A300067198091120E9091130E20893189821B63 -:106A4000930B9093130E8093120E80912D02409120 -:106A50002510509126106091271070912810082E53 -:106A6000000C990BAA0BBB0B840F951FA61FB71F19 -:106A70008093251090932610A0932710B093281090 -:106A80004098E0916619F0916719248135818091D1 -:106A90000E0E90910F0E820F931F90930F0E809306 -:106AA0000E0E181619066CF5419AE0916619F091D0 -:106AB000671980910E0E90910F0E20893189821BEB -:106AC000930B90930F0E80930E0E80912E024091A7 -:106AD000291050912A1060912B1070912C10082EC3 -:106AE000000C990BAA0BBB0B840F951FA61FB71F99 -:106AF0008093291090932A10A0932B10B0932C1000 -:106B00004198E0916619F09167192085318580914F -:106B10000A0E90910B0E820F931F90930B0E809391 -:106B20000A0E181619066CF5429AE0916619F09152 -:106B3000671980910A0E90910B0E20893189821B72 -:106B4000930B90930B0E80930A0E80912F0240912D -:106B50002D1050912E1060912F1070913010082E32 -:106B6000000C990BAA0BBB0B840F951FA61FB71F18 -:106B700080932D1090932E10A0932F10B09330106F -:106B80004298E0916619F09167192091060E3091B4 -:106B9000070E84859585820F931F9093070E80932F -:106BA000060E1816190664F520893189821B930B8D -:106BB0009093070E8093060E809130024091311021 -:106BC000509132106091331070913410082E000CE7 -:106BD000990BAA0BBB0B840F951FA61FB71F8093A1 -:106BE000311090933210A0933310B09334108091F1 -:106BF0000507909106070196909306078093050775 -:106C00008091020E9091030E01969093030E809353 -:106C1000020E208931898217930708F08DC10981FE -:106C20000F5F0983E7CEB1DAE0916619F091671939 -:106C300040815181628173818091120E9091130E77 -:106C4000A091140EB091150E840F951FA61FB71FAB -:106C50008093120E9093130EA093140EB093150E02 -:106C6000181619061A061B06CCF5409AE09166190B -:106C7000F09167198091120E9091130EA091140E4D -:106C8000B091150E4089518962897389841B950BD7 -:106C9000A60BB70B8093120E9093130EA093140EB5 -:106CA000B093150E80912D02409125105091261021 -:106CB0006091271070912810082E000C990BAA0BD8 -:106CC000BB0B840F951FA61FB71F809325109093B1 -:106CD0002610A0932710B09328104098E0916619D1 -:106CE000F0916719448155816681778180910E0EFC -:106CF00090910F0EA091100EB091110E840F951F60 -:106D0000A61FB71F80930E0E90930F0EA093100E28 -:106D1000B093110E181619061A061B06CCF5419AE7 -:106D2000E0916619F091671980910E0E90910F0E07 -:106D3000A091100EB091110E40895189628973891A -:106D4000841B950BA60BB70B80930E0E90930F0E22 -:106D5000A093100EB093110E80912E024091291035 -:106D600050912A1060912B1070912C10082E000C5D -:106D7000990BAA0BBB0B840F951FA61FB71F8093FF -:106D8000291090932A10A0932B10B0932C104198A7 -:106D9000E0916619F0916719408551856285738588 -:106DA00080910A0E90910B0EA0910C0EB0910D0ED9 -:106DB000840F951FA61FB71F80930A0E90930B0E8A -:106DC000A0930C0EB0930D0E181619061A061B068A -:106DD000CCF5429AE0916619F091671980910A0EFC -:106DE00090910B0EA0910C0EB0910D0E408951891F -:106DF00062897389841B950BA60BB70B80930A0ECF -:106E000090930B0EA0930C0EB0930D0E80912F0259 -:106E100040912D1050912E1060912F1070913010D4 -:106E2000082E000C990BAA0BBB0B840F951FA61FF5 -:106E3000B71F80932D1090932E10A0932F10B09316 -:106E400030104298E0916619F09167194091060E52 -:106E50005091070E6091080E7091090E84859585FA -:106E6000A685B785840F951FA61FB71F8093060EB2 -:106E70009093070EA093080EB093090E18161906EA -:106E80001A061B06A4F54089518962897389841BFF -:106E9000950BA60BB70B8093060E9093070EA0934D -:106EA000080EB093090E809130024091311050913C -:106EB00032106091331070913410082E000C990B31 -:106EC000AA0BBB0B840F951FA61FB71F8093311011 -:106ED00090933210A0933310B09334108091050733 -:106EE000909106070196909306078093050780917D -:106EF000020E9091030EA091040EB091050E019622 -:106F0000A11DB11D8093020E9093030EA093040E59 -:106F1000B093050E4089518962897389841795075A -:106F2000A607B70748F409810F5F098380911C0EFB -:106F30001981181708F477CE8091010E83FF0BC0DA -:106F400080910507909106079195819591099093FD -:106F5000060780930507E0916619F0916719E05BD9 -:106F6000FF4F80818823C9F02091160E3091170EB3 -:106F700080910507909106074091030750910407FF -:106F8000B901641B750B860F971F909306078093BA -:106F9000050730930407209303078091050790911C -:106FA0000607892B09F44EC08091050790910607CA -:106FB00097FDB8C380910B01806480930B01809191 -:106FC0000507909106078827892B29F480910507EA -:106FD0009091060701C084E080932A0E90911C0EC8 -:106FE000981710F490932A0E3091090120912A0EDF -:106FF0008091280E9091290E36FD07C03091300205 -:10700000313039F4821B910906C0309130023130A1 -:10701000C9F7820F911D9093290E8093280E439AF1 -:10702000809105079091060701979093060780933A -:107030000507439880912A0E815080932A0E811172 -:10704000EECFA3D84091020E5091030E6091040E32 -:107050007091050EE0916619F0916719828D938DFC -:10706000A48DB58D84179507A607B70708F403C14B -:107070004091180E5091190E60911A0E70911B0ECE -:107080000489158926893789AA27419FB12D529FE6 -:10709000C001629F900D619F800D911D429FB00DB8 -:1070A000811D9A1F519FB00D811D9A1F609FB00DC9 -:1070B000811D9A1F509FB10D8A1F9A1FB6958A1F76 -:1070C0009A1F112423AD34AD820F931F90931E0E8F -:1070D00080931D0E27A930AD2817390720F430936F -:1070E0001E0E20931D0E00911D0E10911E0E0134D8 -:1070F0007CE9170738F401328EE4180788F01A8308 -:10710000098304C0A0E4BCE9BA83A983E981FA81B8 -:10711000F695E795F695E795FA83E98384E00AC04A -:107120000131F7E21F0748F06801D694C794DA826C -:10713000C98282E080931C0E0DC081E080931C0EFA -:107140000032110518F01A83098304C020E230E0F0 -:107150003A83298349815A81405251095A8349838C -:10716000411568E05607F0F0E52FFF27EE0FFF1FEF -:10717000EE0FFF1FCF018253984DFC0132964591CF -:1071800054917981AA27759F9001749F210D3A1F10 -:1071900006942A1F3A1F1124FC0185919491821BA9 -:1071A000930B22C089819A81969587958C7F825313 -:1071B0009C4DFC0125913491FC01329645915491EE -:1071C00069817A8167707727649FC001659F900D00 -:1071D000749F900D1124B3E096958795BA95E1F7C9 -:1071E000D901A81BB90BCD0184369105C0F4F5EE89 -:1071F000EF2EF2E0FF2EF70181917F01882319F035 -:107200000E946EADF8CFC980DA80B60180E090E0D0 -:107210004AE00E9486AD0E94A3AE84E690E090937F -:10722000250E8093240E4091180E5091190E6091F6 -:107230001A0E70911B0E6A017B01C80ED91EE11C4B -:10724000F11CC092180ED092190EE0921A0EF09214 -:107250001B0E8091661990916719FC01E05BFF4F4E -:107260002081222309F4E1C13196208131814281BC -:107270005381D80111C14091020E5091030E6091CB -:10728000040E7091050E868D978DA0A1B1A1841773 -:107290009507A607B70708F00FC1E090200EF09001 -:1072A000210E0091220E1091230EE982FA820B83A7 -:1072B0001C83448955896689778998018701AA27A3 -:1072C000059FB12D169FC001269F900D259F800D13 -:1072D000911D069FB00D811D9A1F159FB00D811D38 -:1072E0009A1F249FB00D811D9A1F149FB10D8A1FF4 -:1072F0009A1FB6958A1F9A1F112420911D0E309156 -:107300001E0E281B390B3E832D83FF9637FD05C0CB -:10731000808191812817390748F4C080D180DE82AE -:10732000CD8201E4C0160CE9D00648F4CD80DE80A1 -:1073300001E2C0160EE4D00650F0C60102C080E49F -:107340009CE9969587959695879524E00BC0CD800E -:10735000DE8001E1C01607E2D00658F0C60196951E -:10736000879522E020931C0E3D812E819E838D8384 -:107370000AC081E080931C0E0D811E810032110530 -:1073800038F03D812E810D811E813D832E8302C008 -:1073900000E210E000521109011528E01207E8F0A0 -:1073A000E12FFF27EE0FFF1FEE0FFF1FCF018253CC -:1073B000984DFC01329645915491AA27059F900162 -:1073C000049F210D3A1F06942A1F3A1F1124FC0125 -:1073D00085919491821B930B20C0C8019695879547 -:1073E0008C7F82539C4DFC0125913491FC01329697 -:1073F00045915491B80167707727649FC001659FDC -:10740000900D749F900D112443E0969587954A95B1 -:10741000E1F7A901481B590BCA0184369105B0F464 -:1074200085EEE82E82E0F82ED7018D917D0188232C -:1074300019F00E946EADF8CFB80180E090E04AE00C -:107440000E9486AD0E94A3AE84E690E09093250E44 -:107450008093240EC980DA80EB80FC80C80ED91E90 -:10746000E11CF11CC092200ED092210EE092220E5F -:10747000F092230E8091661990916719FC01E05BF0 -:10748000FF4F2081222309F4D0C031962081318121 -:1074900042815381AD81BE810F94D5B3DC01CB0114 -:1074A00001E1B695A795979587950A95D1F79093A1 -:1074B000170E8093160EB9C080911F0E8111ADC0BA -:1074C00067A970AD61340CE9700728F461321EE4DD -:1074D000710748F002C060E47CE97695679576957F -:1074E000679584E007C0613127E2720730F0769536 -:1074F000679582E080931C0E08C081E080931C0E8B -:107500006032710510F460E270E08B0100521109E5 -:107510001A830983011528E01207D8F0E12FFF270D -:10752000EE0FFF1FEE0FFF1FCF018253984DFC019E -:10753000329645915491AA27059F9001049F210DF1 -:107540003A1F06942A1F3A1F1124FC018591949139 -:107550001FC089819A81969587958C7F82539C4D17 -:10756000FC0145915491FC01329685919491698179 -:107570007A8167707727689F9001699F300D789FA7 -:10758000300D112463E0369527956A95E1F7CA011D -:10759000821B930B84369105B0F405EE12E0D801FE -:1075A0008D918D01882319F00E946EADF8CFC980AE -:1075B000DA80B60180E090E04AE00E9486AD0E9449 -:1075C000A3AE84E690E09093F80D8093F70D809140 -:1075D0001C0E80931F0EE0916619F0916719DF0170 -:1075E000A05BBF4F8C918823C1F0119627A930ADC5 -:1075F00041AD52AD6D917D918D919C910F94A4B34D -:10760000DC01CB0121E1B695A795979587952A9541 -:10761000D1F79093170E8093160E8091F70D9091ED -:10762000F80D9093250E8093240E8091050790917C -:107630000607892B09F48CC1E0916619F09167194E -:10764000E05BFF4F808181117EC082C180910C027E -:10765000882311F40C9411B28091060182FB8827D3 -:1076600080F99091060197FD8260AFE6BFE0E7E701 -:10767000FFE020E030E090E061E070E0022E01C029 -:10768000660F0A94EAF7482F462329F0408151817A -:107690004F5F5F4F07C0408151814115510521F077 -:1076A0004150510951834083408151810D911C917A -:1076B00011970417150748F411965C934E934034C4 -:1076C000510518F011821082962B2F5F3F4F1296B2 -:1076D00032962330310581F680917F0F81110C9411 -:1076E00011B2992311F40C9411B2909339071092AE -:1076F0000C0280913F0E81110C9411B220E030E019 -:1077000040E85FEB60E070E080E291E40E945CE8BA -:107710000C9411B2982F12C8982F44C8982F79C88A -:10772000982FABC880910B018F7B80930B018091C8 -:107730000507909106079195819591099093060709 -:10774000809305073CCC0E94C5B0E0918400F09185 -:107750008500FA83E983E091240EF091250EE4562A -:10776000F109CF01C980DA808C199D091092270E8A -:107770001092260E97FD5DC0692F7727462F613046 -:1077800051F48FEF80932A0E81E090E09093270EC2 -:107790008093260E4EC020910507309106072227C0 -:1077A000232B49F5209105073091060733276217EF -:1077B00073077CF0609105077091060777270F9497 -:1077C0008DB87093270E6093260E81E080932A0E69 -:1077D00030C0662371F120910507309106073327E9 -:1077E0003595279532E0421718F42695330FFBCFD5 -:1077F00030932A0E18C02091050730910607359561 -:10780000279542E0D901AA27AB2B21F03695279581 -:10781000440FF8CF6217730724F436952795440F69 -:10782000F9CF40932A0E0F948DB87093270E609372 -:10783000260E8091260E9091270E892BB1F50E947D -:10784000C5B0209109018091280E9091290E26FD46 -:1078500005C020913002213029F40BC02091300264 -:10786000213039F42091050730910607820F931FCC -:1078700006C02091050730910607821B930B909359 -:10788000290E8093280E439A809105079091060750 -:107890000197909306078093050743988091050709 -:1078A00090910607892B79F753C0F093250EE0934A -:1078B000240E09811A810C591F4F109389000093DF -:1078C0008800C090020ED090030EE090040EF0905D -:1078D000050E8091661990916719DC0150960D9103 -:1078E0001D912D913C9153976091280E7091290E16 -:1078F000C016D106E206F306D0F00E94DC9B10927F -:10790000290E1092280E1092671910926619909104 -:1079100000078091FF06981711F40C940BB2809128 -:10792000FF068F5F8F708093FF060C940BB220913F -:10793000F50D3091F60D6217730714F40C940BB229 -:107940000E94DC9B1092290E1092280E0C940BB210 -:107950008091240E9091250E909389008093880049 -:10796000B0CF26960FB6F894DEBF0FBECDBFDF9125 -:10797000CF91FF91EF91BF91AF919F918F917F91A7 -:107980006F915F914F913F912F911F910F91FF90B8 -:10799000EF90DF90CF900F900BBE0F900FBE0F9027 -:1079A0001F90189580913807811107C08091370783 -:1079B000811103C08091DA0F01C081E01092380775 -:1079C000109237071092DA0F0895CF93DF93811149 -:1079D00002C0D3E001C0D1E0C0E09FB7F89480912D -:1079E00002018460809302019FBF88EC90E00F94B5 -:1079F000BD129FB7F894809102018B7F80930201A2 -:107A00009FBF84EF91E00F94BD12CF5FDC13E5CFF1 -:107A1000DF91CF910895CF93DF939FB7F894C2E0A1 -:107A2000D1E08881846088839FBF84EF91E00F94C8 -:107A3000BD129FB7F89488818B7F88839FBFDF91A9 -:107A4000CF9108958AE02BE831E04FB7F8949091F8 -:107A500002019460909302014FBFF9013197F1F751 -:107A60004FB7F894909102019B7F909302014FBF12 -:107A7000F9013197F1F7815041F7089598B1907F5E -:107A80008F70892B88B9000098B900000895609123 -:107A900000079091FF0620E030E087E5961761F03F -:107AA000899FF0011124E552F84F40815181240F44 -:107AB000351F9F5F9F70F2CFC90108953091000775 -:107AC0002091FF06321791F0E0910007E11101C00B -:107AD000E0E1E15027E5E202F0011124E552F84F20 -:107AE00020813181820F931F9183808308958F922B -:107AF0009F92AF92BF92CF92DF92EF92FF920F933D -:107B00001F93CF93DF93C0912902D0912A028DE772 -:107B1000E82E80E1F82E0FE51DE06E0180E1C80E31 -:107B2000D11C6991799189919991F70181909190F6 -:107B3000A190B1907F010F948CAEA50194010F9498 -:107B4000F5A70F9454B5F8016193719381939193C4 -:107B50008F01CC15DD0529F7DF91CF911F910F9192 -:107B6000FF90EF90DF90CF90BF90AF909F908F905D -:107B7000089580911807811109C08DE890E19093D4 -:107B80002C0280932B028DE990E10AC0813061F4D0 -:107B900085E191E190932C0280932B0285E291E1A3 -:107BA00090932A0280932902A2CFFC014081518147 -:107BB00062817381409365105093661060936710E3 -:107BC000709368102091891030918A1040918B1029 -:107BD00050918C1060817181828193810F94F5A7FF -:107BE0000F94E7B6E9E6F0E16487758786879787A3 -:107BF0008FB7F89444855585668577854093311015 -:107C00005093321060933310709334108FBF0895E7 -:107C10008091BA069091B906981781F0E82FF0E0AC -:107C2000E454F94F208130E08F5F9091B8068917B6 -:107C300008F080E08093BA06C90108958FEF9FEFA6 -:107C400008959091D00095FFFCCF8093D60080E0FE -:107C500090E00895CF92DF92EF92FF920F931F93DF -:107C6000CF93DF93EC018A0170E06150710990E0DD -:107C700050E0292F30E0261737075CF05111F7CF7D -:107C8000DF91CF911F910F91FF90EF90DF90CF90F8 -:107C900008957E01E20EF31EF7018081D90111964D -:107CA0006E01CA0EDB1EF6014081481788F4F70109 -:107CB0004083F60180830115110549F0F801E20FB8 -:107CC000F31F8081A00FB11F2C9120838C9351E072 -:107CD0009F5FCFCF813041F028F0823039F0833080 -:107CE00059F00895A09A0895A29A08959FB7F8941C -:107CF00080910801806205C09FB7F89480910801C7 -:107D00008061809308019FBF0895813041F028F081 -:107D1000823039F0833059F00895A0980895A298E0 -:107D200008959FB7F894809108018F7D05C09FB793 -:107D3000F894809108018F7E809308019FBF089579 -:107D40001F9291E09F935F934F937F936F93282FA0 -:107D5000082E000C330B3F938F9382EE9BE29F9390 -:107D60008F930F942A312DB73EB7265F3F4F0FB642 -:107D7000F8943EBF0FBE2DBF99E0981B892F0D943C -:107D80001C314F925F926F927F928F929F92AF922F -:107D9000BF92CF92DF92EF92FF920F931F93CF93F8 -:107DA000DF9300D01F92CDB7DEB780913F028130C4 -:107DB000B1F510923F028091F50F81110AC044E1A4 -:107DC00050E06FEB74E180EE9FE00F9474AC0F9481 -:107DD000D2518DEE9FE00F9463B38F3F01F58EEE8D -:107DE0009FE00F9463B38F3FD1F48FEE9FE00F9429 -:107DF00063B38F3FA1F480EF9FE00F9463B38F3F95 -:107E000071F440E050E0BA018DEE9FE00F9487B32B -:107E100040E050E0BA0181EF9FE00F9487B380917A -:107E20003E0E882321F0815080933E0E03C081E0F6 -:107E30008093860280918602882309F498C48091F9 -:107E40003D0E8F5F80933D0E8E3129F40E94149A6F -:107E500010923D0E0AC06AE00F9480B8911105C0DF -:107E600080E00F947F790F944E3260E080E00F94B1 -:107E70006E326091891570918A15072E000C880B5F -:107E8000990B0F948EAE20E030E040E05FE30F945A -:107E9000EFB30F944EB56B017C0120E030E040E081 -:107EA0005FE36091DC0F7091DD0F8091DE0F9091A8 -:107EB000DF0F0F94EFB30F944EB5A60182E040DFC1 -:107EC00083E00F941C318091400E9091410E0197F8 -:107ED00029F485EF9BE20F94953118C080914010F2 -:107EE0008F9380913F108F9380913E108F9380915C -:107EF0003D108F938DEE9BE29F938F930F942A31C9 -:107F00000F900F900F900F900F900F9061E080E016 -:107F10000F946E326091020D7091030D072E000CCC -:107F2000880B990B0F948EAE20E030E040E05FE3C9 -:107F30000F94EFB30F944EB56B017C0120E030E05D -:107F400040E05FE3609108077091090780910A079C -:107F500090910B070F94EFB30F944EB5A60180E0FC -:107F6000EFDE83E00F941C31809144028F93809167 -:107F700043028F931F9286E08F938EEF9BE29F9335 -:107F80008F930F942A3198E0981B892F0F941C31FE -:107F900062E080E00F946E3280913C070F900F906A -:107FA0000F900F900F900F9090918016811107C045 -:107FB00091110AC06DE1E62E6CE2F62E0DC051E281 -:107FC000E52E5CE2F52E04C049E1E42E4CE2F42EED -:107FD000911124C081111CC080913A07811118C0F1 -:107FE0008091400E9091410E049791F080913F0E48 -:107FF00081110EC08091011090910210089741F0FC -:1080000080918216811104C080912E0E882341F048 -:1080100011E080913A028F3F21F402C011E001C0CB -:1080200010E08091420E811104C020913A02253661 -:1080300060F120913902253640F18091A9188823FA -:1080400019F18091531990915419A0915519B0913B -:1080500056190097A105B105B9F0BC01CD016D59C4 -:108060007F4F8F4F9F4F24E630E040E050E00F9469 -:10807000B3B360915B1970915C1980915D19909117 -:108080005E190F94B3B301C020E030E0111103C0BA -:1080900086E09CE202C08AE09CE23F932F939F938C -:1080A0008F938E010F5F1F4F1F930F930F94ECADB3 -:1080B0001F930F93FF92EF9280E19CE29F938F9327 -:1080C0000F942A310FB6F894DEBF0FBECDBF80915A -:1080D0007B13882371F130912D0E20912C0E832F6C -:1080E00090E032130EC001969F938F938CE29CE236 -:1080F0009F938F930F942A310F900F900F900F90B2 -:1081000014C030E02F5F3F4F3F932F9301969F9312 -:108110008F9385E29CE29F938F930F942A310F9067 -:108120000F900F900F900F900F9095E0981B892F54 -:108130000EC08091C80F882349F081E39CE29F9391 -:108140008F930F942A310F900F9003C085E00F9406 -:108150001C31E0903D02F0903E023FEFE316F30643 -:1081600001F18091420E882349F020913B02309129 -:108170003C022F3F8FEF380711F440C09701409128 -:1081800043025091440241155105C1F1A4E6B0E00B -:108190000F94DFB39A01550F440B550B0F94B3B3F3 -:1081A0002DC08091500E9091510EA091520EB09121 -:1081B000530E892B8A2B8B2BF9F00F94258830E6F0 -:1081C000832E3AEE932EA12CB12CA50194010F948D -:1081D000B3B329013A016091500E7091510E809114 -:1081E000520E9091530EA50194010F94B3B3F20176 -:1081F000E21BF30B9F0102C020E030E0809180166B -:10820000811121C080913C0781111DC080913A07E6 -:10821000811119C08091400E9091410E049799F000 -:1082200080913F0E81110FC080910110909102103A -:10823000089749F080918216811105C080912E0E19 -:10824000882309F45BC0EF20E09481F48091500E04 -:108250009091510EA091520EB091530E892B8A2B02 -:108260008B2B09F44BC090E280E20BC0809143025B -:10827000909144028436910511F09FE301C090E291 -:1082800082E5692F092E000C770B482F082E000C71 -:10829000550B2037E7E13E07B8F47F939F935F9338 -:1082A0008F93C9016CE370E00F948DB89F938F9307 -:1082B0007F936F931F9287E08F938DE49CE29F934F -:1082C0008F930F942A3114C07F939F935F938F9362 -:1082D000C9016CE370E00F948DB87F936F931F9288 -:1082E00087E08F9381E49CE29F938F930F942A31D0 -:1082F0000FB6F894DEBF0FBECDBF0DC01F9287E052 -:108300008F9387E39CE29F938F930F942A310F9072 -:108310000F900F900F9098E0981B892F0F941C31AD -:1083200063E080E00F946E3280918016882379F1AB -:108330006CE976E18FEA9EE00F943EB9892B39F122 -:108340002FEAE22E2EE0F22EF70101900020E9F74D -:108350003197AF014F5A5E4060E070E0C7010F9463 -:108360000EB98CE996E19F938F9385E09DE29F93F0 -:108370008F93FF92EF920F94ECAD10923C0E1092FF -:108380003B0E0F900F900F900F900F900F908091D9 -:10839000330E9091340E892B09F46BC08091390E05 -:1083A00090913A0E01968E30910528F490933A0EF2 -:1083B0008093390E04C010923A0E1092390E63E089 -:1083C00087E00F946E3287EF9CE20F94953100E0C6 -:1083D00010E08091390E90913A0E0817190758F461 -:1083E00063E087E0800F0F946E328EE20E949D9AC8 -:1083F0000F5F1F4FEECF8091330E9091340E82307D -:10840000910581F048F40197E9F463E080E00F946E -:108410006E328DE69DE223C083309105D1F0049742 -:1084200009F110C063E080E00F946E328FE59DE2A9 -:108430000F9495311092340E1092330E10923A0E22 -:108440001092390E00EE1FE094EFE92E9FE0F92E16 -:1084500049C163E080E00F946E3283E59DE20F94A2 -:108460009531F0CF63E080E00F946E328AE49DE2B4 -:10847000DFCF209180168091400E9091410E2223F3 -:1084800009F44EC0009709F04BC0ECE9F6E1019009 -:108490000020E9F7CF018D5996414597F0F1009101 -:1084A0003B0E10913C0EC12CD12C80913B0E909133 -:1084B0003C0E9801281B390B2431310544F5C114B9 -:1084C000D10429F598012258394E7901F901968D88 -:1084D000F02FF81B8F2F63E0911110C00F946E32B4 -:1084E000F701858D0E949D9A10923C0E10923B0ED2 -:1084F00000E010E0CC24C394D12CD7CF0F946E327F -:10850000F701858D0E949D9A0F5F1F4FCECF019678 -:1085100090933C0E80933B0E95CF8FEA9EE097C0E0 -:108520008230910509F468C030F4009709F464C002 -:10853000019759F087CF8430910509F48BC008F476 -:108540005EC0059709F4AAC07DCF8091250F909158 -:10855000260F8B30910500F163E080E00F946E32BE -:1085600082EE9CE20F94953163E080E00F946E32CE -:108570008CE39DE20F9495318EED9CE20F94953142 -:108580006091250F7091260F6A50710980E090E08C -:108590004AE00F94823056CF039761F48FEB94E159 -:1085A0000F9495318FEB94E10F94EE511092410EA0 -:1085B0001092400E8091250F9091260F04970797F7 -:1085C00008F040CF63E080E00F946E328AEC9CE2CA -:1085D0000F94953163E080E00F946E328BE29DE260 -:1085E0000F9495318091250F9091260F01979093CC -:1085F000260F8093250F26CF80EE9FE028C080EEC7 -:108600009FE00F9410312091310E3091320E809105 -:108610002F0E9091300E821793070CF413CF809198 -:10862000250F9091260F892B09F40CCF63E08AE087 -:108630000F946E3281E39EE00E94829F0F9410316E -:108640008FE20E949D9A8FE29EE00E94369F0F94D7 -:108650001031F8CE63E080E00F946E3286E19DE247 -:108660000F94953163E08CE00F946E328091260F69 -:108670008F938091250F8F9382E395E09F938F9343 -:108680001F930F930F9485B9C8010F9410310F9069 -:108690000F900F900F900F900F90D4CE63E080E07A -:1086A0000F946E3288E09DE20F9495318091250FF2 -:1086B0009091260F8937910508F0C4CE87EC9CE293 -:1086C0000F9495316091250F7091260F80E090E016 -:1086D0004AE00F94823080E20E949D9AB3CEE01669 -:1086E000F10649F0F80181918F018032C4F780E2F0 -:1086F0000E949D9AF4CF8091C80F882369F18091E0 -:108700005802909159020197909359028093580210 -:10871000181619065CF08AE090E090935902809355 -:10872000580260E080E090E00F94BE028091580211 -:10873000909159028530910531F0089769F460E015 -:1087400085E190E007C080918016882329F060E0E1 -:1087500084E190E00F94BE028AE080933E0E809107 -:10876000011090910210892B11F00F940D1380913C -:10877000041084709091470E992399F09091460EC1 -:10878000992339F081111DC01092460E1092470EA8 -:1087900018C08823B1F00F94BD2F81E08093460E5E -:1087A00010C0882371F080910110909102100297FF -:1087B00041F01092C41984E09DEC0F940D300E949A -:1087C000149A20914302309144028091AC19909107 -:1087D000AD192436310534F4820F931F8536910587 -:1087E0004CF416C02436310599F0820F931F84365D -:1087F000910574F41092AC191092AD191092AE1943 -:108800001092AF1984E690E0909344028093430263 -:1088100020914302309144028091AC199091AD199E -:108820002436310569F48B3091051CF0865A9F4F30 -:1088300009C0863FFFEF9F078CF482599F4F02C00B -:10884000820F931F90934402809343021092AC19BD -:108850001092AD191092AE191092AF198091430287 -:10886000909144028A3091051CF48AE090E005C0A2 -:10887000883E934034F087EE93E0909344028093D7 -:1088800043020F900F900F900F90DF91CF911F91A7 -:108890000F91FF90EF90DF90CF90BF90AF909F909F -:1088A0008F907F906F905F904F9008951F920F92DE -:1088B0000FB60F9211240BB60F922F933F934F9345 -:1088C0005F936F937F938F939F93AF93BF93EF9338 -:1088D000FF932091D6008091B9069091BA06E82FB7 -:1088E000F0E0E454F94F20838F5F2091B80682179F -:1088F00008F080E0981719F08093B90608C084EB5F -:108900009CE29F938F930F9493AD0F900F90FF91E4 -:10891000EF91BF91AF919F918F917F916F915F91F7 -:108920004F913F912F910F900BBE0F900FBE0F9064 -:108930001F901895FF920F931F93CF93DF93EC0135 -:10894000F090BA061091B9060091B80601500F9444 -:1089500045ACFE01E80FF11D8823D1F01F15D1F0C1 -:10896000115008F4102F31972491A12FB0E0A85492 -:10897000B94F14969C91291749F02D3019F49A306B -:1089800059F404C02A3041F49D3031F48150E4CFD1 -:1089900081E003C080E001C08FEFDF91CF911F9194 -:1089A0000F91FF9008954F925F926F927F928F92F6 -:1089B0009F92AF92BF92CF92DF92EF92FF920F936E -:1089C0001F93CF93DF93CDB7DEB7E0970FB6F89440 -:1089D000DEBF0FBECDBF582E682E712CAE014F5F8B -:1089E0005F4F60E1C3010F94DD6640E050E060E15D -:1089F000CE0101962FD983EA9CE29F938F930F9427 -:108A000093AD8E010F5F1F4F0F900F90E12CF12C53 -:108A100062E9C62E6CE2D62ED8018D918D011F928F -:108A20008F93FF92EF92DF92CF920F9493ADBFEFAF -:108A3000EB1AFB0A0F900F900F900F900F900F9072 -:108A4000E0E1EE16F10441F7E981F0E07E0182E019 -:108A5000E80EF11C8E010F5E1F4F20E031E0D701C0 -:108A60004D917D01632F70E0CF010F948DB84617B3 -:108A700018F4562F541B02C0542F561B842F90E01D -:108A8000523020F43F5FE80FF91F10C0422F50E032 -:108A9000F801E40FF51F3083E1E2F0E0EC0FFD1F79 -:108AA000E40FF51F6083FC012F5F31E0E016F10653 -:108AB000B1F6822F90E0D801A80FB91F3C9341E294 -:108AC000E42EF12CEC0EFD1EE80EF91E632F70E073 -:108AD000CF010F948DB8F701608344244394420E74 -:108AE00087E89CE29F938F930F9493ADCE0181967C -:108AF0004C0158010F900F90E12CF12C5FE6C52E30 -:108B00005CE2D52EE414C8F4D4019D914D01F50129 -:108B100081915F011F929F931F928F93FF92EF921B -:108B2000DF92CF920F9493ADFFEFEF1AFF0A0FB6CB -:108B3000F894DEBF0FBECDBFE5CFAE014F5D5F4FF6 -:108B4000642DC80187D8FE01E40DF11D80A1F30159 -:108B5000E35FF84F80831F928F938DE59CE29F9394 -:108B60008F930F9493AD0F900F900F900F90511023 -:108B700005C060910D078EEF9EE007C091E059128D -:108B800006C060910E078BEF9EE00F9475B381E0F5 -:108B9000E0960FB6F894DEBF0FBECDBFDF91CF9148 -:108BA0001F910F91FF90EF90DF90CF90BF90AF900B -:108BB0009F908F907F906F905F904F90089581303D -:108BC00051F028F0823059F0833069F00895409ACE -:108BD000000040980BC0419A0000419807C0429A9B -:108BE0000000429803C0439A000043980000089593 -:108BF000813099F028F08230E9F0833041F1089516 -:108C00009FB7662329F0F89480910B0181602BC0F7 -:108C1000F89480910B018E7F26C09FB7611105C02B -:108C2000F89480910B0182601EC0F89480910B0132 -:108C30008D7F19C09FB7662329F0F89480910B01AE -:108C4000846011C0F89480910B018B7F0CC09FB79A -:108C5000611105C0F89480910B01806404C0F89400 -:108C600080910B018F7B80930B019FBF00000895C3 -:108C7000CF92DF92EF92FF920F931F93CF93DF93E8 -:108C8000C82FF62E8A01DCE5DCBD1DBC3ED88F2D39 -:108C90000F94063A80E00F94063A80E00F94063A6B -:108CA00080E00F94063A80E00F94063A8C2F12D899 -:108CB000DCBD1DBC8C2F29D880E00F94063AD82F3C -:108CC00080E00F94063AC82ED12CE12CF12CFE2C1A -:108CD000ED2CDC2CCC2480E00F94063AC82AFE2C24 -:108CE000ED2CDC2CCC2480E00F94063AC82AFE2C14 -:108CF000ED2CDC2CCC2480E00F94063AC82A8C2F73 -:108D00000E946ABE0115110529F0F801C082D182C6 -:108D1000E282F3828D2FDF91CF911F910F91FF900F -:108D2000EF90DF90CF900895EF92FF920F931F93F3 -:108D3000CF93DF93C82FE62ED22F132F042FF52EBB -:108D40008CE58CBD1DBC8C2F0E9485BE8E2D0F9492 -:108D5000063A8F2D0F94063A802F0F94063A812FF2 -:108D60000F94063A8D2F0F94063A8C2FDF91CF91F6 -:108D70001F910F91FF90EF900C946ABE9C0188E0C8 -:108D8000369527952115310511F08150C9F70895C1 -:108D9000CF93DF9300D01F92CDB7DEB719821A822E -:108DA0001B821C82AE014F5F5F4F6AE661DF8981E3 -:108DB0009A8193700F900F900F900F90DF91CF9149 -:108DC00008958F929F92AF92BF92CF92DF92EF92CF -:108DD000FF920F931F93CF93DF93182FE62F042F4B -:108DE000A82FB0E0AA0FBB1FED01CF5CDD4F48817B -:108DF000542F5F70342F32953770441F4427441F1F -:108E000099819770990F492BAE5CBD4F8C918695D7 -:108E1000869586958370852E912CA12CB12CC32E1E -:108E2000D12CE12CF12C50E060E070E090E0A0E06B -:108E3000B0E0EF70C22FD0E02032D0F56894A1F8F6 -:108E4000B4F824E0CC0CDD1CEE1CFF1C2A95D1F7F5 -:108E50008C289D28AE28BF2837E0440F551F661F79 -:108E6000771F3A95D1F7482959296A297B29FFE0CC -:108E7000880F991FAA1FBB1FFA95D1F7842B952B3A -:108E8000A62BB72B9C01AD015E2B6CEE812F4CDF26 -:108E9000202F2F71822F90E0A0E0B0E0AC01BD0147 -:108EA0006F60DC2FCC27CE01DD0FAA0BBB0B41C0BE -:108EB0006894B4F824E0CC0CDD1CEE1CFF1C2A9551 -:108EC000D1F78C289D28AE28BF2837E0440F551FC6 -:108ED000661F771F3A95D1F7482959296A297B29B6 -:108EE000FFE0880F991FAA1FBB1FFA95D1F7842BAB -:108EF000952BA62BB72B9C01AD015E2B6CEE812F21 -:108F000013DF202F30E0359527952F713327C901C6 -:108F1000330FAA0BBB0BAC01BD016F60CE01959561 -:108F200087958F719927982F8827092E000CAA0BF7 -:108F3000BB0B9A01AB01282B392B4A2B5B2B60E929 -:108F4000812FDF91CF911F910F91FF90EF90DF90D4 -:108F5000CF90BF90AF909F908F90E6CEEF92FF9210 -:108F60000F931F93CF93DF9300D01F92CDB7DEB73F -:108F70000F9425880091350E1091360E2091370EF2 -:108F80003091380EDC01CB01801B910BA20BB30B8F -:108F9000893E9340A105B10508F44AC0E12CF12CAB -:108FA00019821A821B821C82AE014F5F5F4F6FE6EF -:108FB0008E2D5EDE89819A81AB81BC81B2FF26C095 -:108FC000EEECFBE284918F01882339F00E946EADB4 -:108FD0000F5F1F4FF8018491F7CFB701FF0C880B8B -:108FE000990B0E94F7AD8AE00E946EAD10E020E080 -:108FF00030E041E050E06CEE812F96DE1F5F1430D0 -:10900000B1F760E08EEC9BE20F940A0EFFEFEF1ACF -:10901000FF0A24E0E216F10409F0C2CF0F9425887C -:109020006093350E7093360E8093370E9093380E02 -:109030000F900F900F900F90DF91CF911F910F9194 -:10904000FF90EF9008950D948C7280911A18909172 -:109050001B18009721F1019790931B1880931A1801 -:109060002BE1ECE0F7E1A1EFB6E101900D922A953A -:10907000E1F72CE037E140E050E04817590768F489 -:109080004F5F5F4F6BE1F9017B96D90101900D9223 -:109090006A95E1F7255E3F4FF0CF0F94A8461092F6 -:1090A000430E08952F923F924F925F926F927F925C -:1090B0008F929F92AF92BF92CF92DF92EF92FF92E8 -:1090C0000F931F93CF93DF93CDB7DEB7A7970FB65C -:1090D000F894DEBF0FBECDBF89E09FE00F9463B36D -:1090E0008CA38091770E882321F01092770E0F9435 -:1090F000A84680918602811104C08091041082FFED -:1091000001C30F94EA563C010F944E2F1092B019F0 -:109110009E012F5F3F4F2901C30101979EA38DA39D -:109120009CA19D7F9FA38091B019843008F0EAC272 -:109130001092B21983EF9FE20F94B2368111E2C20E -:1091400063E876E181EF96E10E9466E38091831601 -:109150008F3219F400E010E072C065E278EC81EB28 -:109160009DE20F9473368823A9F3CCC28091B21983 -:109170009091B1198913A6C28091C80F882309F470 -:1091800063C08DA19EA1801B910BFCA1F23009F060 -:1091900060C060E070E00F9444572091D116809138 -:1091A000B2199091B119222309F4C3C0891388C25E -:1091B0009091860291115BC08091AB19882309F4CC -:1091C0007FC28091B21990E0A0E0B0E04091AC196C -:1091D0005091AD196091AE197091AF198417950730 -:1091E000A607B70709F06CC21092AB19109245029E -:1091F000E0901A18F9E0EF9EC00111249C01255A55 -:10920000314F790163E876E1C9010F9447B9C7018D -:109210000E94A7AE83E896E10F94B94B1092AC1967 -:109220001092AD191092AE191092AF1931E030932F -:1092300045020F94B52F811165C20F5F1F4F0615B0 -:10924000170509F093CF42C2EFA1EE2309F499CF9D -:10925000C80120911C1830911D188217930708F03F -:1092600098CFFC01E25EF74E808190E092CF90E0D3 -:10927000A0E0B0E04091AC195091AD196091AE19E9 -:109280007091AF1984179507A607B70749F5609144 -:10929000B01980E00F946E328EE30E949D9A85E0B3 -:1092A0000E949D9A80919C16882329F01092AE16F8 -:1092B0008CE996E102C083E896E17C0162E1D62E5A -:1092C000F70181917F01882319F0D1100CC274CF6E -:1092D000DD2009F471CF80E20E949D9ADA94F8CFE4 -:1092E0006091B01980E00F946E3280E20E949D9AE6 -:1092F00085E00E949D9A80919C16882329F0109207 -:10930000AE168CE996E102C083E896E17C0152E159 -:10931000D52EF70181917F01882319F0D110E7C183 -:109320004BCFDD2009F448CF80E20E949D9ADA9469 -:10933000F8CF8913C5C190918602992309F49CC086 -:1093400090E0A0E0B0E04091AC195091AD1960916F -:10935000AE197091AF1984179507A607B70709F0E2 -:1093600066C08090B0193090BD19F12C6F2D80E04F -:109370000F946E3280E20E949D9AF39484E0F8127A -:10938000F5CF682D80E00F946E328EE30E949D9A97 -:10939000C12CD12CF601E456F94E5F01EE24E39482 -:1093A000F12CF50191905F019920B9F1682D8E2D76 -:1093B0000F946E32892D0E949D9AFFEFEF1AFF0ADB -:1093C00024E1E216F10469F73FEFC31AD30A3CE245 -:1093D000E32EFF24F3940F94BC7D8091041082FD52 -:1093E00004C08091BD19381619F01092AE16D0CF76 -:1093F00081E0C816D10431F463E070E080E090E0D1 -:109400000F940D8761E070E080E090E00F940D878D -:1094100091E0E91AF108F9F6BDCF24E1F22EFE1829 -:1094200080E20E949D9AFA94F110FACF25C06091D3 -:10943000B01980E00F946E3280E20E949D9A809174 -:109440009C16882329F01092AF168CE996E102C091 -:1094500083E896E17C0193E1D92EF70181917F01A8 -:10946000882319F0D11047C107C0DD2029F080E220 -:109470000E949D9ADA94F9CF8091AB19882309F460 -:109480001FC18091B21990E0A0E0B0E04091AC190A -:109490005091AD196091AE197091AF19841795076D -:1094A000A607B70709F00CC10E94D49B1092760E54 -:1094B00023E836E13F932F93EAEAFDE2FF93EF932F -:1094C0005F924F920F94ECAD0F900F900F900F9012 -:1094D0000F900F907E0135E0E30EF11CDE2CCF2CB7 -:1094E000F7018081882349F0082E000C990B0F9416 -:1094F000F0B8F70181937F01F3CF85E0E0E4F5E078 -:10950000DE015F9601900D928A95E1F7ED2CFC2C1F -:10951000C12CD12C5701BE01615E7F4FC7010F9452 -:109520003EB996012B56304F892B29F460E0C901D2 -:109530000F9493B30FC0FFEFEF1AFF0AF50160819C -:10954000C9010F9493B3FFEFCF1ADF0A28E0C216C8 -:10955000D10401F720901A18622D8AE59FE00F943C -:1095600093B38BE5A82E8EE0B82EC12CD12C312CD4 -:109570003214F8F4E12CF12C460136EF831A30EF67 -:10958000930AF501EE0DFF1D6081C4018E0D9F1D34 -:109590000F9493B38FEFE81AF80A98E0E916F104F4 -:1095A00081F73394E9E0AE0EB11CF8E0CF0ED11C88 -:1095B000DFCF8091C80F882351F060E0C2010E9484 -:1095C00065DB61E086EA9DE20E9465DB76C041E0F2 -:1095D00061E083E896E10F94E5434091531950917F -:1095E0005419609155197091561941322EE4520761 -:1095F0006105710580F040525E4461097109409334 -:109600005B1950935C1960935D1970935E1986EA3B -:1096100098E10E940EE0F12C40915B1950915C1989 -:1096200060915D1970915E19809153199091541950 -:10963000A0915519B0915619481759076A077B0729 -:1096400010F5F11020C031E0309380160E94F4A094 -:109650008091981390919913892BF1F287E395E00B -:109660000E94A9A781114BC08BE395E00E94A9A796 -:10967000811145C080919713811102C00E943CDC8A -:1096800010929713E5CF0F94634644E150E06FEBDF -:1096900074E180EE9FE00F9474AC0F94D251F110FE -:1096A0008CCF40E060E081ED9FE20F94A007F82EA0 -:1096B00081E00F942737F11080CF0F94388AB9CD0D -:1096C0008091B2198F5F8093B219B7CD0F940F2F8D -:1096D0008091B0198F5F8093B0198091B1198F5F1D -:1096E0008093B11920CD0E949D9ADA94E9CD0E9411 -:1096F0009D9ADA940ECE0E949D9ADA94AECEFF2403 -:10970000F394B8CFA7960FB6F894DEBF0FBECDBFC7 -:10971000DF91CF911F910F91FF90EF90DF90CF904D -:10972000BF90AF909F908F907F906F905F904F9081 -:109730003F902F90089561E081EA9DE20E9465DBF1 -:1097400082E090E09093410E8093400E8CE89EE280 -:109750000F94EE510F94388A83E080938602089527 -:109760000F944E2F1092B0198091B0198430C8F523 -:109770001092B21988EA9FE20F94B236811131C07B -:1097800027E231E040E050E069E875E181EA9FE2DC -:109790000F946035811125C02AE730E040E050E0A9 -:1097A00062E07DE08DE99FE20F946035811119C080 -:1097B0002FEF30E040E050E06BEB79E183E99FE28E -:1097C0000F94603581110DC00F940F2F8091B01947 -:1097D0008F5F8093B0198091B1198F5F8093B11919 -:1097E000C3CF0895209197198091820290918302AE -:1097F000211108C021E02093971990939919809323 -:1098000098190DC020919819309199192817390786 -:1098100031F090939919809398190F94DA0C62E4BF -:109820007EE08FEF9FE00F94D3850F944E2F109220 -:10983000B0198091B019843008F0E5C01092B219C7 -:1098400083EF9FE20F94B2368111DDC027EE33E043 -:109850004AE050E063E472E08DE89FE20F946035E7 -:109860008111D1C027E231E040E050E069E875E1C4 -:1098700081EA9FE20F9460358111C5C023E730E093 -:1098800040E050E062E07DE08DE99FE20F946035BA -:109890008111B9C02FEF30E040E050E06BEB79E18F -:1098A00083E99FE20F9460358111ADC027EE33E06C -:1098B0004AE050E062E872E088E89FE20F94603589 -:1098C0008111A1C06BE97BEC88E79FE20F947336AE -:1098D000811199C08091420266EF71E081110BC045 -:1098E00086E69FE20F94733681118DC00E9482D765 -:1098F000882341F0089584E59FE20F94733688230E -:10990000A9F308958091C80F882391F080910107F1 -:10991000909102078130910509F455C008F43EC0CA -:109920008230910509F458C0039709F45EC066C0FF -:109930008091420E6AE072E081110BC082E49FE2E6 -:109940000F94733681115FC08091420E882341F0DD -:109950001BC080E39FE20F9473368823A9F3089518 -:1099600080910B0268E571E0811107C08EE19FE2F2 -:109970000F947336882351F208958CE09FE20F9480 -:109980007336882319F2089568E072E08AEF9EE248 -:109990000F94DE36882309F4B9CF08956CEC71E09A -:1099A00088EE9EE20F94733681112DC00F940F2F15 -:1099B0008091B0198F5F8093B0198091B1198F5F3A -:1099C0008093B11936CF6CEC71E086ED9EE20F9476 -:1099D0007336882359F308956CEC71E084EC9EE2B1 -:1099E0000F947336882311F308956CEC71E082EBC9 -:1099F0009EE20F9473368823C9F208956CEC71E0EF -:109A000080EA9EE2CFCF08950F944E2F1092B019A6 -:109A10008091B019843008F06AC11092B21980E8C0 -:109A20009EE20F94B236811162C18091801681113D -:109A300012C080913C0781110EC08091011090915D -:109A40000210089741F0809100079091FF06891B52 -:109A50008F7089F521C020E030E040E050E4609153 -:109A60003D1070913E1080913F10909140100F94E6 -:109A700088AE87FFE8CF8091580E8111E4CF8091A6 -:109A8000590E8111E0CF6CEC7DEF82E79EE20F94DE -:109A9000DE368823C1F208958091801681110BC0B3 -:109AA00080913C07811107C08091011090910210B4 -:109AB000089709F013C162EF7BEC8DE69EE20F94EC -:109AC000DE3681110AC180918116811107C0809113 -:109AD000011090910210089709F04EC08091A918CA -:109AE000882359F18091590E882329F0809180169E -:109AF000811156C04BC08091580E8111F7CF8091D3 -:109B00008016882389F066E571E089E59EE20F946E -:109B100073368111ECC068E37FEC86EC9FE20F9412 -:109B2000DE36882319F3089568E77EEC8CE49EE224 -:109B30000F94DE36882379F3089580910110909177 -:109B400002108830910541F42091590E211104C072 -:109B50002091580E222351F220913C072111C6CFAB -:109B6000089721F262E578EC8EE39EE20F94DE36F0 -:109B7000882309F4BBCF089562E578EC83E39EE285 -:109B80000F94DE36882309F4B1CF089580913C0705 -:109B9000811106C08091011090910210089799F4EC -:109BA0008091C80F811106C080913C07882309F479 -:109BB00067C06CC061EA70ED85E99DE20F94DE3606 -:109BC000882391F3089580917B13882349F16FEFE7 -:109BD00071ED85E29EE20F94DE36811188C069EB5B -:109BE00071ED86E19EE20F94DE36811180C063E75D -:109BF00071ED87E09EE20F94DE36811178C06EE849 -:109C00007DE287EF9DE20F943B36811170C06EECD0 -:109C100077ED88EA9FE20F94DE36882319F10895E4 -:109C2000809141028823A9F080914002882389F025 -:109C300069E07BEF85EE9DE20F94DE36811157C01F -:109C40006AE371E087EF9DE20F94DE368823F9F234 -:109C500008956CEB71E085E29EE20F9473368823E1 -:109C600079F3089580913A0781119ECF6AEA72EDE7 -:109C700089ED9DE20F94DE36882309F495CF08958F -:109C80008091011090910210089749F466E671E006 -:109C900083E89DE20F94DE36882351F0089565ED48 -:109CA00079EF8CEC9DE20F94DE36882379F30895EA -:109CB00062E77BEF84EC9DE20F94DE36811117C0E2 -:109CC0000F940F2F8091B0198F5F8093B0198091FE -:109CD000B1198F5F8093B1199BCE08956AEC73EF31 -:109CE00085E69EE20F94DE36882309F4ECCE0895D3 -:109CF000CF92DF92EF92FF920F931F930F94388AC7 -:109D000085EB9DE20F94EE511092F50F80913F0E7E -:109D1000882329F060E070E0CB010E94DBE60F941D -:109D2000258800914C0E10914D0E20914E0E3091D1 -:109D30004F0EC0907216D0907316E0907416F0908B -:109D400075160C191D092E093F09DC01CB01800F86 -:109D5000911FA21FB31F80934C0E90934D0EA093A2 -:109D60004E0EB0934F0E0F94D26610923A071F9189 -:109D70000F91FF90EF90DF90CF9008950F931F9376 -:109D800081E080935A0E10928C158091590E8111AA -:109D90000AC08091580E811106C00E948F951092C2 -:109DA000FD0C1092FC0C0E942DDC81EB9FE20F94C5 -:109DB000EE51109280160F9437570F94258800911A -:109DC000500E1091510E2091520E3091530EDC0125 -:109DD000CB01801B910BA20BB30B00914C0E109189 -:109DE0004D0E20914E0E30914F0EBC01CD01601BE7 -:109DF000710B820B930B28EE33E040E050E00F94A0 -:109E0000B3B310924C0E10924D0E10924E0E109253 -:109E10004F0E6091480E7091490E80914A0E9091BC -:109E20004B0E0F943E0D0F94388A81E08093470EBD -:109E30001092460E1092450E1092440E82E090E071 -:109E400090930210809301108091010188608093AB -:109E500001019FB7F89480910201877F80930201EE -:109E60009FBF1092BC191092BB191F910F910895BA -:109E700060E080E00F946E3286EC9FE20F949531A3 -:109E800062E082E00F946E3283EC9FE20F94953192 -:109E900063E082E00F946E328FEB9FE20F94953176 -:109EA00062E080E00F946E3289E596E00F94103105 -:109EB00063E080E00F946E3289E596E00F941031F4 -:109EC0008091AC199091AD19A091AE19B091AF19D4 -:109ED0000397A105B10564F082E090E0A0E0B0E056 -:109EE0008093AC199093AD19A093AE19B093AF19AC -:109EF0008091AC199091AD19A091AE19B091AF19A4 -:109F0000181619061A061B0664F081E090E0A0E01E -:109F1000B0E08093AC199093AD19A093AE19B093B3 -:109F2000AF196091AC196F5F80E00F946E3288E6D4 -:109F300094E00F9410310F946B308823D9F0809106 -:109F4000AC199091AD19A091AE19B091AF190197CC -:109F5000A105B10511F40F94388A8091AC19909144 -:109F6000AD19A091AE19B091AF190297A105B10535 -:109F700009F404CF0895EF92FF921F93CF93DF93DC -:109F800000D01F92CDB7DEB785E495E09A83898330 -:109F90008CE495E09C838B83E090BD190E2C000C23 -:109FA000FF080F941D3761E080E00F946E3288E661 -:109FB00094E00F94103111E045E75DE260E080E04D -:109FC0000F94123761E081E00F946E32E091780EC9 -:109FD000F091790EEE0FFF1F81E090E08C0F9D1F36 -:109FE000E80FF91F808191810F94103162E081E0C8 -:109FF0000F946E32E091780EF091790E3196EE0F5B -:10A00000FF1F81E090E08C0F9D1FE80FF91F8081FA -:10A0100091810F9410310F94BC7D81E00F94680EF4 -:10A020008091981390919913892B11F00E945DA053 -:10A030008091BD19082E000C990B9701281B390B34 -:10A0400037FF03C03195219531092D3031050CF4CE -:10A0500057C08E159F050CF41150E816F90624F42C -:10A060001F5F133018F421C0133070F08091780E08 -:10A070009091790E97FF59C001969093790E809335 -:10A08000780E0F941D3751C011110FC08091780EBA -:10A090009091790E181619063CF401979093790E59 -:10A0A0008093780E0F941D3711E061E080E00F94EB -:10A0B0006E3289E596E00F94103162E080E00F94F3 -:10A0C0006E3289E596E00F94103163E080E00F94E2 -:10A0D0006E3289E596E00F941031612F80E00F9485 -:10A0E0006E3288E694E00F941031E090BD190E2C8A -:10A0F000000CFF0864E670E080E090E00F940D87AC -:10A100000F946B30882309F457CF8091780E90918B -:10A11000790E810F911D019731F0019711F480E0C4 -:10A1200006C083E604C081E002C012E0BECF0F90FB -:10A130000F900F900F90DF91CF911F91FF90EF90B4 -:10A140000895AF92BF92CF92DF92EF92FF921F934A -:10A15000CF93DF93C0912907D0912A070F941D3721 -:10A1600060E080E00F946E3282E595E00F9410314C -:10A1700010E094E6C92ED12C2AE0A22EB12C209119 -:10A18000BD19822F022E000C990B97FF03C09195E9 -:10A190008195910903970CF440C027FF1DC0113031 -:10A1A00051F0123081F0111136C0C436D1059CF146 -:10A1B000C456D10930C0CE01B6010F94A1B80A9798 -:10A1C00054F12A9728C0CE01B5010F94A1B81816F2 -:10A1D00019060CF521971FC02223E9F0113059F020 -:10A1E000123091F0111117C0C43883E0D8079CF4E5 -:10A1F000CC59DF4F10C0CE01B6010F94A1B88A35FB -:10A2000091054CF42A9607C0CE01B5010F94A1B870 -:10A21000099709F021961092BD1962E080E00F9431 -:10A220006E32C436D1055CF487EA94E00F941031A5 -:10A23000CA30D10524F487EA94E00F941031BE01AE -:10A240000D2E000C880B990B0F94F53088E596E0E5 -:10A250000F94103163E080E00F946E3287E596E052 -:10A260000F94103163E0812F0F946E328AE595E0F0 -:10A270000F94103164E670E080E090E00F940D8759 -:10A280000F946B308823F1F068EC70E080E090E090 -:10A290000F940D871F5F1330A9F4D0932A07C09342 -:10A2A000290769E277E081EC9FE00E94B8FD60E059 -:10A2B00084E190E00F94BE020F94388AEE24E39478 -:10A2C000F12C02C0E12CF12C0F94BC7DEF2809F495 -:10A2D00056CFDF91CF911F91FF90EF90DF90CF90FD -:10A2E000BF90AF9008950F944E2F1092B0198091A7 -:10A2F000B0198430E8F51092B21983EF9FE20F9401 -:10A30000B236811135C062E971E08CE59AE30F94B1 -:10A31000733681112DC066ED71E08BE49AE30F94E2 -:10A320007336811125C064E471E08AE39AE30F94E7 -:10A33000733681111DC066EB71E089E29AE30F94D8 -:10A340007336811115C064E571E088E19AE30F94DA -:10A35000733681110DC00F940F2F8091B0198F5F4C -:10A360008093B0198091B1198F5F8093B119BFCFDD -:10A3700008950F944E2F1092B0198091B019843027 -:10A38000E8F51092B21983EF9FE20F94B236811173 -:10A3900035C064EE71E088E09AE30F947336811162 -:10A3A0002DC06AE671E088EF99E30F94733681114E -:10A3B00025C064E671E088EE99E30F94733681114D -:10A3C0001DC064EA71E088ED99E30F947336811142 -:10A3D00015C06CE072E088EC99E30F94733681113C -:10A3E0000DC00F940F2F8091B0198F5F8093B0191B -:10A3F0008091B1198F5F8093B119BFCF08950F94E9 -:10A400004E2F1092B0198091B019843008F049C0D5 -:10A410001092B21983EF9FE20F94B236811141C0BE -:10A4200060E571E08FEB99E30F947336811139C0C9 -:10A4300068E771E08FEA99E30F947336811131C0B8 -:10A440006AEF71E08FE999E30F947336811129C0A7 -:10A450006CE971E08FE899E30F947336811121C0A4 -:10A4600066E871E08FE799E30F947336811119C0A4 -:10A4700080917B1381110DC00F940F2F8091B01923 -:10A480008F5F8093B0198091B1198F5F8093B1195C -:10A49000BACF60ED71E08FE699E30F9473368823AD -:10A4A00059F3089561E08CEF9FE20E9465DB0D9403 -:10A4B000388A61E080E090E30E9465DB0D94388A81 -:10A4C00061E088EF9FE20E9465DB0D94388A61E0CD -:10A4D00086E090E30E9465DB0D94388A40E061E0FD -:10A4E0008BE490E30F94A007882339F061E087E4C0 -:10A4F00090E30E9465DB0F94388A81E00F94273740 -:10A5000082E08093860208950F944E2F1092B01926 -:10A510008091B0198430E8F41092B21989ED9DE26F -:10A520000F94B236811115C067E672ED8EE590E3A7 -:10A530000F94DE3681110DC00F940F2F8091B0194A -:10A540008F5F8093B0198091B1198F5F8093B1199B -:10A55000DFCF08950F944E2F1092B0198091B0194B -:10A56000843008F07AC01092B21983EF9FE20F9402 -:10A57000B236811172C080913A07882369F00F9436 -:10A580000F2F8091B0198F5F8093B0198091B1190E -:10A590008F5F8093B119E2CF6CE87AED88E699E39A -:10A5A0000F947336811159C066E477ED87E599E31E -:10A5B0000F94DE36811151C061E470E383E69CE1C3 -:10A5C0000F943B36811149C063E278EC85E499E34E -:10A5D0000F947336811141C062E572ED87E399E310 -:10A5E0000F947336811139C069E572ED8BE299E3FE -:10A5F0000F94DE36811131C060E672ED89E199E396 -:10A600000F94DE36811129C06CE474EF87E099E382 -:10A610000F94DE36811121C06DE173EF87EF98E36F -:10A620000F94DE36811119C06CE471E086EE98E378 -:10A630000F94DE36811111C06DE370E384ED98E371 -:10A640000F943B36811109C064E872ED82EC98E307 -:10A650000F94DE36882309F492CF089560910F0796 -:10A6600081E0682760930F078FEA9FE00F9475B32E -:10A670000D94D382E7E8F8E1608181E06827608388 -:10A680008BEB9FE00D9475B36091E60681E068273F -:10A690006093E60686ED9EE00D9475B380918B1570 -:10A6A000813019F410928B1503C081E080938B15D3 -:10A6B00060918B1588E09FE00F9475B30D944E76F2 -:10A6C000CF93DF930F944E2F1092B0198091B01951 -:10A6D0008430A8F51092B21988EA9FE20F94B2363E -:10A6E000811192C064E177E083EE96E30F94418597 -:10A6F00081118AC065E177E089ED96E30F94418589 -:10A70000811182C066E177E08FEC96E30F9441857A -:10A7100081117AC067E177E085EC96E30F9441857B -:10A72000811172C00F940F2F8091B0198F5F8093A9 -:10A73000B0198091B1198F5F8093B119C7CF809103 -:10A740000310882309F460C0809114078E3110F43F -:10A7500010921407809115078E3110F4109215078E -:10A76000809116078E3110F410921607809117070A -:10A770008E3110F41092170787EF9EE00F9463B3A9 -:10A78000D0911407C1E08D1301C0C0E086EF9EE0B8 -:10A790000F9463B391E020911507281301C090E056 -:10A7A000C92B85EF9EE00F9463B391E020911607CB -:10A7B000281301C090E0C92B84EF9EE00F9463B38F -:10A7C00091E020911707281301C090E0C92B6D2F4D -:10A7D00087EF9EE00F9475B36091150786EF9EE0BA -:10A7E0000F9475B36091160785EF9EE00F9475B3D3 -:10A7F0006091170784EF9EE00F9475B3CC2321F08E -:10A80000DF91CF910D948B38DF91CF910895809196 -:10A810007B13882319F08BE192E302C083ED91E36F -:10A820000F94410880E00F9427370F941D3742ECB6 -:10A8300051E362E080E00F94123781E08093760E5E -:10A840000D945D658F929F92AF92BF92CF92DF92EF -:10A85000EF92FF920F931F9380E090E0A8ECB2E498 -:10A8600080933D1090933E10A0933F10B093401002 -:10A870002091391030913A1040913B1050913C108A -:10A88000609135107091361080913710909138108A -:10A89000EEEFFCE0FF93EF93E5E58E2E982CA82CCD -:10A8A000E1E4BE2EF1E4CF2EF0E1DF2EE12CF12C1D -:10A8B00008EC12E40E94518780ED97E00F94BD12DE -:10A8C00084E291E30F9493070F944E320F900F9010 -:10A8D0006091891570918A15072E000C880B990BD1 -:10A8E0000F948EAE9B01AC016091DC0F7091DD0F77 -:10A8F0008091DE0F9091DF0F0F94EEB36B017C011E -:10A9000020E030E0A9010F943AB618165CF420E07C -:10A9100030E040E450E4C701B6010F943AB618168F -:10A920005CF03FC020E030E040E450ECC701B601ED -:10A930000F9488AE87FF35C084E291E30F949307AC -:10A9400064E080E00F946E326091891570918A15F1 -:10A95000072E000C880B990B0F948EAE20E030E090 -:10A9600040E05FE30F94EFB30F944EB56B017C01B1 -:10A9700020E030E040E05FE36091DC0F7091DD0F9C -:10A980008091DE0F9091DF0F0F94EFB30F944EB5CF -:10A99000A60182E00E94A0BE88EE93E00F94BD1253 -:10A9A00097CF1F910F91FF90EF90DF90CF90BF90C6 -:10A9B000AF909F908F9008958F929F92AF92BF9289 -:10A9C000CF92DF92EF92FF920F931F93CF93DF937B -:10A9D00082E090E09093410E8093400E82E99AE3EA -:10A9E0000F94EE5120E030E044E352E460914110D6 -:10A9F0007091421080914310909144100F94EEB3E7 -:10AA000060934110709342108093431090934410D0 -:10AA1000E0903D10F0903E1000913F1010914010DA -:10AA20002091391030913A1040913B1050913C10D8 -:10AA300060913510709136108091371090913810D8 -:10AA4000CEEFDCE0DF93CF93812C912CECEAAE2E9D -:10AA5000E2E4BE2EF1E4CF2EF0E1DF2E0E9451871A -:10AA60000F94988320E030E040E751E4609141107A -:10AA70007091421080914310909144100F94EEB366 -:10AA80006093411070934210809343109093441050 -:10AA9000E0903D10F0903E1000913F10109140105A -:10AAA0002091391030913A1040913B1050913C1058 -:10AAB0006091351070913610809137109091381058 -:10AAC000DF93CF93812C912CA0E8AA2EA1E4BA2E7B -:10AAD0000E9451870F94988320E030E040EA51E4CF -:10AAE00060914110709142108091431090914410F8 -:10AAF0000F94EEB360934110709342108093431013 -:10AB000090934410E0903D10F0903E1000913F1063 -:10AB1000109140102091391030913A1040913B1023 -:10AB200050913C1060913510709136108091371023 -:10AB300090913810DF93CF930E9451870F949883A0 -:10AB40008DE69AE30F949307149A64E670E080E030 -:10AB500090E00F940D870F900F900F900F900F9033 -:10AB60000F908091010790910207009711F00197D3 -:10AB700011F40E940BBDC3E30F946B30811107C029 -:10AB8000C15029F084E690E00F94BD12F5CF0F94E8 -:10AB900098830F946B30882329F084E690E00F941B -:10ABA000BD12F7CF81E00F9427378FEB94E10F941C -:10ABB000EE511092410E1092400EDF91CF911F91F5 -:10ABC0000F91FF90EF90DF90CF90BF90AF909F904C -:10ABD0008F90089580917B13882371F024E431E3F2 -:10ABE0004AE451E361E081E591E30F9431888111FA -:10ABF0000D94B0250D943C25DFCE2F923F924F92BD -:10AC00005F926F927F928F929F92AF92BF92CF92FC -:10AC1000DF92EF92FF920F931F93CF93DF93CDB705 -:10AC2000DEB728970FB6F894DEBF0FBECDBF6C011C -:10AC30008B017A0180917B13452B29F0882341F009 -:10AC400026E029830AC0811106C034E0398305C09B -:10AC500085E0898302C095E099830115110529F0EB -:10AC6000C8010F9445ACA82E01C0A12CB090BD190D -:10AC70000F941D3784E090E090932302809322028A -:10AC800033243394212C2981022E000C330B2350C2 -:10AC9000310938872F83A394A394AE820F94BC7D8F -:10ACA00081E00F94680E3091BD1939838B2D0B2CE8 -:10ACB000000C990B831B910937FD939597FF03C0F7 -:10ACC00091958195910905976CF089818B152CF4EC -:10ACD0003A9493E09315C4F409C02981B2161CF488 -:10ACE000339401C0B98293E09315BCF4822D022CF9 -:10ACF000000C990B2F813885821793070CF0C3C085 -:10AD000023940F941D37BFC0311007C012141CF4D8 -:10AD10002A940F941D3733243394C114D10429F09D -:10AD2000A60160E080E00F941237822D022C000C07 -:10AD3000990B9B838A83E114F10429F02F813885D4 -:10AD40008217930711F083E001C082E0A12CB12C9F -:10AD5000282F880F330B3D832C838C819D81A8166F -:10AD6000B9066CF40115110531F0A80161E06A0D16 -:10AD700081E00F9412379FEFA91AB90AEECF412C48 -:10AD8000512C3201822C022C000C9908AA08BB0815 -:10AD90002FEF821A920AA20AB20A61E0640D8E8134 -:10ADA0000F946E32C501B401640D751D861D971D8B -:10ADB0000F94F5303FEF431A530A630A730A8C81EC -:10ADC0009D81481659064CF3E114F10461F02A8183 -:10ADD0003B818F8198852817390729F4A70163E003 -:10ADE00081E00F94123761E080E00F946E3289E5C4 -:10ADF00096E00F94103162E080E00F946E3289E5A6 -:10AE000096E00F94103163E080E00F946E3289E594 -:10AE100096E00F941031632D80E00F946E3288E637 -:10AE200094E00F94103164E670E080E090E00F94BD -:10AE30000D870F946B30811102C0B9802FCF82E053 -:10AE400090E090932302809322021092BD198FEF1D -:10AE5000830D820D28960FB6F894DEBF0FBECDBFCE -:10AE6000DF91CF911F910F91FF90EF90DF90CF90E6 -:10AE7000BF90AF909F908F907F906F905F904F901A -:10AE80003F902F90089583E0382E47CFCF93DF93E4 -:10AE900080917B13882381F040EA50E367EA70E3F6 -:10AEA00080EB90E3AADE853030F590E044969093F5 -:10AEB000450E8093440E08C041E060E088E890E3CE -:10AEC0000F94A007882339F088E090E09093021057 -:10AED0008093011010C088E690E30F949307C4E1BB -:10AEE000D0E084E690E00F94BD120F946B30811196 -:10AEF00002C02197B1F70F94388A81E0DF91CF919A -:10AF00000D942737CF93C0917B13CC2309F443C012 -:10AF1000C0914002C1112EC09091B2198091B11917 -:10AF2000981322C080918602882329F06DEE76E383 -:10AF300080E20F9400368091AB198823A9F08091AC -:10AF4000B21990E0A0E0B0E04091AC195091AD1979 -:10AF50006091AE197091AF1984179507A607B707CE -:10AF600019F40F94B52F13C08091B2198F5F80939D -:10AF7000B21911C08091E60664E473ED882319F0DC -:10AF800081E197E302C08FEF96E30F947336C1E03F -:10AF9000811101C0C0E08C2FCF910895CF93DF9332 -:10AFA0001F92CDB7DEB762E47EE08FEF9FE00F9493 -:10AFB000D3850F944E2F1092B0198091B019843020 -:10AFC00008F066C11092B21983EF9FE20F94B23677 -:10AFD00081115EC160EB7BEC86EB98E30F94DE366B -:10AFE000811156C18091580E882329F080913A072B -:10AFF000811112C009C068E671E08CEA98E30F94F1 -:10B00000DE36882399F344C169E370E38BE998E362 -:10B010000F943B3681113CC180914202811129C0BD -:10B0200080917A1366EF71E08823B1F080917B13F1 -:10B03000811112C089E898E30F947336811128C1F9 -:10B0400062E671E087E798E30F94DE36811120C154 -:10B0500059DF882341F11CC186E69FE20F947336C5 -:10B06000811116C180917B138111F2CF64E971E0E7 -:10B07000E9CF66EF71E084E59FE20F9473368111AA -:10B0800007C180917B138111E3CF809141026DE470 -:10B090007BEF882319F085E698E302C083E598E307 -:10B0A0000F947336D3CF8091460260EC73EF882300 -:10B0B00059F081E498E30F9473368111E9C08091CF -:10B0C000C80F882321F01FC08FE298E3F4CF80914E -:10B0D000420E6AE072E081111FC082E49FE20F9489 -:10B0E00073368111D5C08091420E81111BC08091B1 -:10B0F0000B0268E571E0811112C08EE19FE20F94AE -:10B1000073368111C5C060E673ED8FE198E30F944B -:10B11000DE36882371F0BCC080E39FE2E0CF8CE094 -:10B120009FE2EDCF68E072E08AEF9EE20F94DE3698 -:10B13000E8CF80910F076EE273ED81110FC08DE0B3 -:10B1400098E30F9473368111A3C080918B15811100 -:10B1500008C06EE473ED89EE97E307C08BEF97E3C9 -:10B16000F0CF6EE473ED87ED97E30F9473368111A2 -:10B170008FC080913A07811104C08091580E8823B6 -:10B1800049F080918718882371F06AE373ED85ECAC -:10B1900097E30DC06CEC7DEF82E79EE20F94DE3604 -:10B1A000882379F375C06AE373ED83EB97E30F941B -:10B1B000733681116DC08091C80F81111EC0BE0110 -:10B1C0006F5F7F4F89E09FE00F94D385898188234B -:10B1D00039F0813051F46CE671E08FE897E309C0F3 -:10B1E0006CE671E081EA97E304C06CE671E08DE7FC -:10B1F00097E30F94733681114BC0809101079091B2 -:10B20000020781309105C1F050F082309105C9F0FC -:10B210000397E1F46CEC71E085E397E304C06CEC18 -:10B2200071E08BE697E30F947336811131C0809102 -:10B23000C80F811110C01FC06CEC71E089E597E365 -:10B24000F2CF6CEC71E087E497E3EDCF6CEC71E04A -:10B2500083E297E3E8CF61EA70ED8DE290E30F942B -:10B26000DE36811115C06EE672ED8BE190E30F942E -:10B27000733681110DC00F940F2F8091B0198F5F1D -:10B280008093B0198091B1198F5F8093B11995CED9 -:10B290000F90DF91CF910895CF92DF92EF92FF92BE -:10B2A0000F931F93CF93C82F0AE010E387EDE82E8A -:10B2B000F12C9CE3C92ED12CCF931F930F930F94A5 -:10B2C00093AD0F900F900F908C2F90E08E309105E2 -:10B2D00098F7FC018827E658FF4F8F4F0D94D0B8A0 -:10B2E00081E080937B0E23EC3FE24FEB5FE261E075 -:10B2F00082E696E30F943188882309F4C5C061E0A3 -:10B300008FE59FE00F9493B3C1E0D6CF0E94C6AC07 -:10B31000863E09F4F7C028F4813009F4B5C0C2E0D4 -:10B32000CBCF803F21F08A3F09F4EAC0F8CFC4E0D8 -:10B33000C3CF8BE196E30F9441080F948C7288235E -:10B3400009F4A7C08AEF0E949AA9DAC08DED95E3AF -:10B350000F94410880E00E9405708111D3C099C00C -:10B3600087EB95E30F9441088BE895E30F94410830 -:10B370008DE695E30F94410840E060E082EB9BE1AD -:10B380000F94A007811104C082E39AE10F94410851 -:10B3900081E00E940570882309F47BC0F0928A1531 -:10B3A000E09289158AE495E30F9493074BDA12DC57 -:10B3B0002EDA10928A1510928915ACC0F0928A1577 -:10B3C000E0928915D092030DC092020D80917B13FB -:10B3D00040E060E0882319F084E395E302C080E256 -:10B3E00095E30F94A007082E000C990B892B09F008 -:10B3F0008BC080917B13811189C0C6E05DCF8DEF3A -:10B4000094E30F9493071EDA81C001E020E040E04E -:10B4100050E0BA018AEC93EF0F94C32F8EEB94E3C4 -:10B420000F94410836C00EDAD5DB70C0F0D970C079 -:10B4300041E060E08AEA94E30F94A007811168C0BC -:10B44000C7E03ACF8DE594E30F94410889EA93E38E -:10B450000F94410888E090E09093021080930110CF -:10B460000F94388A16C023EC3FE24FEB5FE260E0B6 -:10B4700088E593E30F943188882309F44BC08AE26E -:10B4800093E30F94410844C060E08FE59FE00F9480 -:10B4900093B3CF9385EA9AE39F938F930F9493ADE1 -:10B4A0000F900F900F90C530F0F4C230B8F08DEAD5 -:10B4B00092E3CB3031F0C73021F00F944108109265 -:10B4C0007B0E81E00F94273782E0CF911F910F917F -:10B4D000FF90EF90DF90CF900D94932FC13069F0E3 -:10B4E00080E792E3E6CFCD30D9F71092F50F8FEBDE -:10B4F00094E10F94EE510F94388A8DE093E3DBCF03 -:10B50000C3E0DACEC5E0D8CECAE0D6CEC9E0D4CE0C -:10B51000CBE0D2CECDE0D0CE0E94C6AC8F3F29F496 -:10B520008FEF0E949AA980E0B7CE23EC3FE24FEB69 -:10B530005FE260E085EC90E30F9431888111F0CFF9 -:10B540000F94388A81E00F94273782E00D94932F6F -:10B550002F923F924F925F926F927F928F929F9223 -:10B56000AF92BF92CF92DF92EF92FF920F931F9311 -:10B57000CF93DF93EC012A013B0169018C81833079 -:10B5800039F059E0440C551C661C771C5A95D1F7CC -:10B5900043E0942E88248A94560181E0A81A8EEF05 -:10B5A000B80A1601EEEF3E1A9A94A301920161E1E6 -:10B5B000CE010E947FE6882319F0F4E0F9835EC093 -:10B5C0000F9425888B010E9478E68B838F3F51F47E -:10B5D0000F942588601B710B6D327140A0F381E1DF -:10B5E000898343C08E3F19F0EFE0E9833EC08EBCF3 -:10B5F000D601F6010DB407FEFDCF8EB581938EBC4A -:10B60000EA15FB05B9F70DB407FEFDCF8EB5F501C0 -:10B610008083E12CF12C8D91EF2DFF27E827EE0F91 -:10B62000FF1FE554F54C85919491FE2CEE24E826FD -:10B63000F926A215B30579F70E9478E6082F10E0E5 -:10B64000102F00270E9478E6082B0E151F0519F011 -:10B65000F0E2F9830AC0CE010E946EE68D81882354 -:10B6600001F18FEF0E9473E61CC0CE010E946EE6CE -:10B670008D81882319F08FEF0E9473E6992061F085 -:10B68000CE010E946EE620E030E0A9016CE0CE0120 -:10B690000E947FE6198288CFCE010E946EE680E08C -:10B6A00001C081E0DF91CF911F910F91FF90EF904A -:10B6B000DF90CF90BF90AF909F908F907F906F90D2 -:10B6C0005F904F903F902F900895FF920F931F939C -:10B6D000CF93DF93EC01F62E662321F00F9445AC57 -:10B6E0008C0108C0FC0101900020E9F731978F011F -:10B6F000081B190B0036110508F071C060E0C80185 -:10B700000E9468A0882309F46AC0809195139091E3 -:10B710009613FC01E656FC4E23E020830396BE01FF -:10B7200086569C4EFF2019F00F943EAC02C00F9439 -:10B7300047B9E6E9FEE58491EF01882331F00E94E4 -:10B740006EAD2196FE018491F8CFE4EEFCE3849186 -:10B75000EF01882331F00E946EAD2196FE018491A5 -:10B76000F8CFC0919513D0919613C356DC4E8991B2 -:10B77000882319F00E946EADFACFE2EEFCE38491CB -:10B78000EF01882331F00E946EAD2196FE01849175 -:10B79000F8CF8AE00E946EAD809195139091961338 -:10B7A0000496080F191F0D3EF1E01F0729F01093B2 -:10B7B00096130093951304C010929613109295134C -:10B7C0008091981390919913019690939913809377 -:10B7D0009813DF91CF911F910F91FF900895E4E7A7 -:10B7E000FEE584918F01882339F00E946EAD0F5FD2 -:10B7F0001F4FF8018491F7CFE4EEFCE384918F01B1 -:10B80000882339F00E946EAD0F5F1F4FF8018491BD -:10B81000F7CFFF2041F0FE018491882351F00E9470 -:10B820006EAD2196F8CF8991882319F00E946EADF4 -:10B83000FACFEBECFCE38491EF01882331F00E9416 -:10B840006EAD2196FE018491F8CF8AE0DF91CF9111 -:10B850001F910F91FF900C946EAD1092881510926D -:10B8600087151092961310929513109299131092B7 -:10B8700098131092971308958091981390919913AB -:10B88000181619060CF047C00197909399138093EE -:10B890009813892B79F48091931390919413892BA9 -:10B8A00021F4109296131092951380919513909114 -:10B8B00096132BC0E0918715F0918815E356FC4E46 -:10B8C000CF018A59934121912111FACF0196FC01B0 -:10B8D000E656FC4E8D3E21E0920740F42191AC01EA -:10B8E0004F5F5F4F211111C0CA01F4CF90938815AB -:10B8F000809387158D3E914061F4EAE9F3E1CF0131 -:10B900008A59934121912223D1F3909388158093F2 -:10B91000871581E0089580E00895FC0120E03EE273 -:10B92000DB014C91403241F0283011F430833196E4 -:10B93000DB014C91408331962F5F6F5F7F4F2B303F -:10B9400079F7108208951092560F1092470F409188 -:10B95000E7065091E806E8E4FFE080E090E061E06F -:10B9600070E09B01082E02C0220F331F0A94E2F7F9 -:10B9700024233523232B11F4118210820196329651 -:10B980008730910571F70895FF920F931F93CF931E -:10B99000DF93FC01F080F11002C0F12C17C08B0185 -:10B9A000EC010F94258889819A819801280F391F0D -:10B9B0002817390720F06217730738F403C062179D -:10B9C000730758F36817790740F718828F2DDF91B6 -:10B9D000CF911F910F91FF900895CF93DF93EC01CA -:10B9E0000F9425887A83698381E08883DF91CF91E2 -:10B9F00008958F929F92AF92BF92CF92DF92EF9273 -:10BA0000FF921F93CF93DF93FC011081111102C0AD -:10BA100010E027C06A017B01EC010F9425884B01DF -:10BA20005C0189819A81AB81BC81B701A601480F75 -:10BA3000591F6A1F7B1F481759076A077B0730F099 -:10BA400084169506A606B70658F405C08416950612 -:10BA5000A606B706E8F288169906AA06BB06C0F63F -:10BA60001882812FDF91CF911F91FF90EF90DF908F -:10BA7000CF90BF90AF909F908F900895CF93DF931A -:10BA8000EC010F94258869837A838B839C8381E002 -:10BA90008883DF91CF9108950F931F93CF93DF9306 -:10BAA000EB010F9425888B010E9478E68F3F49F0C7 -:10BAB0000F942588601B710B6C177D07A8F380E03D -:10BAC00001C081E0DF91CF911F910F9108950F93F5 -:10BAD0001F93CF93DF93EC0189018C81833039F080 -:10BAE00089E0440F551F661F771F8A95D1F79A0189 -:10BAF000AB0168E1CE010E947FE6882311F086E069 -:10BB000030C08EEF8EBDF801C8019E5F0DB407FEF8 -:10BB1000FDCF20812EBD0DB407FEFDCF21812EBDAE -:10BB200032968E179F0791F70DB407FEFDCF8FEF6A -:10BB30000E9473E68FEF0E9473E60E9478E68B8383 -:10BB40008F71853031F083E18983CE010E946EE6EA -:10BB500009C068E572E0CE019FDF182F811107C090 -:10BB600087E18983CE010E946EE610E012C020E0DA -:10BB700030E0A9016DE0CE010E947FE6811104C092 -:10BB80000E9478E6882311F086E1EBCFCE010E9477 -:10BB90006EE6812FDF91CF911F910F910895CF9382 -:10BBA000809156138823A9F140914E1350914F1361 -:10BBB00060915013709151132EE431E1809157132D -:10BBC0009091581384DFC82F811102C0C0E022C0B9 -:10BBD0004091521350915313609154137091551327 -:10BBE000411551056105710589F02EE431E180911F -:10BBF0005713909158136BDF882341F3109252131F -:10BC0000109253131092541310925513109256130E -:10BC100001C0C1E08C2FCF910895CF92DF92EF92B7 -:10BC2000FF92CF936B017C01C42F80914E139091B2 -:10BC30004F13A0915013B09151138C159D05AE0573 -:10BC4000BF05C1F0ACDF811102C080E017C02EE457 -:10BC500031E1B701A601809157139091581378DC18 -:10BC6000882399F3C0924E13D0924F13E092501351 -:10BC7000F092511381E0C11180935613CF91FF9040 -:10BC8000EF90DF90CF9008954F925F926F927F92E6 -:10BC90008F929F92AF92BF92CF92DF92EF92FF92DC -:10BCA0000F931F93CF93DF93EC0142305105610551 -:10BCB000710510F480E068C089859A85AB85BC85E4 -:10BCC0000196A11DB11D84179507A607B70790F32C -:10BCD0008F89803149F4852E962EA72EBB248B891F -:10BCE0009C89AD89BE890FC0803221F78B889C88E2 -:10BCF000AD88BE88DB01CA01E7E0B695A7959795A8 -:10BD00008795EA95D1F7880E991EAA1EBB1E2801B9 -:10BD100039016A017B0141E0C501B4017EDF88235E -:10BD200049F29F89903161F4DD24EE24FF249601CD -:10BD3000220F331FF901E25BFE4E5182408211C097 -:10BD4000E894C7F8DD24EE24FF249601220F331F68 -:10BD5000220F331FF901E25BFE4E40825182628264 -:10BD600073829A89923080F04D815E816F817885EF -:10BD7000840E951EA61EB71E8092521390925313E6 -:10BD8000A0925413B0925513DF91CF911F910F9150 -:10BD9000FF90EF90DF90CF90BF90AF909F908F90EB -:10BDA0007F906F905F904F900895CF92DF92EF92C7 -:10BDB000FF920F931F93CF93DF93FC0181859285B0 -:10BDC000A385B4850196A11DB11D84179507A6070B -:10BDD000B70710F480E061C08789803149F4BB2740 -:10BDE000A72F962F852FC388D488E588F6880FC0A3 -:10BDF000803281F783899489A589B6896A017B019C -:10BE0000C7E0F694E794D794C794CA95D1F78C0D00 -:10BE10009D1DAE1DBF1DE9016A017B018F0140918F -:10BE20004E1350914F13609150137091511384171A -:10BE30009507A607B70799F4F80187898031B1F40F -:10BE4000B701A601552766277727440F551FFA012A -:10BE5000E25BFE4E80819181A0E0B0E019C040E03D -:10BE6000BC01CD01DADE8111E7CFB4CFB701A60165 -:10BE70004F77552766277727440F551F440F551FC7 -:10BE8000FA01E25BFE4E80819181A281B381BF7095 -:10BE900088839983AA83BB8381E0DF91CF911F912F -:10BEA0000F91FF90EF90DF90CF9008954F925F92A7 -:10BEB0006F927F92AF92BF92CF92DF92EF92FF92FA -:10BEC0000F931F93CF93DF9300D01F92CDB7DEB7B0 -:10BED0008C0149835A836B837C835901C12CD12CFB -:10BEE0007601412C82E0582E612C712C49815A81B7 -:10BEF0006B817C819E012F5F3F4FC80156DF8823F5 -:10BF000041F1D301C201F801058404C0880F991FD3 -:10BF1000AA1FBB1F0A94D2F7C80ED91EEA1EFB1E29 -:10BF200049815A816B817C818789803139F481E034 -:10BF3000483F5F4F6105710538F4D8CF81E0483F35 -:10BF40005F4F6F4F7F4090F2F501C082D182E28255 -:10BF5000F3820F900F900F900F90DF91CF911F9170 -:10BF60000F91FF90EF90DF90CF90BF90AF907F90B8 -:10BF70006F905F904F9008950F931F93CF93DF932F -:10BF8000FC012381222311F080E043C08B01EC01EE -:10BF9000FB018789803131F18032B1F783E08B83F7 -:10BFA000F801428D538D648D758D4D8B5E8B6F8B3B -:10BFB000788F9E012F5E3F4FC80178DF882321F3E1 -:10BFC0001A8F098F81E089831C821D821E821F8245 -:10BFD000188619861A861B861C861D861E861F8655 -:10BFE000188A17C082E08B831D8A1E8A1F8A188ECA -:10BFF000FB01808D918DA0E0B0E025E0880F991FB6 -:10C00000AA1FBB1F2A95D1F7898B9A8BAB8BBC8B50 -:10C01000D7CFDF91CF911F910F9108958F929F926B -:10C02000AF92BF92CF92DF92EF92FF920F931F9346 -:10C03000CF93DF93EC018B81811102C080E077C048 -:10C0400009891A892B893C890417150726073707A0 -:10C05000A8F36A017B01823029F4C886D986EA8672 -:10C06000FB860DC0C114D104E104F10451F41C821B -:10C070001D821E821F82188619861A861B8681E001 -:10C0800056C088849984AA84BB84E98DFA8D25855D -:10C0900030E0275F3F4FB501A401415051096109CC -:10C0A0007109022E04C076956795579547950A94B5 -:10C0B000D2F7D701C6010197A109B10904C0B6950D -:10C0C000A795979587952A95D2F784179507A60780 -:10C0D000B70720F089288A288B2871F44D895E895A -:10C0E0006F89788D4C835D836E837F834C015D0106 -:10C0F0008E010C5F1F4F15C0841B950BA60BB70B51 -:10C10000F5CF4C815D816E817F819801898D9A8DFB -:10C110004CDE91E0891A9108A108B108882309F43E -:10C120008DCF81149104A104B10459F796CFDF910A -:10C13000CF911F910F91FF90EF90DF90CF90BF9024 -:10C14000AF909F908F90089540E050E0BA0166CF85 -:10C150003F924F925F926F927F928F929F92AF9297 -:10C16000BF92CF92DF92EF92FF920F931F93CF93E4 -:10C17000DF93CDB7DEB72C970FB6F894DEBF0FBEB6 -:10C18000CDBF5C01DC0159968D909C905A97F401CB -:10C1900081859285A385B4859C01AD012F5F3F4FBA -:10C1A0004F4F5F4F29873A874B875C87D50114969D -:10C1B000CD90DD90ED90FC901797C114D104E1046F -:10C1C000F10439F0BFEFCB1ADB0AEB0AFB0A312C82 -:10C1D00007C0F401C080D180E280F380332433941F -:10C1E000260137011D821E821F821886F401818577 -:10C1F0009285A385B4852D813E814F81588528176E -:10C2000039074A075B0708F061C089859A85AB85C5 -:10C21000BC858C159D05AE05BF0550F482E0C82E87 -:10C22000D12CE12CF12C92E0492E512C612C712C57 -:10C230009E012F5F3F4FB701A601C401B6DD8823E1 -:10C2400009F444C089819A81AB81BC81892B8A2BF6 -:10C250008B2B41F0260137019FEF491A590A690AD1 -:10C26000790A05C0C414D504E604F70491F02D81C1 -:10C270003E814F8158852F5F3F4F4F4F5F4F2D833A -:10C280003E834F8358873FEFC31AD30AE30AF30A6A -:10C29000ADCF0FEF1FEF2FEF3FE0B301A201C401BD -:10C2A000F3DCF82E882391F0D50114964D915D9121 -:10C2B0006D917C911797411551056105710541F00C -:10C2C00093018201C401E0DC811102C0F12C29C07C -:10C2D000D50114964D925D926D927C921797332002 -:10C2E00051F0D301C2010196A11DB11DF40180835B -:10C2F0009183A283B383F50185899689A789B08D3F -:10C30000892B8A2B8B2B69F4D50155964D925D9222 -:10C310006D927C92589711968C9111978068119626 -:10C320008C938F2D2C960FB6F894DEBF0FBECDBF29 -:10C33000DF91CF911F910F91FF90EF90DF90CF9001 -:10C34000BF90AF909F908F907F906F905F904F9035 -:10C350003F9008952F923F924F925F926F927F92FB -:10C360008F929F92AF92BF92CF92DF92EF92FF9205 -:10C370000F931F93CF93DF9300D01F92CDB7DEB7FB -:10C380009C838B834B015A01DC0113968C918111A4 -:10C3900003C08FEF9FEFE8C0EB81FC81818180FFBC -:10C3A000F8CFAB81BC8151960D911D912D913C919F -:10C3B000549718964D915D916D917C911B97C50195 -:10C3C000A0E0B0E068017901C41AD50AE60AF70ACC -:10C3D0008C159D05AE05BF0518F05801A41AB50AC5 -:10C3E00075018B819C8104969A838983612C42E03C -:10C3F000742EE114F10409F48AC0AB81BC81189653 -:10C400004D915D916D917C911B976A01B1E0DB22AA -:10C41000EB81FC812381818D928D1A012B0139E002 -:10C4200056944794379427943A95D1F7223061F483 -:10C43000FC01828D938DA48DB58DBC01CD01620D63 -:10C44000731D841D951D49C0DC0114961C9111506B -:10C450001221C114D104F9F411111DC0452B462B32 -:10C46000472B59F4EB81FC8185899689A789B08D8A -:10C4700084839583A683B7830EC0AB81BC81149659 -:10C480004D915D916D917C91179729813A818DDC59 -:10C49000882309F47ECFEB81FC81218D328D84814C -:10C4A0009581A681B7810297A109B109F901058497 -:10C4B00004C0880F991FAA1FBB1F0A94D2F7468594 -:10C4C000578560897189840F951FA61FB71FBC010E -:10C4D000CD01610F711D811D911D93012C193D0925 -:10C4E00087012E153F0508F489010115F2E01F07A9 -:10C4F00071F520914E1330914F134091501350918C -:10C500005113621773078407950719F420C0C501FA -:10C510002BC09401AB01BC0180915713909158132B -:10C5200017D8882309F435CF800E911EEB81FC814A -:10C5300080859185A285B385800F911FA11DB11DB6 -:10C5400080879187A287B387E01AF10A52CF40E033 -:10C5500064DB882309F41DCFB601625B7E4EA8011F -:10C56000C4010F9405B9E0CF0F900F900F900F907A -:10C57000DF91CF911F910F91FF90EF90DF90CF90BF -:10C58000BF90AF909F908F907F906F905F904F90F3 -:10C590003F902F900895DF92EF92FF920F931F9399 -:10C5A000CF93DF938C01EB017A018DE0D82E40E22E -:10C5B00050E0BE01C801CEDE8032910539F021E0A5 -:10C5C000892B09F420E0822F819547C028812223FE -:10C5D000C1F0253E61F32E3251F33B853F733F306E -:10C5E00061F4E114F10449F04A8D5B8D452B29F487 -:10C5F0002F713FEF320F343030F02B8523FDD7CF32 -:10C600002CC080E02AC030E021503109D29EC00108 -:10C61000D39E900D1124F701E80FF91F2981208383 -:10C620002B8121832D8122832F81238329852483BC -:10C630002E852583288926832A8927832C8920878C -:10C640002E892187288D22872C8D23872E8D248764 -:10C65000288126FFD2CF1586D0CFDF91CF911F91B1 -:10C660000F91FF90EF90DF900895CF93DF931F928B -:10C67000CDB7DEB741E050E0BE016F5F7F4F6ADEAD -:10C68000019719F4898190E002C08FEF9FEF0F901E -:10C69000DF91CF910895CF93DF93EC0141E06111D9 -:10C6A00001C040E06C857D858E859F85B6DA882344 -:10C6B00041F0888920E2829FC0011124825B9E4E56 -:10C6C00002C080E090E0DF91CF910895CF93DF9397 -:10C6D000EB01FC012381211102C080E027C0225020 -:10C6E000223020F48FE2888319821FC060E0D3DFFC -:10C6F000009799F3FC0190E080E02EE23081303227 -:10C7000069F0883029F4DE01A90FB11D2C939F5FD9 -:10C71000DE01A90FB11D30813C939F5F8F5F319681 -:10C720008B3061F7C90FD11D188281E0DF91CF9165 -:10C730000895CF93DF93EC018B81882329F18981C0 -:10C7400087FF1FC061E0CE01A6DFFC01892BE1F06D -:10C750008081853EC9F08B81823040F489899A8935 -:10C76000AB89BC89848F958FA68FB78F8D899E8961 -:10C77000AF89B88D938F828FB58BA48B89818F778A -:10C780008983DF91CF910BCA81E0888380E0DF91BC -:10C79000CF910895CF93DF93EC01CBDF1B82DF9124 -:10C7A000CF9108958F929F92AF92BF92CF92DF92D6 -:10C7B000EF92FF920F931F93CF93DF93EC018B01C6 -:10C7C0006A01F22EDB0159968D919C915A979A8FAE -:10C7D000898FCB01B9DCE12CF80180859185A28598 -:10C7E000B385418952896389748984179507A6079F -:10C7F000B70708F051C025E0B695A795979587959E -:10C800002A95D1F7F82FFF70BF2ED80113968C917F -:10C81000823008F44FC0C80128DF97FD4BC0F801F3 -:10C8200080859185A285B3854F96A11DB11D808716 -:10C830009187A287B387F0E2BF9EB0011124625BAB -:10C840007E4E61157105B1F1DB018C91882319F0E1 -:10C85000853EB9F456C1E1100DC080914E13909100 -:10C860004F13A0915013B09151138C879D87AE87C1 -:10C87000BF87B88AFB018081882361F0EE24E394AE -:10C88000ABCF4BE050E0C6010F94F8B8892B09F00C -:10C89000A3CF12C0EE24E3948F2D8274823451F41E -:10C8A000EE2009F471C0B88861E0CE01F4DE009793 -:10C8B00009F0F2C080E028C1F7FCFCCF20E2B29E74 -:10C8C000F00111249F01225B3E4ED9011B968C91F1 -:10C8D000817121F08F2D827109F054C080914E1327 -:10C8E00090914F13A0915013B09151138C879D8755 -:10C8F000AE87BF87B88AE25BFE4E4489558960E007 -:10C9000070E0DA01992788278D8B9E8BAF8BB88FCB -:10C91000428D538D60E070E0482B592B6A2B7B2BA6 -:10C920004D8B5E8B6F8B788FD9011B968C918871A4 -:10C9300051F4848D958DA68DB78D898B9A8BAB8B99 -:10C94000BC8B81E00BC08031E9F49E012F5E3F4F2C -:10C95000898D9A8DABDA8823A9F084E08B838F2DA3 -:10C960008F7089831C821D821E821F821886198601 -:10C970001A861B86F4FEAFC0CE010F94E67A8111B1 -:10C98000AAC098CF1B8296CFD80113968C9113978B -:10C99000823009F48FCF51968D919D910D90BC916D -:10C9A000A02D803E9F4FAF41B10508F083CFC80155 -:10C9B000CFDB882309F47ECFF2D8882309F47ACF1D -:10C9C000D80159962D913C915A9714968D919D912D -:10C9D0000D90BC91A02D0297A109B109F901058420 -:10C9E00004C0880F991FAA1FBB1F0A94D2F7868420 -:10C9F0009784A088B188880E991EAA1EBB1E81E06C -:10CA00008093561380924E1390924F13A09250131E -:10CA1000B092511380E092E0EEE4F1E1DF019C017D -:10CA20001D9221503040E1F7EE24E394D80159964D -:10CA3000ED91FC915A978481E81690F42EE431E14F -:10CA4000B501A4014E0D511D611D711D809157133B -:10CA5000909158133CD8882309F42CCFE394E6CF67 -:10CA600080E092E0A0E0B0E0058404C0880F991F48 -:10CA7000AA1FBB1F0A94D2F7F80141895289638922 -:10CA80007489840F951FA61FB71F818B928BA38B70 -:10CA9000B48B8EE491E1B12C20E2DC011D922A9549 -:10CAA000E9F72BE0F601DC0101900D922A95E1F700 -:10CAB00021E238E2FC01318B208B40E058E05787BF -:10CAC0004687338B228B318F208F578B468B67D8CD -:10CAD0008111F4CEEFCEF5FE12C049895A896B89D7 -:10CAE0007C89CE01DF91CF911F910F91FF90EF9044 -:10CAF000DF90CF90BF90AF909F908F908FCA81E0D2 -:10CB000003C0E110BBCEA9CEDF91CF911F910F9151 -:10CB1000FF90EF90DF90CF90BF90AF909F908F905D -:10CB200008952F923F924F925F926F927F928F92D1 -:10CB30009F92AF92BF92CF92DF92EF92FF920F93AC -:10CB40001F93CF93DF93CDB7DEB7C254D1090FB691 -:10CB5000F894DEBF0FBECDBF4C015B016A01322EDF -:10CB600019821C821C8E1F8E672B11F410E093C05B -:10CB7000FC0183818111FACFFA0180818F3261F447 -:10CB8000CA016C010196F60120812F32D1F3F50123 -:10CB900083818250823010F485010AC0618D728DCC -:10CBA000CE014C96E9D9882309F38E01045E1F4F0C -:10CBB000CE0101967C013C012E019CE1490E511CE5 -:10CBC0002396EFAE23972F2C2FC020E221938E17B0 -:10CBD0009F07D9F7B60190E027E0DB018D91811125 -:10CBE00029C08FA9803211F26B01FB0180816F5F38 -:10CBF0007F4F8F32C9F3882309F448C021E0B80180 -:10CC0000C701D0DD882309F4B1CF0A151B0511F047 -:10CC1000C801C0DD6E147F04B1F123969FAD239748 -:10CC2000822D8701E92EF82EFE01F796CF010B9693 -:10CC3000AF01CBCF8F32A9F28E3239F42A3009F40A -:10CC400095CF98E02AE0BD01C8CFEBEBFCE334912F -:10CC5000332321F031968313FACF88CF291708F4B4 -:10CC600085CF3FED380F3E3508F080CF31E0390FEA -:10CC7000FA01E90FF11D9FE9980F9A3108F48052EB -:10CC80008083932FE0CF942D852DCBCF232DB8011A -:10CC9000C40188DD182FCE014C960E94BDA7CE019D -:10CCA00001960E94BDA7812FCE5BDF4F0FB6F8948F -:10CCB000DEBF0FBECDBFDF91CF911F910F91FF90CF -:10CCC000EF90DF90CF90BF90AF909F908F907F902C -:10CCD0006F905F904F903F902F90089561E0FC011E -:10CCE00080810D94DC858EBD0DB407FEFDCF0895C7 -:10CCF0008FEF8EBD0DB407FEFDCF8EB508958F92D8 -:10CD00009F92AF92BF92EF92FF921F93CF93DF93C8 -:10CD1000EC01162F49015A019A81892F806A869564 -:10CD20008CBD90FD03C081E0963009F480E08DBD9C -:10CD300060E088810F94DC856CE271E0CE010E9496 -:10CD40004CDD812F8064CFDF88E1E82EF12CD50106 -:10CD5000C4010E2C04C0B695A795979587950A94A3 -:10CD6000D2F7C1DF88E0E81AF10888EFE8168FEF04 -:10CD7000F80669F7112391F0183011F487E801C023 -:10CD80008FEFB1DF1C3009F4B3DF10E0B1DF8B832C -:10CD900087FF07C01F3F29F01F5FF8CF85E9A3DF9A -:10CDA000F4CFDF91CF911F91FF90EF90BF90AF90A4 -:10CDB0009F908F9008952F923F924F925F926F9223 -:10CDC0007F928F929F92AF92BF92CF92DF92EF921B -:10CDD000FF920F931F93CF93DF93CDB7DEB72897C2 -:10CDE0000FB6F894DEBF0FBECDBF1B012C017090B3 -:10CDF0009C0E7092FE0C71100EC06091980E709196 -:10CE0000990E80919A0E90919B0E0F944EB570934F -:10CE10008A156093891581E090E09093340E809399 -:10CE2000330E0F942588472D0F946B1182E090E00C -:10CE30009093340E8093330E8091940E9091950EC2 -:10CE4000A091960EB091970E80937E0290937F02F0 -:10CE5000A0938002B09381028091930E8093320F51 -:10CE60008091910E9091920E9093BC198093BB1972 -:10CE7000A201910160918D0E70918E0E80918F0EA6 -:10CE80009091900E0F94EEB36D837E838F8398877D -:10CE9000CE0105960E94D5BDA201910160918D0E33 -:10CEA00070918E0E80918F0E9091900E0F94EEB334 -:10CEB00069837A838B839C83E0903D10F0903E10D1 -:10CEC00000913F10109140102091850E3091860EF8 -:10CED0004091870E5091880E6091810E7091820E64 -:10CEE0008091830E9091840EEEEF6E2EECE07E2EFC -:10CEF0007F926F92F2E68F2EF7E29F2EF6E7AF2E2B -:10CF0000F2E4BF2EFE0131966F010E9451870F940B -:10CF10009883A201910160918D0E70918E0E809187 -:10CF20008F0E9091900E0F94EEB369837A838B836A -:10CF30009C83E090890EF0908A0E00918B0E1091E8 -:10CF40008C0E2091850E3091860E4091870E509167 -:10CF5000880E6091810E7091820E8091830E909167 -:10CF6000840E7F926F920E9451870F949883E09075 -:10CF7000890EF0908A0E00918B0E10918C0E2091EC -:10CF8000850E3091860E4091870E5091880E6091EB -:10CF9000810E7091820E8091830E9091840E7F920B -:10CFA0006F92812C912CACE0AA2EA2E4BA2EBDE89F -:10CFB000CB2EBEE0DB2E0E9451870F94988380E138 -:10CFC000E1E8FEE0A5E3B0E101900D928A95E1F77A -:10CFD00080E1E5E3F0E1A9ECBFE001900D928A95D4 -:10CFE000E1F780917C0E0F900F900F900F900F90B3 -:10CFF0000F9081112AC040907D0E50907E0E60905F -:10D000007F0E7090800E40925B1950925C19609276 -:10D010005D1970925E19B301A20186EA98E10E943F -:10D020000EE04092270D5092280D6092290D7092CB -:10D030002A0D81E08093801680EA9EE39F938F9370 -:10D040000F9493AD0F900F9018C08130B1F4809180 -:10D050007D0E90917E0EA0917F0EB091800E8093F8 -:10D060002D0D90932E0DA0932F0DB093300D109297 -:10D070009413109293130F94DF128FEB94E10F949B -:10D08000EE5110923F0E28960FB6F894DEBF0FBEF9 -:10D09000CDBFDF91CF911F910F91FF90EF90DF9067 -:10D0A000CF90BF90AF909F908F907F906F905F9048 -:10D0B0004F903F902F9008954F925F926F927F9282 -:10D0C0008F929F92AF92BF92CF92DF92EF92FF9298 -:10D0D0000F931F93CF93DF93CDB7DEB7E0970FB6D3 -:10D0E000F894DEBF0FBECDBF4B015C0129013A01B0 -:10D0F000F894809180168823F9F0C090270DD09085 -:10D10000280DE090290DF0902A0D0E9447BDC81A05 -:10D11000D90AE108F1080E94B3A0C81AD90AE108A7 -:10D12000F108C0927D0ED0927E0EE0927F0EF092BA -:10D13000800E10927C0E29C080913C07882329F133 -:10D14000C0902D0DD0902E0DE0902F0DF090300D51 -:10D150000E9447BDC81AD108E108F10880919813D0 -:10D1600090919913092E000CAA0BBB0BC81AD90A6F -:10D17000EA0AFB0AC0927D0ED0927E0EE0927F0EEC -:10D18000F092800E81E080937C0E90910007809158 -:10D19000FF06981799F0E091FF0627E5E29FF0015E -:10D1A0001124EA57F84F20E030E040E752E462A152 -:10D1B00073A184A195A10F94F5A708C060917E0288 -:10D1C00070917F0280918002909181026093940E11 -:10D1D0007093950E8093960E9093970E0E948F9564 -:10D1E00080E1E5E3F0E1A1E8BEE001900D928A95CF -:10D1F000E1F7E091FE0CE0939C0EF0E0EE0FFF1FD4 -:10D20000E757FA4E60817181072E000C880B990B4D -:10D210000F948EAE6093980E7093990E80939A0E31 -:10D2200090939B0E8091320F8093930E8091BB1947 -:10D230009091BC199093920E8093910E0E942DDCD8 -:10D240001092801681E080933F0EB19A1092850073 -:10D250001092840080ED97E090938900809388007D -:10D26000789420E030E0A901C501B4010F9488AEA4 -:10D2700081110AC020E030E0A901C301B2010F947E -:10D2800088AE882309F472C08091930E9E012F5FAF -:10D290003F4F7901811109C06CE97EE3C9010F9408 -:10D2A0003EAC60E0C7010E9465DB67E97EE3C70131 -:10D2B0000F943EACF70101900020E9F78F01015077 -:10D2C000110923E046E0C301B2010F94A9A864E963 -:10D2D0007EE3C7010F9433ACF70101900020E9F71A -:10D2E0008F010150110923E048E060E070EC88E212 -:10D2F00095E40F94A9A860E0C7010E9465DB6FE880 -:10D300007EE3C7010F943EACF70101900020E9F7DE -:10D310008F01015011092091890E30918A0E4091A0 -:10D320008B0E50918C0EC501B4010F94EFB323E026 -:10D3300048E00F94A9A86CE87EE3C7010F9433ACD2 -:10D34000F70101900020E9F78F010150110923E056 -:10D3500048E060E070E088E494E40F94A9A860E0FD -:10D36000C7010E9465DB81E080939713E0960FB6BA -:10D37000F894DEBF0FBECDBFDF91CF911F910F910B -:10D38000FF90EF90DF90CF90BF90AF909F908F90E5 -:10D390007F906F905F904F9008958F929F92AF9281 -:10D3A000BF92CF92DF92EF92FF92CF93DF930F94D1 -:10D3B00025886B017C0120914F02222309F47BC058 -:10D3C00040912202509123024130510509F473C06B -:10D3D00080914B0290914C02A0914D02B0914E026F -:10D3E00046015701881A990AAA0ABB0A30E0A8EE3A -:10D3F000B3E00F94DFB386169706A806B9060CF4BF -:10D4000062C04430510559F14CF4423051050CF4DE -:10D4100052C0E6E9FEE58491EF0109C045305105AF -:10D4200009F049C0E6E9FEE58491EF0130C08823A8 -:10D4300031F00E946EAD2196FE018491F8CFEBE7AA -:10D44000FEE38491EF01882331F00E946EAD2196B6 -:10D45000FE018491F8CF8AE00E946EAD2CC0E6E90F -:10D46000FEE58491EF01882331F00E946EAD219694 -:10D47000FE018491F8CFE5E6FEE38491EF01882375 -:10D4800051F30E946EAD2196FE018491F8CF88235E -:10D4900031F00E946EAD2196FE018491F8CFEEE44A -:10D4A000FEE38491EF018823B1F20E946EAD2196D4 -:10D4B000FE018491F8CFC0924B02D0924C02E092D0 -:10D4C0004D02F0924E02DF91CF91FF90EF90DF90EE -:10D4D000CF90BF90AF909F908F9008958F929F9222 -:10D4E000AF92BF92CF92DF92EF92FF920F931F9372 -:10D4F000CF93DF93C5E3D0E120E030E048EC51E486 -:10D500006C857D858E859F850F94EFB36C877D87B5 -:10D510008E879F87E884F9840A851B852C813D814D -:10D520004E815F81688179818A819B81EEEFFCE089 -:10D53000FF93EF93E3E38E2E982CE3E5AE2EE0E429 -:10D54000BE2EF1E4CF2EF0E1DF2E0E9451870F9026 -:10D550000F90DF91CF911F910F91FF90EF90DF908F -:10D56000CF90BF90AF909F908F9008953F924F9231 -:10D570005F926F927F928F929F92AF92BF92CF9263 -:10D58000DF92EF92FF920F931F93CF93DF93CDB76C -:10D59000DEB7C855D1090FB6F894DEBF0FBECDBFB8 -:10D5A000B82E81E00F94273782E00F94932F86E8FE -:10D5B0009FE30F94EE5185EA9FE00F9463B3A82E8A -:10D5C0008DE99FE00F946BB3609335107093361024 -:10D5D000809337109093381081EA9FE00F946BB3DB -:10D5E0006093391070933A1080933B1090933C10E5 -:10D5F00022E0A21209C08AED9EE00F946BB36B018A -:10D600007C0188ED9EE008C08DE89FE00F946BB32D -:10D610006B017C0183E79FE00F9470B367E074E0D7 -:10D62000681B790BE4E076956795EA95E1F780E071 -:10D6300090E00F948CAE209185103091861040912F -:10D640008710509188100F94DDB42B013C012AE023 -:10D6500037ED43E25FE3C701B6010F94EFB39B01DF -:10D66000AC01C301B2010F94EFB360933D1070930E -:10D670003E1080933F109093401082E79FE00F94FC -:10D6800063B3882391F18EE69FE00F946BB36093B0 -:10D69000411070934210809343109093441083E69E -:10D6A0009DE39F938F93CE0101967C019F938F936F -:10D6B0000F94ECADF70101900020E9F78F010150C4 -:10D6C0001109609141107091421080914310909126 -:10D6D000441023E046E00F94A9A860E0C7010E942F -:10D6E00065DB0F900F900F900F9080E1E5E3F0E184 -:10D6F000A9ECBFE001900D928A95E1F7E1E3FDE32B -:10D7000084918F01882339F00E946EAD0F5F1F4F07 -:10D71000F8018491F7CF809140108F9380913F1052 -:10D720008F9380913E108F9380913D108F938091C5 -:10D730003C108F9380913B108F9380913A108F9380 -:10D74000809139108F93809138108F93809137108A -:10D750008F93809136108F93809135108F938BEB40 -:10D760009EE39F938F930F9493AD0F94EA2E1092A4 -:10D770008C150FB6F894DEBF0FBECDBF55E7E52E72 -:10D780005FE0F52E912C63E0762E6E013FE1C30E33 -:10D79000D11C6624639477E0872E892D672D0F9422 -:10D7A00080B8082F592E42E050E0B701C6010F940F -:10D7B00053B36F8D78A16115710511F060928C15CE -:10D7C000282D020380011124050D111D57FC1A9507 -:10D7D000000F111F000F111F04571A4E072E000CC7 -:10D7E000880B990B0F948EAE2FE632E143E85AE393 -:10D7F0000F94F5A7F80161837283838394839394D4 -:10D80000F2E0EF0EF11C29E09212C7CF80918C1547 -:10D8100081110F940D610F94152AE0903D10F09046 -:10D820003E1000913F10109140102091391030911E -:10D830003A1040913B1050913C106091351070911E -:10D84000361080913710909138100F94BA5981E0BA -:10D850008093FF0C17988093000D16988093010D0C -:10D860001598EFEFFCE384918F01882339F00E9433 -:10D870006EAD0F5F1F4FF8018491F7CF82E00F94D8 -:10D880008583962E872E782E692E81E00F948583CE -:10D89000162F072FF82EE92E80E00F9485836F92C4 -:10D8A0007F928F929F92EF92FF920F931F939F937D -:10D8B0008F937F936F9382EE9EE39F938F930F944A -:10D8C00093AD8CE89FE00F9463B3E091FE0CF0E021 -:10D8D000EE0FFF1FE757FA4E90E0918380838BE8AD -:10D8E0009FE00F9463B390E09093030D8093020D3B -:10D8F00088EE9EE00F946BB36093470270934802EA -:10D900008093490290934A028EED9EE00F9470B38B -:10D9100090938302809382020FB6F894DEBF0FBE0D -:10D92000CDBF32E0A316A9F020E030E048EC51E48E -:10D9300060913D1070913E1080913F109091401089 -:10D940000F9488AE87FF05C061E082E49EE30E94E9 -:10D9500065DB61E08AE39EE30E9465DBE091FE0CFB -:10D96000F0E0EE0FFF1FE757FA4E81818F93808121 -:10D970008F9381E39EE39F938F93DF92CF920F94D7 -:10D98000ECAD60E0C6010E9465DB8091030D8F93D2 -:10D990008091020D8F9388E29EE39F938F93DF9295 -:10D9A000CF920F94ECAD60E0C6010E9465DB61E0B0 -:10D9B00084E29EE30E9465DB0FB6F894DEBF0FBEE3 -:10D9C000CDBFB11005C061E089E19EE30E9465DB37 -:10D9D00061E08CEF9DE30E9465DB80913C108F93AA -:10D9E00080913B108F9380913A108F9380913910E2 -:10D9F0008F93809138108F93809137108F938091FF -:10DA000036108F93809135108F938DE39FE39F9312 -:10DA10008F930F9493AD88E89FE00F9463B3382EF3 -:10DA2000BE01695A7F4F89E89FE00E949EFDE2EFA8 -:10DA3000FDE384910FB6F894DEBF0FBECDBF02EFB9 -:10DA40001DE3882339F00E946EAD0F5F1F4FF80170 -:10DA50008491F7CF69966EAD7FAD6997072E000C64 -:10DA6000880B990B0E94F7AD0E94A3AE8AE59FE058 -:10DA70000F9463B3482E512C682F70E080E090E043 -:10DA80000E94F7AD0E94A3AE9BE5C92E9EE0D92E61 -:10DA90000AE01FE0A12CB12CA414B5043CF54E0102 -:10DAA000FAE48F0E911C380128E0620E711C74019B -:10DAB000C8010F9463B3F40181934F010F5F1F4FAF -:10DAC00060167106A9F7F7011086C7010E94A7AE7C -:10DAD000B701C6010F9447B9C7010F94B94BFFEFC7 -:10DAE000AF1ABF0A29E0C20ED11CD6CF8E01035C4B -:10DAF0001F4F580185E9E82E8FE0F82ED02EC12E59 -:10DB0000C7010F9463B3F50181935F01FFEFEF1A33 -:10DB1000FF0A2DE9E2162FE0F20691F726961FAED6 -:10DB20002697F80181918F01882319F00E946EAD2C -:10DB3000F8CF6DEE7DE38D2D9C2D0F9433ACCF92FD -:10DB4000DF9286EE9DE39F938F938E010F5F1F4FB1 -:10DB50001F930F930F94ECAD60E0C8010E9465DB4A -:10DB600081E99FE00F946BB3D62EC72EB82EA92E55 -:10DB7000EBECFDE384910F900F900F900F900F90BE -:10DB80000F907F01882341F00E946EADFFEFEF1AE6 -:10DB9000FF0AF7018491F6CF4AE06D2D7C2D8B2D85 -:10DBA0009A2D0E9486AD0E94A3AE61E087EC9DE3B2 -:10DBB0000E9465DB62EC7DE3C8010F943EAC8DE909 -:10DBC0009FE00F946BB367966CAF7DAF8EAF9FAF46 -:10DBD0006797CE018D5A9F4F0E94C19FBC01C8011B -:10DBE0000F9428B96FEB7DE3C8010F9433AC81EA41 -:10DBF0009FE00F946BB367966CAF7DAF8EAF9FAF16 -:10DC00006797CE018D5A9F4F0E94C19FBC01C801EA -:10DC10000F9428B968EB7DE3C8010F9433AC60E042 -:10DC2000C8010E9465DB63EB7DE3C8010F943EAC45 -:10DC30008DE89FE00F946BB367966CAF7DAF8EAFAE -:10DC40009FAF6797CE018D5A9F4F0E94C19FBC0125 -:10DC5000C8010F9428B960E0C8010E9465DB61E04B -:10DC600085E99DE30E9465DB69968FAD69978F9387 -:10DC700068968FAD68978F938EE89DE39F938F93FF -:10DC80001F930F930F94ECAD60E0C8010E9465DB19 -:10DC900082E79FE00F9463B30F900F900F900F9067 -:10DCA0000F900F90882329F061E08AE89DE30E949D -:10DCB00065DB63E87DE3C8010F943EAC832D90E003 -:10DCC00065969FAF8EAF6597CE018D5A9F4F0E948C -:10DCD000829FBC01C8010F9428B960E0C8010E946E -:10DCE00065DBAF92BF92CF92DF928AE79DE39F936D -:10DCF0008F931F930F930F94ECAD60E0C8010E94C7 -:10DD000065DB61E084E79DE30E9465DB61E089E615 -:10DD10009DE30E9465DB809144108F9380914310B6 -:10DD20008F93809142108F93809141108F938091B7 -:10DD300040108F9380913F108F9380913E108F936E -:10DD400080913D108F938CE09FE39F938F930F946E -:10DD500093AD0FB6F894DEBF0FBECDBFC85ADF4FEC -:10DD60000FB6F894DEBF0FBECDBFDF91CF911F91EC -:10DD70000F91FF90EF90DF90CF90BF90AF909F906A -:10DD80008F907F906F905F904F903F9008951F927B -:10DD90000F920FB60F9211240BB60F922F923F9253 -:10DDA0004F925F926F927F928F929F92AF92BF92AB -:10DDB000CF92DF92EF92FF920F931F932F933F9397 -:10DDC0004F935F936F937F938F939F93AF93BF9383 -:10DDD000EF93FF93CF93DF93CDB7DEB76197DEBFAD -:10DDE000CDBFEC98EAEFFCE384918F01882339F0F2 -:10DDF0000E946EAD0F5F1F4FF8018491F7CF8AE04C -:10DE00000E946EAD80918016882309F478C285EA5D -:10DE10009FE00F9463B3811172C20F9425886D87C0 -:10DE20007E878F87988BF0918016F98B179A1092C6 -:10DE3000FF0C169A1092000D64E182E00F94BF9BD4 -:10DE400064E182E00F94AE9B64E183E00F94BF9B9A -:10DE500064E183E00F94AE9B83E40E94C8C6988778 -:10DE60008F834090270D5090280D6090290D709061 -:10DE70002A0D0E9447BD481A590A610871080E947C -:10DE8000B3A0481A590A6108710877FE03C0412CF3 -:10DE9000512C3201909100078091FF06981799F05C -:10DEA000E091FF0627E5E29FF0011124EA57F84FC1 -:10DEB00020E030E040E752E462A173A184A195A183 -:10DEC0000F94F5A708C060917E0270917F02809147 -:10DED0008002909181020F944EB57E836D830E94E3 -:10DEE0008F9583E00F948583AB01BC018EE69FE0A4 -:10DEF0000F9487B36091320F81E0682782E79FE03B -:10DF00000F9475B30E942DDC10928016789420E057 -:10DF100030E040E85FE360914110709142108091E1 -:10DF20004310909144100F94EEB369837A838B83EE -:10DF30009C83E0903D10F0903E1000913F101091B6 -:10DF400040102091391030913A1040913B1050917F -:10DF50003C1060913510709136108091371090917F -:10DF60003810EEEF2E2EECE03E2E3F922F92812CB9 -:10DF7000912CFEEBAF2EF2E4BF2EFE0131966F0125 -:10DF80000E9451870F949883149A20E030E040E873 -:10DF90005FE3609141107091421080914310909125 -:10DFA00044100F94EEB369837A838B839C8367E07C -:10DFB00074E02F813885621B730BA4E0769567951A -:10DFC000AA95E1F780E090E00F948CAE69877A879C -:10DFD0008B879C872AE037ED43E25FE360913D1039 -:10DFE00070913E1080913F10909140100F94EFB3CC -:10DFF0006B017C0120918510309186104091871033 -:10E000005091881069857A858B859C850F94DDB445 -:10E010009B01AC01C701B6010F94EFB37B018C01EA -:10E020002091391030913A1040913B1050913C10A2 -:10E0300060913510709136108091371090913810A2 -:10E040003F922F92812C912CB0E2AB2EB2E4BB2EEA -:10E05000FE0131966F010E9451870F949883149AA4 -:10E0600020E030E040E85FE36091411070914210A1 -:10E0700080914310909144100F94EEB369837A839A -:10E080008B839C832AE037ED43E25FE360913D1090 -:10E0900070913E1080913F10909140100F94EFB31B -:10E0A0006B017C0120918510309186104091871082 -:10E0B0005091881069857A858B859C850F94DDB495 -:10E0C0009B01AC01C701B6010F94EFB37B018C013A -:10E0D0002091391030913A1040913B1050913C10F2 -:10E0E00060913510709136108091371090913810F2 -:10E0F0003F922F92FE0131966F010E9451870F943B -:10E100009883149AB301A20181E99FE00F9487B329 -:10E110000F900F900F900F900F900F9005E71FE05A -:10E12000712C83E0682E80918C15882341F1872D16 -:10E13000662D0F9480B825E18202F001112433E0AE -:10E140009302E00DF11D1124EE0FFF1FEE0FFF1FD4 -:10E15000E457FA4E20E030E04AE754E461817281EE -:10E16000838194810F94F5A720E030E040E05FE3E5 -:10E170000F94EFB30F9483B50F944EB502C060E0D7 -:10E1800070E0C8010F948FB373940E5F1F4F49E086 -:10E190007412C9CF6F81788583E79FE00F948FB3A6 -:10E1A00040913510509136106091371070913810B1 -:10E1B0008DE99FE00F9487B34091391050913A1048 -:10E1C00060913B1070913C1081EA9FE00F9487B3FF -:10E1D00040913D1050913E1060913F107091401061 -:10E1E0008DE89FE00F9487B3BE016B5F7F4F89E896 -:10E1F0009FE00E94B8FDE091FE0CF0E0EE0FFF1FE3 -:10E20000E757FA4E60818CE89FE00F9475B36091F8 -:10E21000020D8BE89FE00F9475B36091BB1988E8FD -:10E220009FE00F9475B3409147025091480260916E -:10E23000490270914A0288EE9EE00F9487B3609184 -:10E240008202709183028EED9EE00F948FB3598904 -:10E25000552329F061E085EA9FE00F9475B30F9490 -:10E26000988382E00E94C8C69F938F9383EB9EE3BE -:10E270009F938F930F9493AD84E69FE00F9463B3C5 -:10E2800061E0680F84E69FE00F9475B38FEF9EE026 -:10E290000F9470B3BC016F5F7F4F8FEF9EE00F94C0 -:10E2A0008FB30F942588DC01CB012D853E854F85EA -:10E2B0005889821B930BA40BB50BBF93AF939F930D -:10E2C0008F9384EA9EE39F938F930F9493AD9DE089 -:10E2D00088E10FB6F894A895809360000FBE9093E4 -:10E2E00060009FB7F89480910201846080930201DE -:10E2F0009FBF0FB6F894DEBF0FBECDBFFFCF85EA3C -:10E300009FE00F9463B3882309F4A7C0179A109273 -:10E31000FF0C169A1092000D149A64E182E00F949B -:10E32000BF9B64E182E00F94AE9B83E40E94C8C669 -:10E330003C010E948F95789467E074E06619770934 -:10E3400084E0769567958A95E1F780E090E00F94F8 -:10E350008CAE20918510309186104091871050919D -:10E3600088100F94DDB46B017C012AE037ED43E2A5 -:10E370005FE360913D1070913E1080913F1090914D -:10E3800040100F94EFB39B01AC01C701B6010F948D -:10E39000EFB37B018C012091391030913A104091FC -:10E3A0003B1050913C106091351070913610809167 -:10E3B000371090913810EEEFFCE0FF93EF93812C33 -:10E3C000912CE0E2AE2EE2E4BE2EF1E4CF2EF0E19D -:10E3D000DF2E0E9451870F94988362E085EA9FE0C8 -:10E3E0000F9475B3B30188ED9EE00F948FB3409105 -:10E3F0003D1050913E1060913F10709140108AED99 -:10E400009EE00F9487B384E69FE00F9463B361E0CE -:10E41000680F84E69FE00F9475B38FEF9EE00F9432 -:10E4200070B3BC016F5F7F4F8FEF9EE00F948FB38F -:10E430009DE088E10FB6F894A895809360000FBE28 -:10E44000909360009FB7F89480910201846080935C -:10E4500002019FBF0F900F90FFCF61960FB6F89407 -:10E46000DEBF0FBECDBFDF91CF91FF91EF91BF9186 -:10E47000AF919F918F917F916F915F914F913F915C -:10E480002F911F910F91FF90EF90DF90CF90BF9051 -:10E49000AF909F908F907F906F905F904F903F9044 -:10E4A0002F900F900BBE0F900FBE0F901F901895DE -:10E4B0001F920F920FB60F9211242F933F934F93F9 -:10E4C0005F936F937F938F939F93AF93BF932091AD -:10E4D000BB193091BC192B3431050CF449C0809123 -:10E4E0006A0086FF11C08091871990918819A091C8 -:10E4F0008919B0918A1980936E1690936F16A09324 -:10E500007016B09371162EC080918719909188195A -:10E51000A0918919B0918A1940916E1650916F1689 -:10E520006091701670917116841B950BA60BB70B3A -:10E53000253631052CF444E050E060E070E004C082 -:10E5400043E050E060E070E084179507A607B70746 -:10E5500048F08091590F90915A0F029690935A0F5C -:10E560008093590F90916A0080E4892780936A0014 -:10E57000BF91AF919F918F917F916F915F914F91DB -:10E580003F912F910F900FBE0F901F901895CF9233 -:10E59000DF92EF92FF92CF93DF93E091FE0C84E045 -:10E5A000E89FF0011124E452F04FC080D180E28056 -:10E5B000F380E7EFFCE38491EF01882331F00E94C0 -:10E5C0006EAD2196FE018491F8CF42E0C701B601FD -:10E5D0000E9411AEE3EFFCE38491EF01882331F058 -:10E5E0000E946EAD2196FE018491F8CF6091FE0CE1 -:10E5F00070E080E090E00E94F7ADEFEEFCE38491E4 -:10E60000EF01882331F00E946EAD2196FE018491C6 -:10E61000F8CF609108077091090780910A079091DF -:10E620000B0741E00E9411AE8AE0DF91CF91FF908D -:10E63000EF90DF90CF900C946EADCF92DF92EF927F -:10E64000FF920F941D3760E081E00F946E328AEAEA -:10E6500093E40F9495316091AC197091AD19072E28 -:10E66000000C880B990B0F948EAE209154023091C0 -:10E67000550240915602509157020F94EFB36B012F -:10E680007C0120E030E848E953E40F943AB61816CC -:10E690004CF0C0925402D0925502E0925602F09291 -:10E6A00057020CC080E090E8A8E9B3E480935402DC -:10E6B00090935502A0935602B093570220E030E0A9 -:10E6C00040E751E4609154027091550280915602E6 -:10E6D000909157020F9488AE87FF0CC080E090E0C5 -:10E6E000A0E7B1E48093540290935502A0935602A0 -:10E6F000B09357021092AC191092AD191092AE1946 -:10E700001092AF1962E081E00F946E3284E592E0DE -:10E710000E9446A00F9410310F946B30882379F03B -:10E7200087E090E090930210809301100F94388A54 -:10E7300082E0FF90EF90DF90CF900D94932FFF90A9 -:10E74000EF90DF90CF90089561E080EC9FE00F9410 -:10E7500075B360E08FEB9FE00F9475B360E08EEBD4 -:10E760009FE00F9475B360E08DEB9FE00F9475B35D -:10E7700060E08CEB9FE00F9475B3109297190895A9 -:10E780006091460281E068276093460287E89FE037 -:10E790000D9475B30F944E2F1092B0198091B0194B -:10E7A000843008F078C01092B21980917B0E8823D3 -:10E7B00029F08091C80F811108C034C083EF9FE217 -:10E7C0000F94B2368823A9F3089568E971E083ECC9 -:10E7D00090E40F94733681115EC062E072E083EBC7 -:10E7E00090E40F947336811156C06CE371E08CEBAA -:10E7F00091E40F94733681114EC064EC71E081EAAC -:10E8000090E40F947336811146C00F940F2F8091BE -:10E81000B0198F5F8093B0198091B1198F5F809389 -:10E82000B119BCCF6EE871E082E990E40F947336C1 -:10E83000811131C06EEF71E083E890E40F9473367C -:10E84000811129C064EC71E083E790E40F94733682 -:10E85000811121C062E172E083E690E40F94733687 -:10E86000811119C068ED71E083E590E40F9473366F -:10E87000811111C06EEA71E084E490E40F94733664 -:10E88000811109C080917B0E8111BFCF6CE371E0D3 -:10E890008CEB91E4B6CF089580919719811145C012 -:10E8A000109299191092981910929B1910929A1916 -:10E8B00010929D1910929C1910929F1910929E19F6 -:10E8C00080EC9FE00F9463B3813061F58FEB9FE0A4 -:10E8D0000F9463B3082E000C990B909399198093B1 -:10E8E00098198EEB9FE00F9463B3082E000C990BE0 -:10E8F00090939B1980939A198DEB9FE00F9463B3CB -:10E90000082E000C990B90939D1980939C198CEB09 -:10E910009FE00F9463B3082E000C990B90939F19FE -:10E9200080939E1981E0809397190F944E2F109237 -:10E93000B0198091B019843008F082C01092B219D9 -:10E940008091B119811110C08091AB19882361F0B9 -:10E950008091AC199091AD19A091AE19B091AF19F9 -:10E96000892B8A2B8B2B21F0809103108823E9F0CF -:10E97000609198198FEB9FE00F9475B360919A198D -:10E980008EEB9FE00F9475B360919C198DEB9FE027 -:10E990000F9475B360919E198CEB9FE00F9475B343 -:10E9A00061E080EC9FE00F9475B388EA9FE20F94DA -:10E9B000B236811145C022E330E04EEC5FEF68E9EA -:10E9C00079E18BE993E40F946035811139C022E33A -:10E9D00030E04EEC5FEF6AE979E18CE893E40F9464 -:10E9E000603581112DC022E330E04EEC5FEF6CE921 -:10E9F00079E18DE793E40F946035811121C022E322 -:10EA000030E04EEC5FEF6EE979E18EE693E40F942F -:10EA10006035811115C064EA73EF88E693E40F94C2 -:10EA2000733681110DC00F940F2F8091B0198F5F35 -:10EA30008093B0198091B1198F5F8093B11979CF0C -:10EA40000895CF93109251161F92C1E0CF93609119 -:10EA500008077091090780910A0790910B070F949E -:10EA60004EB57F936F931F92CF936091DC0F70919F -:10EA7000DD0F8091DE0F9091DF0F0F944EB57F93E5 -:10EA80006F9384EC9FE39F938F930F942A311F928F -:10EA9000CF936091A10E7091A20E8091A30E9091E0 -:10EAA000A40E0F944EB57F936F931F92CF936091F6 -:10EAB0009D0E70919E0E80919F0E9091A00E0F94CE -:10EAC0004EB57F936F938BE99FE39F938F930F9442 -:10EAD0002A318DB79EB744960FB6F8949EBF0FBEED -:10EAE0008DBFCF910D947E304F925F926F927F9247 -:10EAF0008F929F92AF92BF92CF92DF92EF92FF924E -:10EB0000CF93DF9300D01F92CDB7DEB7109251168E -:10EB10006091A70E7091A80E072E000C880B990B20 -:10EB20000F948EAE20E030EC4FE756E40F94DDB446 -:10EB300020E030E040EA50E40F94F5A727ED30E301 -:10EB400044E45EE30F94DDB44B015C016091A50EDB -:10EB50007091A60E072E000C880B990B0F948EAEA9 -:10EB600020E030EC4FE756E40F94DDB420E030E0D5 -:10EB700040EA50E40F94F5A727ED30E344E45EE368 -:10EB80000F94DDB42B013C010F944EB56B017C0159 -:10EB9000C501B4010F944EB569837A838B839C833E -:10EBA000B6010D2C000C880B990B0F948EAE9B01B7 -:10EBB000AC01C301B2010F94EEB39F7720E030E0C7 -:10EBC00040E251E40F94F5A70F944EB57F936F93F5 -:10EBD000DF92CF9229813A81B901330F880B990BCB -:10EBE0000F948EAE9B01AC01C501B4010F94EEB33E -:10EBF0009F7720E030E040E251E40F94F5A70F94B6 -:10EC00004EB57F936F933A813F9389818F938DEEB9 -:10EC10009FE39F938F930F942A310FB6F894DEBF32 -:10EC20000FBECDBF0F900F900F900F90DF91CF913F -:10EC3000FF90EF90DF90CF90BF90AF909F908F901C -:10EC40007F906F905F904F900D947E304F925F92C7 -:10EC50006F927F928F929F92AF92BF92CF92DF92EC -:10EC6000FF920F931F93CF93DF93CDB7DEB76897D3 -:10EC70000FB6F894DEBF0FBECDBF60E080E00F940A -:10EC80006E3289E493E40F94953145E25BE561E0EF -:10EC900080E00F94123742EA51E462E080E00F9482 -:10ECA000123740EA51E463E080E00F941237AE017E -:10ECB0004F5E5F4FBE01675F7F4FCE0101960F949D -:10ECC000552D8E010F5E1F4F82E0F82E4FE951E463 -:10ECD0006F2D8BE00F9412376801F80180809180CE -:10ECE000A280B38020E030E0A901C501B4010F94F7 -:10ECF00088AE87FF07C08DE20E949D9AB7FAB09454 -:10ED0000B7F8B0942AE037ED43EA5BE3C501B401FC -:10ED10000F94EFB32B013C010F9454B54B015C01F0 -:10ED20000F948CAE9B01AC01C301B2010F94EEB302 -:10ED30002B013C014AE0C501B4010F9482308EE200 -:10ED40000E949D9A20E030E040E251E4C301B2010C -:10ED50000F94F5A72B013C010F944EB54B01770F93 -:10ED6000AA08BB08C501B4010F94F530C501B40170 -:10ED70000F948EAE9B01AC01C301B2010F94EEB3B0 -:10ED800020E030E040E251E40F94F5A70F944EB537 -:10ED9000072E000C880B990B0F94F5300C5F1F4F5A -:10EDA00020E030E0A901F6016081718182819381C8 -:10EDB0000F9488AE881F8827881F4CE951E46F2D77 -:10EDC000805F0F941237F394F4E0FF127FCF0F941B -:10EDD0007E3068960FB6F894DEBF0FBECDBFDF91D0 -:10EDE000CF911F910F91FF90DF90CF90BF90AF9088 -:10EDF0009F908F907F906F905F904F900895CF92EB -:10EE0000DF92EF92FF920F9380E69FE00F946BB337 -:10EE10006B017C018EE38F9380E88F931F921F928A -:10EE200083E293E49F938F938DE38F9385EF8F938A -:10EE300082EC8F9380E98F938FE293E49F938F937B -:10EE400085E29BE59F938F938BE393E49F938F934E -:10EE500088E594E49F938F930F942A318DB79EB7E2 -:10EE600042960FB6F8949EBF0FBE8DBF20E030E0F3 -:10EE700048EC52E4C701B6010F9488AE87FF1FC06B -:10EE800020E030E044E353E4C701B6010F94F5A756 -:10EE90002BED3FE049E450E40F94DDB49F938F9352 -:10EEA0007F936F938AE494E49F938F930F942A3116 -:10EEB0000F900F900F900F900F900F9004C08FE362 -:10EEC00094E40F9495310F946B30882349F001E05E -:10EED00021E040E050E0BA0186E296EF0F94C32FA4 -:10EEE0000F91FF90EF90DF90CF9008954F925F9237 -:10EEF0006F927F928F929F92AF92BF92CF92DF924A -:10EF0000EF92FF920F931F93CF93DF93CDB7DEB7AE -:10EF100029970FB6F894DEBF0FBECDBF89EE9FE0F4 -:10EF20000F946BB369837A838B839C8381EE9FE01C -:10EF30000F946BB34B015C0189ED9FE00F946BB3B1 -:10EF40006B017C01EAEEFEE12591359145915491EA -:10EF5000EEEEFEE185919591A591B4918D839E830E -:10EF6000AF83B887C501B4010F94F5A72B013C010D -:10EF70002D813E814F815885C701B6010F94F5A7B9 -:10EF80009B01AC01C301B2010F94EFB329813A8117 -:10EF90004B815C810F94EFB320E030E040E950E416 -:10EFA0000F94EFB3062F7D838987192FE2EFFEE1DF -:10EFB0002591359145915491E6EFFEE145905590AC -:10EFC00065907490C501B4010F94F5A74B015C01E5 -:10EFD000A3019201C701B6010F94F5A79B01AC01F3 -:10EFE000C501B4010F94EFB329813A814B815C8153 -:10EFF0000F94EFB320E030E040E950E40F94EFB31A -:10F00000F62EE72ED82EC92E84E093E49F938F939B -:10F010008AE093E49F938F9385E29BE59F938F9380 -:10F020008FE093E49F938F938AE294E49F938F936E -:10F030000F942A3162E08BE00F946E320FB6F89491 -:10F04000DEBF0FBECDBF20E030E048E453E4AD8129 -:10F05000F985602F7A2F8F2F912F0F943AB687FF63 -:10F0600013C01F93B985BF938D818F930F938EE14A -:10F0700094E49F938F930F942A310F900F900F90E9 -:10F080000F900F900F9004C086E294E40F94953196 -:10F0900063E08BE00F946E3220E030E048E453E40C -:10F0A000D701F6016B2F7E2D8F2F9C2D0F943AB632 -:10F0B00087FD05C086E294E40F94953110C0CF928D -:10F0C000DF92EF92FF928EE194E49F938F930F94DF -:10F0D0002A310F900F900F900F900F900F900F9478 -:10F0E0006B30882349F001E021E040E050E0BA01B4 -:10F0F0008FEF96EF0F94C32F29960FB6F894DEBFCB -:10F100000FBECDBFDF91CF911F910F91FF90EF9078 -:10F11000DF90CF90BF90AF909F908F907F906F9037 -:10F120005F904F9008952F923F924F925F926F920F -:10F130007F928F929F92AF92BF92CF92DF92EF9287 -:10F14000FF920F931F93CF93DF931C01EB015A01A2 -:10F15000690180918B19811109C08091210210925F -:10F16000210280938C1981E080938B198091AC19D6 -:10F170009091AD19A091AE19B091AF19892B8A2B3E -:10F180008B2B09F4ADC00F94D266809100078F5F7E -:10F19000803109F480E09091FF06981709F4A0C02F -:10F1A0006091AC197091AD19072E000C880B990B6A -:10F1B0000F948EAE2091F60F3091F70F4091F80F1B -:10F1C0005091F90F0F94F5A78E01000F111F000F3A -:10F1D000111F98012B5C3F4E7901F901208131818B -:10F1E000428153810F94EFB32B013C01B501BB0C5D -:10F1F000880B990B0F948EAE4B015C019B01AC0107 -:10F20000C301B2010F9488AEF70187FD05C04082AB -:10F2100051826282738204C080829182A282B38210 -:10F22000B601DD0C880B990B0F948EAE4B015C017F -:10F2300098012B5C3F4E79019B01AC01F701608185 -:10F240007181828193810F943AB618162CF4F701DC -:10F2500080829182A282B3821092AC191092AD1971 -:10F260001092AE191092AF1969E370E185E390E155 -:10F270000E946BA8F801E85DFC4F20E030E040E719 -:10F2800052E460817181828193810F94DDB44B01DE -:10F290005C01E0903D10F0903E1000913F10109105 -:10F2A00040102091391030913A1040913B1050910C -:10F2B0003C1060913510709136108091371090910C -:10F2C0003810EEEFFCE0FF93EF93E1E4CE2EE0E1A7 -:10F2D000DE2E0E94518781E0809386020F900F906E -:10F2E00080918602882389F061E080E00F946E327D -:10F2F000CC0FDD1FCC0FDD1FCB5CDF4E4881598169 -:10F300006A817B81C1010F94E984909103108091FF -:10F310000410911102C082FF04C090918C19909347 -:10F32000210282FF14C0DF91CF911F910F91FF90B6 -:10F33000EF90DF90CF90BF90AF909F908F907F9095 -:10F340006F905F904F903F902F900D944E30DF91D3 -:10F35000CF911F910F91FF90EF90DF90CF90BF90D2 -:10F36000AF909F908F907F906F905F904F903F9065 -:10F370002F90089522ED30E040E050E062E070E030 -:10F3800088EA91E4D0CE24ED30E04CEF5FEF61E00D -:10F3900070E086EA91E4C7CE2FEF30E040E050E025 -:10F3A00060E070E084EA91E4BECE4F925F926F928B -:10F3B0007F928F929F92AF92BF92CF92DF92EF9205 -:10F3C000FF920F931F93CF93DF9380918016882332 -:10F3D00009F494C06091480E7091490E80914A0ED4 -:10F3E00090914B0E0F948CAE20E030E543EC57E447 -:10F3F0000F94DDB4EB01182F092F0F942588C090CE -:10F40000500ED090510EE090520EF090530E4B01E2 -:10F410005C018C189D08AE08BF08C501B40128EE38 -:10F4200033E040E050E00F94B3B369017A01C501C5 -:10F43000B40120E83EEE46E350E00F94B3B3490137 -:10F440005A01A0E1BEE00F94D5B3A7019601261B97 -:10F45000370B480B590BCA01B9012CE330E040E0EF -:10F4600050E00F94B3B360E17EE0869EC001879EBA -:10F47000900D969E900D1124C81AD90A2901032EC9 -:10F48000000C660877086CE3649DC001659D900DD3 -:10F490001124C81AD90ADF92CF923F932F939F92DB -:10F4A0008F928BEE92E49F938F930F931F93DF9332 -:10F4B000CF9386EF92E49F938F938EEE93E49F9386 -:10F4C0008F930F942A314DB75EB7405F5F4F0FB6F1 -:10F4D000F8945EBF0FBE4DBFDF91CF911F910F918A -:10F4E000FF90EF90DF90CF90BF90AF909F908F9064 -:10F4F0007F906F905F904F900D94783081EF9FE0F8 -:10F500000F946BB34B015C018DEE9FE00F946BB3D6 -:10F510006B017C0120EA35E040E050E00F94B3B38A -:10F52000E901142F052FA0EAB5E00F94D5B3A70188 -:10F530009601261B370B480B590BCA01B9012CE366 -:10F5400030E040E050E00F94B3B330E6C39FC00C0E -:10F5500011244CE3249FC01811241F92CF921F92B4 -:10F560002F930F931F93DF93CF938BEC92E49F9392 -:10F570008F93C501B4010F948CAE20E030E048ECCD -:10F5800052E40F94DDB49F938F937F936F938CED30 -:10F5900092E49F938F938BEB93E49F938F930F94BD -:10F5A0002A3184E090E090932302809322028DB769 -:10F5B0009EB742960FB6F8949EBF0FBE8DBF0F94B4 -:10F5C0006B3081110CC00F94BC7D81E00F94680EEC -:10F5D00064E670E080E090E00F940D87F0CF81E06A -:10F5E00090E090932302809322020F94BD2FDF912D -:10F5F000CF911F910F91FF90EF90DF90CF90BF9030 -:10F60000AF909F908F907F906F905F904F900D94F0 -:10F610004E30CF93DF931F92CDB7DEB720E030E0BE -:10F620004FE253E46091DC0F7091DD0F8091DE0FAB -:10F630009091DF0F0F943AB6181644F4BE016F5F35 -:10F640007F4F80E892E40F94670621C080918B1968 -:10F65000811104C08BE899E10E94EDDC60E080E05C -:10F660000F946E3289E792E40F94953162E080E066 -:10F670000F946E3285E692E40F94953160ED77E059 -:10F680008BE899E10E94C4DC81110F944E300F94F5 -:10F690007E300F90DF91CF9108959091410281E0EB -:10F6A00089270C942A9CCF93DF938BE59FE00F94DE -:10F6B00070B3EC018DE59FE00F9470B3DF93CF93AF -:10F6C0009F938F938EE190E49F938F930F942A31B1 -:10F6D0000F900F900F900F900F900F90DF91CF91A0 -:10F6E0000D947E30EF92FF920F931F93CF93DF9391 -:10F6F00080918B19882329F090918602923009F02D -:10F7000080C081E080938B19C0918718CC2309F4C5 -:10F7100051C084E0EDE8F9E1DF011D928A95E9F737 -:10F7200023E030EA4AE050E960E382E898E10E9491 -:10F730007FE6882321F080E88093831836C00F94F9 -:10F7400025888B010E9478E6809385188F3F49F4C5 -:10F750000F942588601B710B6D32714098F381E125 -:10F7600003C08E3F41F08FE08093831882E898E1D8 -:10F770000E946EE61AC00DE819E10E9478E6F801D1 -:10F7800081938F01F9E101391F07B9F70EEF11E0FD -:10F790000E9478E601501109D9F782E898E10E94A9 -:10F7A0006EE68FEF0E9473E605C082E898E10E9442 -:10F7B0006EE6C0E0C0938C19CC23E9F180919019DA -:10F7C0001F928F9380918F191F928F9380918E1922 -:10F7D0001F928F9380918D191F928F938DE791E4E3 -:10F7E0009F938F9381E999E19F938F930F94ECAD51 -:10F7F0008DB79EB70C960FB6F8949EBF0FBE8DBF07 -:10F800001AC090918C199923B1F090918D19911192 -:10F8100012C090918E1991110EC090918F19911173 -:10F820000AC090919019911106C08F5F803109F440 -:10F830001BC180938B190F944E2F1092B019CAE000 -:10F84000D0E084E6E82EF12C0DEF10E48091B019A1 -:10F85000843008F00CC11092B21983EF9FE20F942C -:10F86000B236811104C183E791E40F94B23681115D -:10F87000FEC083E691E40F94B2368111F8C085E5AD -:10F8800091E40F94B2368111F2C080E392E40F94B8 -:10F89000B2368111ECC08EE192E40F94B236811140 -:10F8A000E6C08CE092E40F94B2368111E0C088E4A7 -:10F8B00091E40F94B2368111DAC08DE391E40F9494 -:10F8C000B2368111D4C083E391E40F94B236811132 -:10F8D000CEC089E291E40F94B2368111C8C088E4A9 -:10F8E00091E40F94B2368111C2C086E092E40F9485 -:10F8F000B2368111BCC08DE191E40F94B236811112 -:10F90000B6C088E491E40F94B2368111B0C0809102 -:10F910007B13882309F455C08EE091E40F94B2362E -:10F920008111A5C089E091E40F94B23681119FC086 -:10F930008091B21990E001972091B11930E08217BF -:10F94000930709F044C080918602882309F43FC0E0 -:10F950006091B01986E00F946E322091520230917E -:10F9600053021216130644F58091500290915102F1 -:10F97000181619060CF59F938F93C901BE010F94B9 -:10F98000A1B89F938F93C901B7010F94A1B89B01B0 -:10F99000BE010F94A1B87F936F933F932F931F9352 -:10F9A0000F930F942A31ADB7BEB71A960FB6F894DD -:10F9B000BEBF0FBEADBF0BC085EF90E40F94953175 -:10F9C00006C086EE90E40F94B236811150C080914B -:10F9D0008C19811107C088E491E40F94B236882312 -:10F9E00071F045C088E491E40F94B23681113FC0B4 -:10F9F00084ED90E40F94B236882369F338C066E74B -:10FA000077EF85EF91E40F94DE36811130C062EE1E -:10FA100071E087EE91E40F94DE36811128C063E532 -:10FA20007BEF8BED91E40F94DE36811120C061E213 -:10FA300075EF8EEC91E40F94DE36811118C064E707 -:10FA400075EF85EC91E40F94DE36811110C00F94B0 -:10FA50000F2F8091B0198F5F8093B0198091B119E9 -:10FA60008F5F8093B119F2CE10928B19E4CEDF91A3 -:10FA7000CF911F910F91FF90EF900895FC01949109 -:10FA8000903249F0892F8B7F893029F081E09A30BC -:10FA900019F080E0089581E00895CF93DF9300D0BE -:10FAA0001F92CDB7DEB784E291E30F9493070F94D2 -:10FAB000423264E080E00F946E3282E00E949D9AB0 -:10FAC000E091FE0C84E0E89FF0011124E452F04F35 -:10FAD00080819181A281B38189839A83AB83BC8326 -:10FAE000CE0101960E9446A00F94103185E094E06B -:10FAF0000F941031E091FE0CF0E0EE0FFF1FE7577E -:10FB0000FA4E60817181072E000C880B990B0F94BF -:10FB10008EAE69837A838B839C83CE0101960E948B -:10FB200046A00F94103187E094E00F9410310F90AD -:10FB30000F900F900F90DF91CF910895EF92FF9269 -:10FB40000F931F93CF938C017B010F9463B3C82F46 -:10FB5000C80101960F9463B32C2F30E0382BF701C6 -:10FB600031832083CF911F910F91FF90EF900895E3 -:10FB70000F931F93CF93DF93EC018B01FB01608107 -:10FB80000F9475B3F8016181CE010196DF91CF9199 -:10FB90001F910F910D9475B3CF92DF92EF92FF9268 -:10FBA0000F931F93CF93DF93CDB7DEB765970FB653 -:10FBB000F894DEBF0FBECDBF80918B19811177C045 -:10FBC00081E080938B190F949E0C6CE879E18CEFA7 -:10FBD0009FE0B4DF6EE879E18AEF9FE0AFDF60E994 -:10FBE00079E188EF9FE0AADF0E94C6AC863E20F054 -:10FBF000109291191092901960918C1970918D1931 -:10FC0000072E000C880B990B0F948EAE20917D105F -:10FC100030917E1040917F10509180100F94DDB490 -:10FC200060939219709393198093941990939519F6 -:10FC300060918E1970918F19072E000C880B990B0B -:10FC40000F948EAE209181103091821040918310DC -:10FC5000509184100F94DDB46093961970939719A6 -:10FC600080939819909399196091901970919119B6 -:10FC7000072E000C880B990B0F948EAE20918510E7 -:10FC80003091861040918710509188100F94DDB408 -:10FC900060939A1970939B1980939C1990939D1966 -:10FCA00081E08093860281E596E10E943EDD8091AD -:10FCB000AC199091AD19A091AE19B091AF19892BE3 -:10FCC0008A2B8B2B09F46BC08091580E882341F04E -:10FCD0001092AC191092AD191092AE191092AF1982 -:10FCE0002091AC193091AD19809190199091911992 -:10FCF000820F931F9093911980939019813620EF72 -:10FD000092073CF481E690EF9093911980939019BB -:10FD100019C0181619062CF4109291191092901906 -:10FD200011C02FB7F8944091AD0E5091AE0E809156 -:10FD3000AC199091AD19840F951F9093AE0E8093DE -:10FD4000AD0E2FBF6091901970919119072E000C84 -:10FD5000880B990B0F948EAE2091851030918610F0 -:10FD600040918710509188100F94DDB460939A19D8 -:10FD700070939B1980939C1990939D1962E370E096 -:10FD800080E090E00F940D871092AC191092AD199D -:10FD90001092AE191092AF1981E080938602809183 -:10FDA0008602882369F161E080E00F946E32F09062 -:10FDB0009A19E0909B19D0909C19C0909D1963EC02 -:10FDC0007FE58E010F5F1F4FC8010F943EAC1A8272 -:10FDD000CF92DF92EF92FF921F930F938CE593E403 -:10FDE0009F938F931F9280E28F938AEA91E49F936F -:10FDF0008F930F942A310FB6F894DEBF0FBECDBF9C -:10FE00008091041082FD04C080910310882341F08A -:10FE100060E979E188EF9FE0ABDE81E00E949AA97A -:10FE20008091041082FD0F944E3065960FB6F894C1 -:10FE3000DEBF0FBECDBFDF91CF911F910F91FF901D -:10FE4000EF90DF90CF90089541E060E08CE392E482 -:10FE50000F94A00791E0811101C090E0911112C0B0 -:10FE600081E00F94273782E00F94932F0E946EEA6F -:10FE70000F94988341E060E08CE392E40F94A00734 -:10FE8000882371F308950F941D3760E080E00F948C -:10FE90006E3289E792E40F94953162E080E00F942E -:10FEA0006E3285E692E40F94953160ED77E080E064 -:10FEB00090E00F940D870D941D378F929F92AF9213 -:10FEC000BF92CF92DF92EF92FF920F931F9320E0A9 -:10FED00030E04FE253E46091DC0F7091DD0F8091D0 -:10FEE000DE0F9091DF0F0F943AB618160CF09AC0FF -:10FEF0008091AC199091AD19A091AE19B091AF1944 -:10FF0000892B8A2B8B2B09F469C00F94D2668091C0 -:10FF100000078F5F803109F480E09091FF06981709 -:10FF200009F45CC06091AC197091AD19072E000CFA -:10FF3000880B990B0F948EAE2091F60F3091F70F2E -:10FF40004091F80F5091F90F0F94F5A720914110AF -:10FF50003091421040914310509144100F94EFB3F0 -:10FF6000609341107093421080934310909344101B -:10FF70001092AC191092AD191092AE191092AF19DF -:10FF8000E0903D10F0903E1000913F101091401015 -:10FF90002091391030913A1040913B1050913C1013 -:10FFA0006091351070913610809137109091381013 -:10FFB000EEEFFCE0FF93EF93E5E58E2E982CE5ED58 -:10FFC000AE2EEFE3BE2EF1E4CF2EF0E1DF2E0E9445 -:10FFD000518781E0809386020F900F908091860276 -:10FFE000882381F061E080E00F946E3240914110EF -:10FFF00050914210609143107091441083E991E454 -:020000022000DC -:100000000F94E9848091041082FF19C01F910F9111 -:10001000FF90EF90DF90CF90BF90AF909F908F9028 -:100020000D944E3030DF1F910F91FF90EF90DF90D5 -:10003000CF90BF90AF909F908F900D94388A1F9172 -:100040000F91FF90EF90DF90CF90BF90AF909F9077 -:100050008F900895CF93DF9320E030E04FE253E498 -:100060006091DC0F7091DD0F8091DE0F9091DF0FBA -:100070000F943AB61816ECF482E090E09093410E9B -:100080008093400E81E08093760E61E08EE891E4EB -:100090000E9465DBCCE5D5E08991882319F00E94A8 -:1000A0006EADFACF8AE00E946EADDF91CF910D94D4 -:1000B000388ADF91CF91E7CE20E030E04FE253E481 -:1000C0006091DC0F7091DD0F8091DE0F9091DF0F5A -:1000D0000F943AB6181634F461E089E891E40E946E -:1000E00065DB01C0D0DE0D944E308091420291E07C -:1000F000811190E090934202882369F00E94379C1E -:10010000809141028823A9F080917B13811111C055 -:1001100084E991E00CC00E94449E80917A13882368 -:1001200041F080917B13811104C082E691E00D942F -:100130000D3008950F93CF9380910B0291E08111C0 -:1001400090E090930B02882319F00E949DA70AC0AB -:10015000C1E0C0930C026FEF89E69FE00F9475B386 -:10016000C0930B028091801681110AC080913C07D8 -:10017000811106C08091011090910210089749F4F6 -:1001800001E021E049E050E060E070E082EF9BECAC -:1001900008C001E021E049E050E060E070E08EEC52 -:1001A00097ED0F94C32FCF910F9108958091010780 -:1001B000909102078130910559F038F0029759F07B -:1001C00010920207109201070CC081E090E005C078 -:1001D00082E090E002C083E090E090930207809379 -:1001E00001076091010787ED9EE00D9475B3809142 -:1001F000420E882319F01092420E03C081E08093D2 -:10020000420E6091420E8FEF9FE00F9475B30F94F2 -:1002100098830F949943F89481E09091420E911144 -:1002200001C080E0809318070E94B9BD0F948B38FD -:10023000B19A109285001092840080ED97E090931F -:1002400089008093880078940F94D38280910B0268 -:10025000882341F08091420E882321F082E491E0CE -:100260000D940D300895CF92DF92EF92FF9281E0CE -:100270000F942737C090EA0ED090EB0EE090EC0E72 -:10028000F090ED0E88EEC80E83E0D81EE11CF11C44 -:100290000F942588C616D706E806F90680F467ECA1 -:1002A00076E083E296E40F944AAD0F94258860933C -:1002B000EA0E7093EB0E8093EC0E9093ED0EFF9090 -:1002C000EF90DF90CF900D947E30CF92DF92EF923F -:1002D000FF9281E00F942737C090E60ED090E70E92 -:1002E000E090E80EF090E90E88EEC80E83E0D81E8C -:1002F000E11CF11C0F942588C616D706E806F906FE -:1003000080F467EC76E080EE95E40F944AAD0F94AC -:1003100025886093E60E7093E70E8093E80E909325 -:10032000E90EFF90EF90DF90CF900D947E30CF9349 -:10033000DF931F92CDB7DEB7BE016F5F7F4F89E0BD -:100340009FE00F94D3858981882321F0813029F49F -:1003500082E001C081E0898301C01982698189E05E -:100360009FE00F9475B381E08093770E0F90DF913B -:10037000CF91089580E090E0A0E8BFE38093F60F6E -:100380009093F70FA093F80FB093F90F0F944E2F9F -:100390001092B0198091B0198430A8F51092B2195A -:1003A00088EA9FE20F94B23681112DC06CEC79EF90 -:1003B00089ED95E40F94DE36811125C063EC79EF69 -:1003C00082ED95E40F94DE3681111DC06AEB79EF62 -:1003D0008BEC95E40F94DE36811115C06DE57FEF4F -:1003E00082EC95E40F94DE3681110DC00F940F2F2F -:1003F0008091B0198F5F8093B0198091B1198F5F90 -:100400008093B119C7CF0895CF93DF93CDE6D5E0A0 -:100410008991882319F00E946EADFACF60918915F9 -:1004200070918A15072E000C880B990B0E94F7AD6E -:10043000C3E7D5E08991882319F00E946EADFACF09 -:100440006091020D7091030D072E000C880B990B23 -:100450000E94F7ADCAE7D5E08991882319F00E9480 -:100460006EADFACF6091DC0F7091DD0F8091DE0FE1 -:100470009091DF0F42E00E9411AEC1E8D5E0899172 -:10048000882319F00E946EADFACF60910807709131 -:10049000090780910A0790910B0742E00E9411AE74 -:1004A000C2E1D6E08991882319F00E946EADFACF9F -:1004B000DF91CF910895CF93DF93C9EFD5E0899174 -:1004C000882319F00E946EADFACF609129077091D0 -:1004D0002A07072E000C880B990B0E94F7ADC2E18A -:1004E000D6E08991882319F00E946EADFACFDF9192 -:1004F000CF9108950F931F93CF93DF93EC0108E8FA -:1005000015E0F80181918F01882319F00E946EADEA -:10051000F8CFBE01DD0F880B990B0E94F7ADC2E149 -:10052000D6E08991882319F00E946EADFACFDF9151 -:10053000CF911F910F9108951092511660E080E0C5 -:100540000F946E3283E295E40F94953162E080E07F -:100550000F946E321C9903C089E095E402C086E1D5 -:1005600095E40F9495318091041082FF06C081E5D7 -:1005700096E10E943EDD0D944E3008958F929F9239 -:10058000AF92BF92CF92DF92EF92FF920F931F93A1 -:10059000CF93DF931F921F92CDB7DEB7162F88300F -:1005A000910509F47DC2E4F48430910509F4E4C1B5 -:1005B00064F48130910509F45AC18230910509F43F -:1005C00074C1892B09F074C32FC08630910509F4DA -:1005D0002BC20CF044C281EDE82E85E0F82EFCC160 -:1005E0008A35910509F4DBC274F48531910509F46B -:1005F0009CC28631910509F4B7C2449709F058C3EB -:100600000EE815E070C28C35910509F4F3C20CF4C4 -:10061000DBC28D35910509F403C38336910509F0DA -:1006200047C30FE216E012C3809180160EE815E072 -:10063000882309F4FCC0F80181918F01882319F007 -:100640000E946EADF8CF84E090E054DF34DF00E923 -:1006500015E0F80181918F01882319F00E946EAD99 -:10066000F8CF6091480E7091490E80914A0E90919A -:100670004B0E4AE00E9486AD06E915E0F801819133 -:100680008F01882319F00E946EADF8CF2091A91830 -:10069000222321F18091531990915419A091551959 -:1006A000B09156190097A105B105B9F0BC01CD0173 -:1006B0006D597F4F8F4F9F4F24E630E040E050E070 -:1006C0000F94B3B360915B1970915C1980915D19BF -:1006D00090915E190F94B3B301C020E030E03A83EB -:1006E0002983CE0101960E94829F8C01F80181919D -:1006F0008F01882319F00E946EADF8CF0DE915E047 -:10070000F80181918F01882319F00E946EADF8CF16 -:1007100083E492E00E94829F8C01F80181918F0115 -:10072000882319F00E946EADF8CF04EA15E0F801B5 -:1007300081918F01882319F00E946EADF8CF0FEAE6 -:100740001EE0F80181918F01882319F00E946EAD9F -:10075000F8CF0BEA15E0F80181918F01882319F099 -:100760000E946EADF8CF8091500E9091510EA091E5 -:10077000520EB091530E892B8A2B8B2B31F10F9493 -:10078000258838EE832E33E0932EA12CB12CA501C1 -:1007900094010F94B3B369017A016091500E709186 -:1007A000510E8091520E9091530EA50194010F9419 -:1007B000B3B3C701B601621B730B840B950B4AE000 -:1007C0000E9486AD02EB15E006C060E070E0CB0150 -:1007D0000E94F7ADF7CFF80181918F01882319F0BE -:1007E0000E946EADF8CF09EB15E0F80181918F0101 -:1007F000882319F00E946EADF8CF02E116E0F801EF -:1008000081918F01882319F00E946EADF8CF00E02E -:1008100016E0F80181918F01882319F00E946EADD6 -:10082000F8CF8AE00E946EAD84E090E01BC0F80132 -:1008300081918F01882319F00E946EADF8CF81E07D -:1008400090E058DE38DE00E016E0F80181918F017B -:10085000882319F00E946EADF8CF8AE00E946EAD39 -:1008600081E090E09093E50E8093E40E21C20EE8C3 -:1008700015E0F80181918F01882319F00E946EAD77 -:10088000F8CF82E090E036DE16DE00E016E0F801F8 -:1008900081918F01882319F00E946EADF8CF8AE014 -:1008A0000E946EAD82E090E048C02EE8E22E25E086 -:1008B000F22E8701F80181918F01882319F00E949F -:1008C0006EADF8CF83E090E015DEF5DD00E016E0D8 -:1008D0006801F60181916F01882319F00E946EADC5 -:1008E000F8CF8AE00E946EAD83E090E09093E50E31 -:1008F0008093E40E81E090E0909359028093580237 -:10090000809180168823F1F0F70181917F0188237F -:1009100019F00E946EADF8CF84E090E0EBDDCBDD06 -:10092000F80181918F01882319F00E946EADF8CFF4 -:100930008AE00E946EAD84E090E09093E50E809393 -:10094000E40E17C0F70181917F01882319F00E94FE -:100950006EADF8CF83E090E0CDDDADDDF8018191A3 -:100960008F01882319F00E946EADF8CF8AE00E94B3 -:100970006EAD81E090E0D4C093ECE92E95E0F92EC5 -:10098000F70181917F01882319F00E946EADF8CFA5 -:10099000612F70E080E090E00E94F7AD02E116E088 -:1009A000F80181918F01882319F00E946EADF8CF74 -:1009B0008091E40E9091E50E9DDD7DDD00E016E076 -:1009C000F80181918F01882319F00E946EADF8CF54 -:1009D0008AE00E946EAD61C0F70181917F0188239A -:1009E00019F00E946EADF8CF612F70E080E090E0CA -:1009F0000E94F7AD02E116E0F80181918F01882392 -:100A000019F00E946EADF8CF8091E40E9091E50E42 -:100A100071DD51DD00E016E0F80181918F0188233E -:100A2000B9F20E946EADF8CF0FED15E0F80181919B -:100A30008F01882319F00E946EADF8CF3CDD00E0F5 -:100A400016E0F80181918F01882319F00E946EADA4 -:100A5000F8CF8AE00E946EAD88E090E01AC008EE00 -:100A600015E0F80181918F01882319F00E946EAD85 -:100A7000F8CF21DD00E016E0F80181918F01882395 -:100A800019F00E946EADF8CF8AE00E946EAD89E049 -:100A900090E09093E50E8093E40E82E090E040C0F9 -:100AA00001EF15E0F80181918F01882319F00E9470 -:100AB0006EADF8CF1092E50E1092E40E609129070A -:100AC00070912A07072E000C880B990B0E94F7AD36 -:100AD0000FEF15E0F80181918F01882309F478CF99 -:100AE0000E946EADF7CFF80181918F01882319F034 -:100AF0000E946EADF8CF8091E40E9091E50EFADC85 -:100B0000DADC00E016E0F80181918F01882319F00A -:100B10000E946EADF8CF8AE00E946EAD84E090E056 -:100B20009093590280935802C3C00EE815E0F80173 -:100B300081918F01882319F00E946EADF8CF64DC9B -:100B4000BADC8091E40E9091E50ED4DC00E016E072 -:100B5000F80181918F01882319F00E946EADF8CFC2 -:100B60008AE00E946EADA4C002E016E0F801819117 -:100B70008F01882319F00E946EADF8CF9CDC00E055 -:100B800016E0F80181918F01882319F00E946EAD63 -:100B9000F8CF8AE00E946EAD85E090E063CE0BE076 -:100BA00016E0F80181918F01882319F00E946EAD43 -:100BB000F8CF81DC00E016E0F80181918F018823F5 -:100BC00079F20E946EADF8CF04E116E0F801819150 -:100BD0008F01882319F00E946EADF8CF6CDC00E025 -:100BE00016E0F80181918F01882309F4B9CF0E94A2 -:100BF0006EADF7CF0DE116E0F80181918F018823EA -:100C000019F00E946EADF8CF56DC00E016E0F80156 -:100C100081918F01882309F4A3CF0E946EADF7CF95 -:100C200006E216E0F80181918F01882319F00E94F5 -:100C30006EADF8CF40DC00E016E0F80181918F0145 -:100C4000882309F48DCF0E946EADF7CFF801819112 -:100C50008F01882319F00E946EADF8CFD5DB09EF24 -:100C600015E0F80181918F01882319F00E946EAD83 -:100C7000F8CF6091290770912A07072E000C880B86 -:100C8000990B0E94F7AD02E116E0F80181918F0106 -:100C9000882319F00E946EADF8CF00E016E0F8014D -:100CA00081918F01882309F45BCF0E946EADF7CF4D -:100CB0000F900F90DF91CF911F910F91FF90EF90C8 -:100CC000DF90CF90BF90AF909F908F9008958F92BC -:100CD0009F92AF92BF92CF92DF92EF92FF920F93CB -:100CE0001F93CF93DF938C015B0160E080E00F9452 -:100CF0006E32E801C12CD12CC8010E943EFD882330 -:100D000019F00F5F1F4FF8CFF8018491882309F481 -:100D100062C06D2D80E00F946E32C8010F9445AC17 -:100D20008431910508F084E17801E80EF11CF3E0CC -:100D3000E701DF1214C0843191F4CE010E943EFD20 -:100D4000882311F02196F9CFFE018491882331F098 -:100D5000E70122977E01CC24C39401C0C12CFE017F -:100D60008491882339F1CE010E943EFD811122C079 -:100D7000FE01849192ED980F9230E0F08C32D1F028 -:100D800096EC980F9230B0F08F33A1F0813291F051 -:100D90000C171D0758F44E01F1E08F1A9108C40199 -:100DA0000E943EFD811102C0E401F2CF0C171D0725 -:100DB00009F4E7010C171D0750F4F80184918E37F0 -:100DC00009F480E20E949D9A0F5F1F4FF3CFD394E6 -:100DD000F4E0DF1291CFCC2049F00F94463263E06B -:100DE00083E10F946E3281E00E949D9AF501D082DA -:100DF000C11003C080E090E001C0CE01DF91CF912F -:100E00001F910F91FF90EF90DF90CF90BF90AF9028 -:100E10009F908F900895CF92DF92EF92FF92CF93A1 -:100E2000DF931F92CDB7DEB781E00F942737C090D4 -:100E3000F20ED090F30EE090F40EF090F50E88EEE6 -:100E4000C80E83E0D81EE11CF11C0F942588C6163D -:100E5000D706E806F90680F4BE016F5F7F4F81EB8D -:100E600096E435DF0F9425886093F20E7093F30EAD -:100E70008093F40E9093F50E0F947E300F90DF91D7 -:100E8000CF91FF90EF90DF90CF900895CF92DF92B7 -:100E9000EF92FF92CF93DF931F92CDB7DEB781E041 -:100EA0000F942737C090EE0ED090EF0EE090F00E2A -:100EB000F090F10E88EEC80E83E0D81EE11CF11C04 -:100EC0000F942588C616D706E806F90680F4BE01F9 -:100ED0006F5F7F4F88E696E4FADE0F942588609373 -:100EE000EE0E7093EF0E8093F00E9093F10E0F9430 -:100EF0007E300F90DF91CF91FF90EF90DF90CF90F9 -:100F000008950F931F93CF93DF93EC018B0180E043 -:100F10000F9427370F941D37B801CE01DF91CF9181 -:100F20001F910F91D4CECF93DF931F92CDB7DEB731 -:100F3000BE016F5F7F4FE5DF0F90DF91CF91089586 -:100F4000CF92DF92EF92FF921F93CF93DF93162FF2 -:100F5000C42FE9DF62E0CC2381F080E00F946E3291 -:100F600087E894E40F9495318FEB9FE20F949531CD -:100F700063E081E00F946E320FC081E00F946E3217 -:100F80008FEB9FE20F94953163E080E00F946E3217 -:100F900085E894E40F94953183EC9FE20F949531AA -:100FA0000F9425886B017C01D091BD1984E090E0FD -:100FB0009093230280932202112379F00F942588C5 -:100FC000DC01CB018C199D09AE09BF09813395471E -:100FD000A105B10510F08FEF4CC00F94BC7D81E0EE -:100FE00077D62091BD198D2F0D2E000C990B821BE9 -:100FF000910927FD939597FF03C0919581959109DC -:1010000005975CF162E080E00F946E328091BD192B -:10101000D81784F4CC23F9F083E894E40F94953145 -:1010200063E080E00F946E3281E894E40F94953190 -:10103000C0E011C08D177CF4C1110DC08FE794E49E -:101040000F94953163E080E00F946E328DE794E465 -:101050000F949531C1E0D091BD190F946B30882366 -:1010600009F4AACF82E090E09093230280932202B9 -:101070008C2FDF91CF911F91FF90EF90DF90CF9059 -:101080000895CF92DF92EF92FF920F931F93CF9329 -:10109000DF93D82EC92EEE24E3948091450281116E -:1010A00001C0E12C80E00F9427378D2D9C2D3BDF74 -:1010B0008C010F94463284E090E090932302809359 -:1010C0002202E8010115110539F463E083E10F9470 -:1010D0006E3282E00E949D9A84E6F82E82E390E0D0 -:1010E0000F94BD120F946B308823D9F02097E1F450 -:1010F00082E090E090932302809322020F944E327C -:1011000081E00F94273782E00F94932F8E2DDF918B -:10111000CF911F910F91FF90EF90DF90CF900D94A2 -:101120002737FA94F110DACF0115110559F22097FB -:1011300011F4CD2DDC2DCE01F6DEEC01892B11F65C -:1011400063E083E10F946E3282E00E949D9ABACFF1 -:101150002F923F924F925F926F927F928F929F92C7 -:10116000AF92BF92CF92DF92EF92FF920F931F93B5 -:10117000CF93DF93CDB7DEB7C059D2400FB6F89406 -:10118000DEBF0FBECDBFCD58DD4F688379838A8324 -:101190009B83C357D240FE01E754FE4F88E2DF0134 -:1011A0001D928A95E9F7E85BF14080E991E0DF0163 -:1011B0009C011D9221503040E1F7C75ADD4F198242 -:1011C0001882C955D240CE018F519E4FCF58DD4F66 -:1011D00099838883C157D2408E01075A1D4FDE0183 -:1011E000AF5CBD4FC159DD4FB983A883CF56D24004 -:1011F0003D014C0120EBA22E2FE0B22E33E2C32E94 -:10120000D12CE12CF12CB6010D2C000C880B990B84 -:101210000F948EAED4016D937D938D939D934D016C -:10122000F801619171918F01072E000C880B990BC9 -:101230000F948EAED3016D937D938D939D933D015D -:10124000BFEFEB1AFB0AE6E0EE16F10459F0B80125 -:10125000C5010E949EFDB5E0CB0ED11CE2E0AE0EB2 -:10126000B11CD1CFCD58DD4F288139814A815B81B6 -:10127000C357D240CF58DD4FA881B981C157D24062 -:101280006D917D918D919C910F943AB618160CF446 -:1012900035C35E01BFEDAB1ABDEFBB0A6E01EBE5D6 -:1012A000CE1AEEEFDE0ACF58DD4F08811981C15703 -:1012B000D240C159DD4FE880F980CF56D24025E0B9 -:1012C00030E0C359DD4F39832883CD56D240C3590E -:1012D000DD4F88819981CD56D2400197C359DD4FAA -:1012E00099838883CD56D240D80150962D913D9157 -:1012F0004D915C91539754966D917D918D919C91F8 -:1013000057970F94EEB32B013C01F70120893189E7 -:101310004289538964897589868997890F94EEB3C8 -:10132000A30192010F94DDB4D5019E938E937E9319 -:101330006E935D01F60172926292529242926F0137 -:10134000F4E0EF1AF10804501109C359DD4F288168 -:101350003981CD56D240232B09F0B9CFCE018F561B -:101360009E4FC558DD4F99838883CB57D2408E015D -:101370000F5F1F4F2E0197EF491A9DEF590A180171 -:101380007801C558DD4F68807980CB57D240CC2496 -:10139000C394D12CD3018D909D90AD90BC901397A8 -:1013A00014962D913D914D915C911797C501B40113 -:1013B0000F94EFB39B01AC010F94EFB3F70164A757 -:1013C00075A786A797A7F1E0CF16D10461F0D701E2 -:1013D00098968D929D92AD92BC929B97F7018482D4 -:1013E0009582A682B782FFEFCF1ADF0AD201149648 -:1013F0002D913D914D915C91179718966D917D912E -:101400008D919C911B970F94EEB320E030E040EC5F -:1014100050E40F94F5A7F10164AF75AF86AF97AFB5 -:10142000F4E06F0E711C2CE2E20EF11C34E0430E6E -:10143000511C88E2280E311C95E0C916D10409F030 -:10144000A9CF7E01B5E5EB0EF11C1E01E5E82E0EDD -:10145000311CD8019C962D913D914D915C919F97A7 -:10146000F801EC5AFF4F60817181828193810F9462 -:10147000DDB44B015C013701C12CD12C2701BCE24A -:101480004B1A5108E4E0CE0ED11CF201EC0DFD1D0B -:101490002081318142815381C501B4010F94F5A7A8 -:1014A0009B01AC01D3016D917D918D919C910F9425 -:1014B000EEB3F30161937193819391933F01F4E152 -:1014C000CF16D104F9F6045D1F4FA8E2EA0EF11C15 -:1014D0000215130509F0BDCF1E0125EB220E311CAC -:1014E0003E0131EB630E711C2E0187E3481A8EEF2B -:1014F000580A84E0E82EF12C4701C12CD12CA12CF4 -:10150000B12C00E010E0F301EC0DFD1DD201AC0D9B -:10151000BD1D2D913D914D915C91608171818281C4 -:1015200093810F94F5A79B01AC01B501C8010F94FD -:10153000EFB35B018C019FEF891A990AA4E0CA0EF0 -:10154000D11CB5E08B169104F1F69501A801F101CB -:1015500060817181828193810F94EEB3D3012D91CB -:101560003D914D915C910F94DDB4F20160837183E4 -:1015700082839383F1E0EF1AF10828E2221A3108FE -:101580003CE2631A710884E0481A5108E114F1043E -:1015900009F0B2CFCB50DE4F88819981AA81BB81FF -:1015A000C55FD140CB57DD4F88839983AA83BB8326 -:1015B000C558D2401E0197E4291A9EEF390ACF5828 -:1015C000DD4FA881B981C157D240CD90DD90ED901B -:1015D000FD90CF58DD4FB983A883C157D240A701F2 -:1015E0009601CD58DD4F688179818A819B81C357EF -:1015F000D2400F943AB687FD16C0CF58DD4FE88130 -:10160000F981C157D2402081318142815381CD5827 -:10161000DD4F688179818A819B81C357D2400F94C5 -:1016200088AE1816FCF4C359DD4F28813981CD5698 -:10163000D2402430310509F02CC1CB57DD4F288131 -:1016400039814A815B81C558D240CD58DD4F6881D0 -:1016500079818A819B81C357D2400F943AB618167C -:101660000CF017C1D10114968D909D90AD90BC9057 -:1016700017978D919D910D90BC91A02DC958DD4F6C -:1016800088839983AA83BB83C757D240C558DD4F4F -:10169000E881F981CB57D2404080518062807380CD -:1016A000C159DD4FA881B981CF56D2408D919D910E -:1016B0000D90BC91A02DCF57DD4F88839983AA83CD -:1016C000BB83C158D240A7019601CD58DD4F688138 -:1016D00079818A819B81C357D2400F94EEB36B010D -:1016E0007C0120E030E040E450E40F941AB7C75783 -:1016F000DD4F688379838A839B83C958D240CF5753 -:10170000DD4F288139814A815B81C158D240C1595E -:10171000DD4FE881F981CF56D240648175818681A1 -:1017200097810F94EEB3A30192010F94DDB4C358D7 -:10173000DD4F688379838A839B83CD57D240A30191 -:101740009201C301B2010F94EFB3C958DD4F288154 -:1017500039814A815B81C757D2400F94F5A7C3579F -:10176000DD4F688379838A839B83CD58D240A30160 -:101770009201C501B4010F94F5A79B01AC01C357B9 -:10178000DD4F688179818A819B81CD58D2400F9449 -:10179000EFB320E030E040EC50E40F94DDB49B0167 -:1017A000AC01C358DD4F688179818A819B81CD5717 -:1017B000D2400F94EEB3A70196010F94F5A7C3583A -:1017C000DD4F688379838A839B83CD57D240C95884 -:1017D000DD4F288139814A815B81C757D240C501DD -:1017E000B4010F94EEB34B015C0120E030E040EC1B -:1017F00050E4C301B2010F94F5A79B01AC01C501F0 -:10180000B4010F94DDB4C757DD4F288139814A8177 -:101810005B81C958D2400F94F5A74B015C0120E0D1 -:1018200030E040E05FE3C958DD4F688179818A810B -:101830009B81C757D2400F94F5A72B013C01A7010C -:101840009601C701B6010F94F5A79B01AC01C30136 -:10185000B2010F94F5A79B01AC01C501B4010F942F -:10186000EFB39B01AC01C358DD4F688179818A8158 -:101870009B81CD57D2400F94EFB3CF57DD4F2881D6 -:1018800039814A815B81C158D2400F94EFB35B012B -:101890008C01C359DD4F28813981CD56D2402F5F4D -:1018A0003F4FC359DD4F39832883CD56D24034E0B2 -:1018B000230E311CC558DD4F88819981CB57D2400A -:1018C0000496C558DD4F99838883CB57D240C159C0 -:1018D000DD4FA881B981CF56D2401496C159DD4F52 -:1018E000B983A883CF56D240C359DD4FE881F9812F -:1018F000CD56D240359709F062CE04C0A12CB12C50 -:1019000000E010E0B501C801C057DD4F0FB6F894F4 -:10191000DEBF0FBECDBFDF91CF911F910F91FF9022 -:10192000EF90DF90CF90BF90AF909F908F907F907F -:101930006F905F904F903F902F9008950F931F935B -:10194000CF93DF931F921F92CDB7DEB7BE016F5FBB -:101950007F4F88EF9FE00E949EFD89819A8181568A -:10196000904F803A9F40F8F01A821982EDE0F9E436 -:1019700084918F01882339F00E946EAD0F5F1F4F55 -:10198000F8018491F7CF8AE00E946EADBE016F5FCF -:101990007F4F88EF9FE00E94B8FD80ED98E471DBF7 -:1019A00081E00F9427370F900F90DF91CF911F9117 -:1019B0000F910895CF92DF92EF92FF92C090111194 -:1019C000D0901211E0901311F09014118091101129 -:1019D000882331F120E030E0A901C701B6010F945E -:1019E0003AB61816ECF42BED3FE049E450E4C70199 -:1019F000B6010F94F5A7A70196010F94F5A720E073 -:101A000030E040E85EE30F94F5A79B01AC0160E095 -:101A100070E080E89FE30F94DDB46B017C0106C0A9 -:101A2000C12CD12C80E8E82E8FE3F82E6091820241 -:101A30007091830264367105A1F0072E000C880BAB -:101A4000990B0F948EAE2AE037ED43E25CE30F94DE -:101A5000F5A79B01AC01C701B6010F94F5A76B0177 -:101A60007C01C0924702D0924802E0924902F09273 -:101A70004A02FF90EF90DF90CF9008954F925F92CF -:101A80006F927F928F929F92AF92BF92CF92DF928E -:101A9000EF92FF92CF93DF9300D01F92CDB7DEB7C6 -:101AA0004B015C0129013A018DEE9FE00F9463B375 -:101AB0008F3F01F58EEE9FE00F9463B38F3FD1F41B -:101AC0008FEE9FE00F9463B38F3FA1F480EF9FE010 -:101AD0000F9463B38F3F71F440E050E0BA018DEE94 -:101AE0009FE00F9487B340E050E0BA0181EF9FE0A0 -:101AF0000F9487B381EF9FE00F946BB36B017C0170 -:101B00008DEE9FE00F946BB369837A838B839C8304 -:101B1000C301B2012CE330E040E050E00F94B3B3D6 -:101B200089819A81AB81BC81820F931FA41FB51F4D -:101B3000AC01BD018DEE9FE00F9487B3C501B401E8 -:101B400028EE33E040E050E00F94B3B3BA01A901AE -:101B50004C0D5D1D6E1D7F1D81EF9FE00F9487B3BF -:101B60001092480E1092490E10924A0E10924B0E8F -:101B70000F900F900F900F90DF91CF91FF90EF900B -:101B8000DF90CF90BF90AF909F908F907F906F909D -:101B90005F904F900895CF93DF930F94A63A809172 -:101BA0005E0F811134C081E080935E0F80912D0D16 -:101BB00090912E0DA0912F0DB091300D8093030FB9 -:101BC0009093040FA093050FB093060FE4E7FEE592 -:101BD0008491EF01882331F00E946EAD2196FE01C1 -:101BE0008491F8CFE9E8F1E28491EF01882331F0A4 -:101BF0000E946EAD2196FE018491F8CF8AE00E948A -:101C00006EAD8FE791E2DF91CF910D94EE51DF91B0 -:101C1000CF910895EC011F926F938BE198E49F930D -:101C20008F930F9493ADF8940F94A63A179A10924D -:101C3000FF0C169A1092000D149AE4E7FEE58491C9 -:101C40000F900F900F900F908F01882339F00E9412 -:101C50006EAD0F5F1F4FF8018491F7CFE6E2F7E416 -:101C600084918F01882339F00E946EAD0F5F1F4F62 -:101C7000F8018491F7CF8AE00E946EAD209791F031 -:101C8000FE0184918E01882339F00E946EAD0F5FB2 -:101C90001F4FF8018491F7CF8AE00E946EADCE010C -:101CA00042D904C08DE197E40F945A537894C6E06A -:101CB000D0E0219751F068EC70E080E090E00F9464 -:101CC0000D8780E00F94932FF4CFF894A895FECF62 -:101CD0008F929F92AF92BF92CF92DF92EF92FF923C -:101CE0000F931F93CF93DF9300D01F92CDB7DEB732 -:101CF000182F80917B13811123C080912C0F90911C -:101D00002D0F8835924059F1809100079091FF0680 -:101D1000891B8F7009F07DC080918016811179C078 -:101D200080913C07811175C0809101109091021043 -:101D3000089709F46EC080917B0E81116AC09AC128 -:101D40008091011090910210089749F080917B0ECC -:101D5000811105C080912E0F81110E94B99D809143 -:101D600080168111BFC180913C078111BBC1809158 -:101D70003A078111B7C18091400E9091410E0497AE -:101D800009F4B0C180913F0E8111ACC18091011066 -:101D900090910210089709F4A5C1809182168111D3 -:101DA000A1C180912E0E81119DC16091020D709193 -:101DB000030D072E000C880B990B0F948EAE4B0170 -:101DC0005C0120E030E0A9010F9488AE811112C0BF -:101DD0006091891570918A15072E000C880B990B5C -:101DE0000F948EAE20E030E0A9010F9488AE8823D6 -:101DF00009F478C1C0907202D0907302E09074022E -:101E0000F0907502C114D104E104F10409F46AC12F -:101E10001DC20E940C9C80914002882309F49FCF30 -:101E200080912802882309F49ACF8091420D823153 -:101E300008F495CFE090410210924102F090310DEC -:101E400001E00093310D0E94229F1092420D80917B -:101E500040028823B1F18091310D882391F18DE406 -:101E600098E49F938F930F9493AD1092400D10922E -:101E70003B0D10923A0D1092390D1092380D1092C0 -:101E8000370D1092360D1092350D1092340D88ECEE -:101E900090E090933F0D80933E0D10923D0D109277 -:101EA0003C0D1092330D1092320D0E943B97109210 -:101EB000C8191092C719109228020093410D0F9073 -:101EC0000F9084EB98E40F94B1760E94F03082E09A -:101ED000C82ED12CD0922302C09222020E943CDC58 -:101EE0000F94988389EA98E40F94B1760E94F030B9 -:101EF000D0922302C09222020E943CDC0F9498836D -:101F00000091420D80914002882309F469C08091BC -:101F1000310D882309F464C080913B0D1F928F938B -:101F200085E298E49F938F930F9493AD8091340D45 -:101F30001F928F938091360D8F938091350D8F93E3 -:101F40008091380D8F938091370D8F9380913A0D4A -:101F50008F938091390D8F938EEE97E49F938F939B -:101F60000F9493AD2091370D3091380DE091F50D20 -:101F7000F091F60D60913B0D70E08091320D9091E3 -:101F8000330D0F948DB87F936F93DF010F94DEB8FC -:101F90002091390D30913A0D40E050E00F94B3B3E9 -:101FA0003F932F9380913D0D8F9380913C0D8F93A4 -:101FB00080913F0D8F9380913E0D8F9384EC97E439 -:101FC0009F938F930F9493AD1092410D81E0809376 -:101FD00028021092420D0FB6F894DEBF0FBECDBF9F -:101FE00091E02091350D3091360D2330310508F404 -:101FF00090E081E0023008F480E0892B79F4809150 -:10200000370D9091380D089748F084E998E49F9334 -:102010008F930F9493AD0E940B9F25C08DE798E49A -:102020009F938F930F9493AD85E69FE00F9463B3D6 -:1020300061E0680F85E69FE00F9475B381E09FE053 -:102040000F9470B3BC016F5F7F4F81E09FE00F94EE -:102050008FB38DE698E40F94B17688E698E40F94F8 -:10206000B176109228020F900F90E0924102F09208 -:10207000310D75CE0E94B99D882309F470CE0E945F -:102080000C9C20E030E04FE253E46091DC0F709153 -:10209000DD0F8091DE0F9091DF0F0F943AB6181686 -:1020A000C4F48091010790910207029720F488EE12 -:1020B00093E00F94185E82E390E05FD284E50F9482 -:1020C000524D81E08093760E80EC98E40F94B176C7 -:1020D00046CE80E00F9427370E9443FF81E00F94A3 -:1020E00027373DCE109269168091981390919913DD -:1020F000039714F40E94F4A00F9425888090FF0E9B -:102100009090000FA090010FB090020FC090FB0EB6 -:10211000D090FC0EE090FD0EF090FE0EDC01CB01A5 -:1021200088199909AA09BB09C816D906EA06FB0647 -:1021300040F4CD28CE28CF2821F064E08AE198E44D -:1021400069DDC0907602D0907702E0907802F0903E -:102150007902C114D104E104F104B1F00F9425888F -:10216000DC01CB0188199909AA09BB09C816D9064F -:10217000EA06FB0648F4909100078091FF06981349 -:1021800003C0112309F49FC06091BB199091FF0611 -:1021900080910007981781F08091FF0697E5899F4D -:1021A000F0011124E353F84F108190910007981724 -:1021B00021F08F5F8F70F9CF162F112339F1C09066 -:1021C000140FD090150FE090160FF090170FC11458 -:1021D000D104E104F10489F40F942588DC01CB01DA -:1021E000805E9C4FAF4FBF4F8093140F9093150F9D -:1021F000A093160FB093170F07C00F9425886C1586 -:102200007D058E059F0550F41FEF08C01092140F36 -:102210001092150F1092160F1092170F612F70E089 -:1022200086E00F9446860F947A260F900F900F90B9 -:102230000F90DF91CF911F910F91FF90EF90DF9062 -:10224000CF90BF90AF909F908F90089520E030E0A6 -:10225000A901C501B4010F9488AE811111C060912C -:10226000891570918A15072E000C880B990B0F9415 -:102270008EAE20E030E0A9010F9488AE882349F0AB -:1022800080916916811105C089E696E10E943EDDC4 -:102290002BCFB701A60189E696E10E94F9DC8823DD -:1022A00009F422CF1092030D1092020D19821A82A6 -:1022B0001B821C82CE0101960F947F768BEF96E4F1 -:1022C0000F94410811CF179A1092FF0C169A109292 -:1022D000000D149A59CF2F923F924F925F926F92B6 -:1022E0007F928F929F92AF92BF92CF92DF92EF92A6 -:1022F000FF920F931F93CF93DF9300D000D0CDB701 -:10230000DEB74B015C01CC24CA94DC2C7601242F6F -:1023100030E08901000F111F000F111F0452104FF0 -:10232000842F90E0A0E0B0E089839A83AB83BC83E4 -:1023300065EC262E68E4362E78EE472E73E0572E95 -:10234000612C712C220F331F27573A4E3E832D8369 -:1023500080915A0E8111F8C09FEFC916D906E9067F -:10236000F90651F0F7FCF0C00F9425886C197D092F -:10237000683B7B4008F0E8C00F942588DC01CB0166 -:1023800088199909AA09BB09893E9340A105B1059D -:1023900008F46EC08091C80F811166C0EDECF8E4BE -:1023A00084915F01882341F00E946EADFFEFAF1A68 -:1023B000BF0AF5018491F6CFD8016D917D918D9181 -:1023C0009C9141E00E9411AEE9ECF8E484915F0138 -:1023D000882341F00E946EADFFEFAF1ABF0AF501EE -:1023E0008491F6CF69817A818B819C810E94F7ADBF -:1023F000F101849195ECA92E98E4B92E882341F03F -:102400000E946EADFFEFAF1ABF0AF5018491F6CFBF -:10241000F7FC1BC00F94258846015701F8EB8F0E7F -:10242000FBE09F1EA11CB11CA5019401261B370BCC -:10243000480B590BCA01B901A30192010F94B3B320 -:10244000CA01B9010E94F7AD0CC08EE7A82E86E044 -:10245000B82ED5018D915D01882319F00E946EADD3 -:10246000F8CF8AE00E946EAD0F9425884B015C0185 -:102470000F94BC7D81E02CDC80E00F94932FBFEFA4 -:10248000CB16DB06EB06FB06A1F58091070FED816D -:10249000FE81608171818823B1F0072E000C880BCA -:1024A000990B0F948EAE20E030E040E85FE30F948C -:1024B000EEB3D8012D913D914D915C910F9488AE72 -:1024C0001816ECF545CF072E000C880B990B0F94CE -:1024D0008EAE20E030E040E85FE30F94EFB3D80128 -:1024E0002D913D914D915C910F943AB687FF27C095 -:1024F0002FCFF7FC2DCFED81FE8160817181072EFA -:10250000000C880B990B0F948EAE9B01AC01D80187 -:102510006D917D918D919C910F94EEB30F944EB57A -:1025200097FF07C090958095709561957F4F8F4F6D -:102530009F4F66307105810591050CF409CF0F940A -:1025400025886B017C0104CF26960FB6F894DEBF78 -:102550000FBECDBFDF91CF911F910F91FF90EF90F4 -:10256000DF90CF90BF90AF909F908F907F906F90B3 -:102570005F904F903F902F900895CF93DF93EC01A1 -:102580000F94BC7D81E0A4DB80E00F94932F209713 -:1025900099F0C233D10540F062E370E080E090E052 -:1025A0000F940D87E297ECCFBE0180E090E00F948E -:1025B0000D87C0E0D0E0E4CFDF91CF910895809106 -:1025C000F10D9091F20D9093F00D8093EF0D8DE54C -:1025D00097E19F938F9380912D0D90912E0DA09157 -:1025E0002F0DB091300D0196A11DB11DBF93AF937A -:1025F0009F938F9384EF96E49F938F9388EB97E458 -:102600009F938F930F9493AD8DB79EB70A960FB695 -:10261000F8949EBF0FBE8DBF08956F927F928F92E8 -:102620009F92AF92BF92CF92DF92EF92FF920F9361 -:102630001F93CF93DF93CDB7DEB7AA970FB6F89469 -:10264000DEBF0FBECDBF80910110909102100597A3 -:1026500009F0EAC0809100079091FF069813E4C04A -:102660008091580E8111E0C088E999E40F94EE51F1 -:102670000F9498830F942588609372167093731645 -:10268000809374169093751620E030E040E85FE385 -:1026900060914110709142108091431090914410CC -:1026A0000F94EEB3609341107093421080934310E7 -:1026B00090934410E0903D10F0903E1000913F1038 -:1026C000109140102091391030913A1040913B10F8 -:1026D00050913C10609135107091361080913710F8 -:1026E00090913810EEEFFCE0FF93EF93812C912C4A -:1026F000E8ECAE2EE3E4BE2EF1E4CF2EF0E1DF2EC7 -:102700000E94518720E030E040EA51E460913D10A2 -:1027100070913E1080913F10909140100F94EFB354 -:102720006B017C010F900F9020E030E042E553E414 -:102730000F943AB6181614F00D949D1C80E090E0AA -:10274000A2E5B3E480933D1090933E10A0933F1018 -:10275000B0934010E0903D10F0903E1000913F107B -:10276000109140102091391030913A1040913B1057 -:1027700050913C1060913510709136108091371057 -:1027800090913810EEEF6E2EECE07E2E7F926F92DD -:10279000812C912CF0E7AF2EF1E4BF2EA1E4CA2EDC -:1027A000A0E1DA2E0E94518780E090E0A8E4B2E434 -:1027B0008093351090933610A0933710B093381053 -:1027C00080E090E0AEE3B3E48093391090933A1048 -:1027D000A0933B10B0933C10E0903D10F0903E1061 -:1027E00000913F10109140107F926F92812C912C9C -:1027F00028E4A22E22E4B22E9C01AD01C501B40151 -:102800000E9451871092BC191092BB190F949883A3 -:1028100010920210109201101092450E1092440E68 -:102820000F900F900F900F908091011090910210D7 -:10283000089709F024C684ED92EEA6E2BFE38BA3CD -:102840009CA3ADA3BEA38FE399EFA9E5BCE38F8F53 -:1028500098A3A9A3BAA38091440E9091450E029724 -:1028600024F081E596E10E943EDD8091440E909136 -:10287000450E892B71F4909100078091FF06981303 -:1028800008C08091981390919913892B11F40D949D -:10289000A71C8091440E9091450E449771F490913D -:1028A00000078091FF06981308C0809198139091BB -:1028B0009913892B11F40D94AF1C8091440E9091C3 -:1028C000450E459771F4909100078091FF0698138B -:1028D00008C08091981390919913892B11F40D944D -:1028E000B91C8091440E9091450E469771F49091D9 -:1028F00000078091FF06981308C08091981390916B -:102900009913892B11F40D94C41C8091440E90915D -:10291000450E479771F4909100078091FF06981338 -:1029200008C08091981390919913892B11F40D94FC -:10293000CF1C8091440E9091450E489771F4909170 -:1029400000078091FF06981308C08091981390911A -:102950009913892B11F40D94DA1C8091440E9091F7 -:10296000450E0A9771F561E083E89DE40E9465DBFE -:1029700061E089E79DE40E9465DB61E080E79DE41A -:102980000E9465DB61E087E69DE40E9465DB61E013 -:102990008DE59DE40E9465DB61E082E899E40E9498 -:1029A00065DB61E089E59DE40E9465DB61E080E52F -:1029B0009DE40E9465DB89E090E09093450E809352 -:1029C000440E8091440E9091450E099709F07AC00B -:1029D000909100078091FF06981374C0809198131E -:1029E00090919913892B09F06DC00F941D371092A7 -:1029F000C4198CEC9DEF0F940D3080917B138823CC -:102A000009F4E3C761E08CE49DE40E9465DB61E0CA -:102A10008BE39DE40E9465DB61E08BE29DE40E9414 -:102A200065DB61EA73E0CE0101960F9447B98091AE -:102A30002B0F90E098A78FA3CE0187960E94369F18 -:102A4000BC01CE0101960F9428B960E0CE01019639 -:102A50000E9465DB61E084E19DE40E9465DB61E04A -:102A60008EEF9CE40E9465DB61E088EE9CE40E94AE -:102A700065DB61E088ED9CE40E9465DB61E08FEC42 -:102A80009CE40E9465DB61E086EB9CE40E9465DBD0 -:102A900061E085EA9CE40E9465DB61E080E99CE4FA -:102AA0000E9465DB61E08FE79CE40E9465DB61E0EA -:102AB0008AE69CE40E9465DB88E090E09093450EF6 -:102AC0008093440E8091440E9091450E089769F4CE -:102AD000909100078091FF06981307C0809198138A -:102AE00090919913892B09F479C78091440E9091A4 -:102AF000450E079769F4909100078091FF0698139F -:102B000007C08091981390919913892B09F495C768 -:102B10008091440E9091450E069709F00AC190915C -:102B200000078091FF06981304C18091981390913B -:102B30009913892B09F0FDC081E596E10E943EDDE5 -:102B4000EE24E394F12C00E010E069E376E0CE019E -:102B500001960F9447B9B801012E000C880B990B10 -:102B60000F948EAE2DEC3CEC4CEC5EE30F94F5A78D -:102B70009B01AC010F94EFB39B01AC0160E070E0EE -:102B80008CE092E40F94EEB36FA378A789A79AA77D -:102B9000CE0187960E94C19FBC01CE0101960F9481 -:102BA00028B962E776E0CE0101960F9428B9CE01EC -:102BB00083960F947584BC01CE0101960F9428B9B9 -:102BC00060E0CE0101960E9465DB62E476E0CE0112 -:102BD00001960F9447B9B7010F2C000C880B990B85 -:102BE0000F948EAE2DEC3CEC4CEC5EE30F94F5A70D -:102BF0009B01AC0160E070E08CE092E40F94EEB3D6 -:102C00004B015C016FA378A789A79AA7CE0187968D -:102C10000E94C19FBC01CE0101960F9428B962E7C2 -:102C200076E0CE0101960F9428B9CE014F960F940D -:102C30007584BC01CE0101960F9428B960E0CE01E5 -:102C400001960E9465DB67E476E0CE0101960F9461 -:102C500047B98FA298A6A9A6BAA6CE0187960E94C8 -:102C6000C19FBC01CE0101960F9428B962E776E0BE -:102C7000CE0101960F9428B9CE0183960F947584E6 -:102C8000BC01CE0101960F9428B960E0CE010196F7 -:102C90000E9465DB62E476E0CE0101960F9447B9AD -:102CA0000F5F1F4FB801012E000C880B990B0F947A -:102CB0008EAE2DEC3CEC4CEC5EE30F94F5A79B0143 -:102CC000AC010F94EFB39B01AC0160E070E08CE0CD -:102CD00092E40F94EEB36FA378A789A79AA7CE01C9 -:102CE00087960E94C19FBC01CE0101960F9428B91E -:102CF00062E776E0CE0101960F9428B9CE014F9697 -:102D00000F947584BC01CE0101960F9428B960E040 -:102D1000CE0101960E9465DB22E0E20EF11C043038 -:102D2000110509F012CF85E090E09093450E809355 -:102D3000440E8091440E9091450E059709F00AC10A -:102D4000909100078091FF06981304C18091981319 -:102D500090919913892B09F0FDC081E596E10E94BD -:102D60003EDD49E0E42EF12C04E010E069E376E07A -:102D7000CE0101960F9447B9B801012E000C880BC3 -:102D8000990B0F948EAE2DEC3CEC4CEC5EE30F9463 -:102D9000F5A79B01AC010F94EFB39B01AC0160E080 -:102DA00070E08CE092E40F94EEB36FA378A789A74C -:102DB0009AA7CE0187960E94C19FBC01CE010196C1 -:102DC0000F9428B962E776E0CE0101960F9428B9F6 -:102DD000CE0183960F947584BC01CE0101960F94A9 -:102DE00028B960E0CE0101960E9465DB62E476E0DE -:102DF000CE0101960F9447B9B7010F2C000C880B38 -:102E0000990B0F948EAE2DEC3CEC4CEC5EE30F94E2 -:102E1000F5A79B01AC0160E070E08CE092E40F94B8 -:102E2000EEB34B015C016FA378A789A79AA7CE01E7 -:102E300087960E94C19FBC01CE0101960F9428B9CC -:102E400062E776E0CE0101960F9428B9CE014F9645 -:102E50000F947584BC01CE0101960F9428B960E0EF -:102E6000CE0101960E9465DB67E476E0CE01019613 -:102E70000F9447B98FA298A6A9A6BAA6CE018796A5 -:102E80000E94C19FBC01CE0101960F9428B962E750 -:102E900076E0CE0101960F9428B9CE0183960F9467 -:102EA0007584BC01CE0101960F9428B960E0CE0173 -:102EB00001960E9465DB62E476E0CE0101960F94F4 -:102EC00047B90F5F1F4FB801012E000C880B990BFB -:102ED0000F948EAE2DEC3CEC4CEC5EE30F94F5A71A -:102EE0009B01AC010F94EFB39B01AC0160E070E07B -:102EF0008CE092E40F94EEB36FA378A789A79AA70A -:102F0000CE0187960E94C19FBC01CE0101960F940D -:102F100028B962E776E0CE0101960F9428B9CE0178 -:102F20004F960F947584BC01CE0101960F9428B979 -:102F300060E0CE0101960E9465DB82E0E80EF11CA4 -:102F40000830110509F012CF84E090E09093450E0F -:102F50008093440E8091440E9091450E049709F0A1 -:102F60000AC1909100078091FF06981304C18091D7 -:102F7000981390919913892B09F0FDC081E596E192 -:102F80000E943EDD31E1E32EF12C08E010E069E320 -:102F900076E0CE0101960F9447B9B801012E000CDE -:102FA000880B990B0F948EAE2DEC3CEC4CEC5EE351 -:102FB0000F94F5A79B01AC010F94EFB39B01AC01FB -:102FC00060E070E08CE092E40F94EEB36FA378A71A -:102FD00089A79AA7CE0187960E94C19FBC01CE0106 -:102FE00001960F9428B962E776E0CE0101960F941E -:102FF00028B9CE0183960F947584BC01CE01019649 -:103000000F9428B960E0CE0101960E9465DB62E46E -:1030100076E0CE0101960F9447B9B7010F2C000C52 -:10302000880B990B0F948EAE2DEC3CEC4CEC5EE3D0 -:103030000F94F5A79B01AC0160E070E08CE092E496 -:103040000F94EEB34B015C016FA378A789A79AA7F1 -:10305000CE0187960E94C19FBC01CE0101960F94BC -:1030600028B962E776E0CE0101960F9428B9CE0127 -:103070004F960F947584BC01CE0101960F9428B928 -:1030800060E0CE0101960E9465DB67E476E0CE0148 -:1030900001960F9447B98FA298A6A9A6BAA6CE0109 -:1030A00087960E94C19FBC01CE0101960F9428B95A -:1030B00062E776E0CE0101960F9428B9CE0183969F -:1030C0000F947584BC01CE0101960F9428B960E07D -:1030D000CE0101960E9465DB62E476E0CE010196A6 -:1030E0000F9447B90F5F1F4FB801012E000C880BDA -:1030F000990B0F948EAE2DEC3CEC4CEC5EE30F94F0 -:10310000F5A79B01AC010F94EFB39B01AC0160E00C -:1031100070E08CE092E40F94EEB36FA378A789A7D8 -:103120009AA7CE0187960E94C19FBC01CE0101964D -:103130000F9428B962E776E0CE0101960F9428B982 -:10314000CE014F960F947584BC01CE0101960F9469 -:1031500028B960E0CE0101960E9465DBE2E0EE0E48 -:10316000F11C0C30110509F012CF83E090E0909330 -:10317000450E8093440E8091440E9091450E039726 -:1031800009F00AC1909100078091FF06981304C1CD -:103190008091981390919913892B09F0FDC081E5D6 -:1031A00096E10E943EDD29E1E22EF12C0CE010E0D8 -:1031B00069E376E0CE0101960F9447B9B801012E7C -:1031C000000C880B990B0F948EAE2DEC3CEC4CEC64 -:1031D0005EE30F94F5A79B01AC010F94EFB39B0145 -:1031E000AC0160E070E08CE092E40F94EEB36FA36A -:1031F00078A789A79AA7CE0187960E94C19FBC0194 -:10320000CE0101960F9428B962E776E0CE010196CF -:103210000F9428B9CE0183960F947584BC01CE011A -:1032200001960F9428B960E0CE0101960E9465DBFB -:1032300062E476E0CE0101960F9447B9B7010F2CF6 -:10324000000C880B990B0F948EAE2DEC3CEC4CECE3 -:103250005EE30F94F5A79B01AC0160E070E08CE0A9 -:1032600092E40F94EEB34B015C016FA378A789A79A -:103270009AA7CE0187960E94C19FBC01CE010196FC -:103280000F9428B962E776E0CE0101960F9428B931 -:10329000CE014F960F947584BC01CE0101960F9418 -:1032A00028B960E0CE0101960E9465DB67E476E014 -:1032B000CE0101960F9447B98FA298A6A9A6BAA6E7 -:1032C000CE0187960E94C19FBC01CE0101960F944A -:1032D00028B962E776E0CE0101960F9428B9CE01B5 -:1032E00083960F947584BC01CE0101960F9428B982 -:1032F00060E0CE0101960E9465DB62E476E0CE01DB -:1033000001960F9447B90F5F1F4FB801012E000CB3 -:10331000880B990B0F948EAE2DEC3CEC4CEC5EE3DD -:103320000F94F5A79B01AC010F94EFB39B01AC0187 -:1033300060E070E08CE092E40F94EEB36FA378A7A6 -:1033400089A79AA7CE0187960E94C19FBC01CE0192 -:1033500001960F9428B962E776E0CE0101960F94AA -:1033600028B9CE014F960F947584BC01CE01019609 -:103370000F9428B960E0CE0101960E9465DBF2E06F -:10338000EF0EF11C0031110509F012CF82E090E040 -:103390009093450E8093440E8091440E9091450E7B -:1033A000029709F045C0909100078091FF0698139D -:1033B0003FC08091981390919913892BC9F581E5AD -:1033C00096E10E943EDD61E084EB9AE40E9465DBB9 -:1033D00061E08BE99AE40E9465DB61E083E99AE4AD -:1033E0000E9465DB61E08BE89AE40E9465DB61E0A6 -:1033F0008AE79AE40E9465DB61E088E69AE40E942D -:1034000065DB80917B13882329F061E081E69AE4F3 -:103410000E9465DB61E08DE59AE40E9465DB81E056 -:103420008093FA0F81E090E09093450E8093440ED4 -:103430008091440E9091450E019709F590910007F7 -:103440008091FF0698131BC0809198139091991357 -:10345000892BA9F48FEB94E10F94EE511092450E55 -:103460001092440E10920210109201108FE59FE00E -:103470000F9463B3813019F48CE00E944CD9809191 -:10348000011090910210029709F0E5C08091440E5E -:103490009091450E892B31F486E090E09093450E93 -:1034A0008093440E8091440E9091450E019739F41B -:1034B000909100078091FF06981709F42EC3809120 -:1034C000440E9091450E029739F490910007809137 -:1034D000FF06981709F434C38091440E9091450E6D -:1034E000039739F4909100078091FF06981709F42B -:1034F0003FC38091440E9091450E049741F5909101 -:1035000000078091FF06981322C086E799E40F9484 -:10351000EE5161E08DE49AE40E9465DB61E089E4AC -:103520009AE40E9465DB61E084E39AE40E9465DB33 -:103530001092470E1092460E80917B13882309F457 -:1035400023C388E090E09093450E8093440E8091D1 -:10355000440E9091450E059721F5909100078091BA -:10356000FF0698131EC081EB9FE20F94EE5161E0BD -:1035700080E39AE40E9465DB61E083E29AE40E94C2 -:1035800065DB8091FF0C882309F401C38091000D55 -:10359000882309F4FCC284E090E09093450E809368 -:1035A000440E8091440E9091450E069759F59091E6 -:1035B00000078091FF06981325C081EB9FE20F94CE -:1035C000EE5181E080935A0E1092030D1092020D7D -:1035D00080917B13882341F019821A821B821C82FE -:1035E000CE0101960F947F760F94BC7D82E090E02F -:1035F0009093410E8093400E85E090E09093450EAD -:103600008093440E8091440E9091450E0797B1F43B -:10361000909100078091FF06981310C080917B1352 -:10362000882309F4B7C261E08CE19AE40E9465DB6B -:1036300083E090E09093450E8093440E8091440E79 -:103640009091450E089739F4909100078091FF06FC -:10365000981709F43BC380910110909102100397D1 -:1036600021F410920210109201108091011090919B -:103670000210049709F062C08091440E9091450EAB -:10368000892B31F486E090E09093450E8093440EB0 -:103690008091440E9091450E019779F49091000726 -:1036A0008091FF06981309C018C31092450E10921E -:1036B000440E10920210109201108091440E9091CD -:1036C000450E029739F4909100078091FF069817F4 -:1036D00009F4D6C38091440E9091450E039739F4B6 -:1036E000909100078091FF06981709F4D0C380914C -:1036F000440E9091450E049739F490910007809103 -:10370000FF06981709F4CAC38091440E9091450EA4 -:10371000059739F4909100078091FF06981709F4F6 -:10372000CEC38091440E9091450E069739F4909146 -:1037300000078091FF06981709F4C8C38091011013 -:1037400090910210079709F0F3C38091440E909175 -:10375000450E892B99F483E090E09093410E80937D -:10376000400E21E030E03093260F2093250F23E018 -:10377000209386029093450E8093440E8091440ED0 -:103780009091450E039739F4909100078091FF06C0 -:10379000981709F4AEC38091440E9091450E02979C -:1037A00009F091C08091240F882309F48CC01092F5 -:1037B000240F1092260F1092250F80E599E40F94A4 -:1037C000EE5120E030E0A9016091200F7091210FAF -:1037D0008091220F9091230F0F9488AE81111EC00B -:1037E00020E030E0A90160911C0F70911D0F8091C5 -:1037F0001E0F90911F0F0F9488AE81110FC020E013 -:1038000030E0A9016091180F7091190F80911A0F83 -:1038100090911B0F0F9488AE8823C1F16BE576E081 -:10382000CE0101960F9447B980E29FE00E94C19FAC -:10383000BC01CE0101960F9428B962E676E0CE0174 -:1038400001960F9428B98CE19FE00E94C19FBC01B2 -:10385000CE0101960F9428B965E676E0CE01019677 -:103860000F9428B988E19FE00E94C19FBC01CE015E -:1038700001960F9428B960E0CE0101960E9465DBA5 -:1038800061E085ED99E40E9465DB0DC0E5EAF9E4AD -:1038900084918F01882339F00E946EAD0F5F1F4F16 -:1038A000F8018491F7CF0F9425886093270F7093C8 -:1038B000280F8093290F90932A0F81E090E0909336 -:1038C000450E8093440E8091440E9091450E0197D1 -:1038D00009F02EC30F9425880091270F1091280F0F -:1038E0002091290F30912A0FDC01CB01801B910B15 -:1038F000A20BB30B813D9740A105B10508F418C395 -:103900008FEB94E10F94EE511092410E1092400E05 -:1039100080E090E0A2E5B3E48093540290935502D6 -:10392000A0935602B09357021092450E1092440E87 -:103930001092021010920110FBC2C0923D10D09262 -:103940003E10E0923F10F09240100D94AA138AE0CE -:1039500090E09093450E8093440E0D94491410927C -:103960002B0F8AE090E09093450E8093440E0D94C7 -:103970005D1481E080932B0F8AE090E09093450ED8 -:103980008093440E0D94711482E080932B0F8AE093 -:1039900090E09093450E8093440E0D94851483E03F -:1039A00080932B0F8AE090E09093450E8093440E15 -:1039B0000D94991484E080932B0F8AE090E090930B -:1039C000450E8093440E0D94AD1461E084E59CE4B3 -:1039D0000E9465DB61E08CE39CE46CC861E083E3FA -:1039E0009CE40E9465DB61E08FE29CE40E9465DB61 -:1039F00061E08BE29CE40E9465DB61E087E29CE48D -:103A00000E9465DB61E08EE09CE40E9465DB61E082 -:103A10008EEF9BE40E9465DB61E083EF9BE40E94F4 -:103A200065DB61E08AEE9BE40E9465DB87E090E065 -:103A30009093450E8093440E58C881E596E10E940C -:103A40003EDD61E08EED9BE40E9465DB61E08AEC87 -:103A50009BE40E9465DB61E081EC9BE40E9465DBF6 -:103A600061E080EB9BE40E9465DB61E080EA9BE41F -:103A70000E9465DB61E08AE89BE40E9465DB61E00F -:103A800084E79BE40E9465DB61E08FE59BE40E9494 -:103A900065DB61E08AE49BE40E9465DB61E084E32E -:103AA0009BE40E9465DB61E08FE19BE40E9465DBA3 -:103AB00061E08BE09BE40E9465DB61E087EF9AE4C4 -:103AC0000E9465DB61E082EE9AE40E9465DB61E0C2 -:103AD0008DEC9AE40E9465DB61E089EB9AE40E9438 -:103AE00065DB68E676E0CE0101960F9447B9CE011A -:103AF00083960F947584BC01CE0101960F9428B96A -:103B000060E0CE0101960E9465DB86E090E0909334 -:103B1000450E8093440E0D9488151092450E109218 -:103B2000440E10920210109201108FEB94E10F944A -:103B3000EE511092410E1092400E10923A07BFCCF7 -:103B40001092030D1092020D61E085E59AE40E9447 -:103B500065DB0F94BC7D8FEB94E10F94EE511092D6 -:103B60005A0E81E090E09093450E8093440EB4CCC1 -:103B700061E081E59AE40E9465DB82E090E0909349 -:103B8000450E8093440EB5CC83E090E0DCCC83E01E -:103B900090E003CD0F941D3747EF5DE260E080E0D9 -:103BA0000F9412378FE795E00F94103161E080E0B9 -:103BB0000F946E3288E694E00F9410314EE359E48E -:103BC00062E081E00F94123746E359E463E081E05C -:103BD0000F94123784E090E09093230280932202A6 -:103BE000E12CF12C11E00F94BC7D81E00F94680E64 -:103BF0008091BD19082E000C990B9701281B390BD9 -:103C000037FF03C031952195310925303105ECF19D -:103C10008E159F050CF41150E816F90624F41F5F69 -:103C2000143044F006C0143024F4111103C011E024 -:103C300001C013E061E080E00F946E3289E596E008 -:103C40000F94103162E080E00F946E3289E596E0C7 -:103C50000F94103163E080E00F946E3289E596E0B6 -:103C60000F941031612F80E00F946E3288E694E05B -:103C70000F941031E090BD190E2C000CFF0864E683 -:103C800070E080E090E00F940D870F946B308823F4 -:103C900009F4A9CF82E090E090932302809322025E -:103CA0001150113059F030F0123061F461E089E0C8 -:103CB0009AE4BCCC61E087E19AE4B8CC61E080E1B1 -:103CC0009AE4B4CC61E084E09AE4B0CC87E090E080 -:103CD0009093450E8093440EBECCE090BD190E2CFF -:103CE000000CFF080F941D3760E080E00F946E32E7 -:103CF00085E796E00F941031A12CB12C01E010E083 -:103D00007724739485E0982E94E0692EC090BD19B5 -:103D10000C2C000CDD08C7018C199D0997FF03C00E -:103D20009195819591090D9794F0CE14DF0414F4C8 -:103D300001501109EC14FD0434F40F5F1F4F0330E0 -:103D4000110574F00BC00330110544F401C0670184 -:103D50000115110529F401E010E002C002E010E0B5 -:103D600062E080E00F946E3280E596E00F941031AF -:103D700063E080E00F946E3280E596E00F9410319E -:103D800062E082E00F946E328FEB9FE20F949531E8 -:103D900063E082E00F946E3283EC9FE20F949531E2 -:103DA00061E0600F80E00F946E3288E694E00F943B -:103DB000103164E670E080E090E00F940D872FEF03 -:103DC000A21AB20A85E6A816B1043CF060E083E6C8 -:103DD00090E00F94BE02A12CB12C0F946B3088237D -:103DE000D9F101301105E1F40E94BBCFF82E682F04 -:103DF00084E090E00F94BE0270922807609227073B -:103E0000F092FC0F0F9425886093FD0F7093FE0FC6 -:103E10008093FF0F90930010EE24E394F12C1EC0CA -:103E20000E94BBCFF82E682F85E090E00F94BE0271 -:103E30007092280790922707F092FC0F0F94258824 -:103E40006093FD0F7093FE0F8093FF0F909300100F -:103E5000A2E0EA2EF12C02C0E12CF12C0F94BC7DE3 -:103E600080E00F94680E8091981390919913892B9C -:103E700011F00E945DA0EF2809F017CC760146CF23 -:103E800081E090E09093450E8093440E23CC82E035 -:103E900090E09093450E8093440E29CC61E080E041 -:103EA0009AE40E9465DB61E08BEE99E40E9465DB99 -:103EB00083E090E09093450E8093440E25CC84E0FF -:103EC00090E09093450E8093440E2BCC61E087EEFA -:103ED00099E40E9465DB61E08AED99E40E9465DB6C -:103EE0000F94988385E090E09093450E8093440E64 -:103EF00025CC60E876E0CE0101960F9447B984E5C1 -:103F000092E00E9446A0BC01CE0101960F9428B910 -:103F100060E0CE0101960E9465DB82E699E40F9491 -:103F2000EE5182E090E09093450E8093440E33CCA6 -:103F3000AA960FB6F894DEBF0FBECDBFDF91CF912A -:103F40001F910F91FF90EF90DF90CF90BF90AF90B7 -:103F50009F908F907F906F9008950F942588609325 -:103F6000370F7093380F8093390F90933A0F08955D -:103F700061E08FE091E50E9465DB61E087E091E51B -:103F80000E9465DB61E08FEF90E50E9465DB61E0F8 -:103F900087EF90E50E9465DB61E08FEE90E50C9481 -:103FA00065DB61E087EE90E50C9465DB61E08FED09 -:103FB00090E50C9465DB61E087ED90E50C9465DBA2 -:103FC00061E08FEC90E50C9465DB61E087EC90E5B7 -:103FD0000C9465DBCF93DF93EC0180E190E10F94CB -:103FE000B3AC97FFFACF60E170E1CE010F944AAD18 -:103FF000EC010F94258860930C1070930D10809342 -:104000000E1090930F10CE01DF91CF9108959091F3 -:10401000C00095FFFCCF8093C6000895A895089531 -:104020008091C00087FFFCCF8091C00084FFF6DF45 -:104030008091C6000895F4DF803249F081E1E7DF26 -:1040400088E18093600088E080936000FFCF84E186 -:10405000DECF84B1817F84B984B1876084B985B1B2 -:10406000817F85B9289A80E58CBD1DBC08957F921B -:104070008F929F92AF92BF92CF92DF92EF92FF9278 -:104080000F931F93CF93DF930F9498837090320F09 -:10409000711003C081E08093320F26E636E646EECB -:1040A00050E46091411070914210809143109091C2 -:1040B00044100F94EFB360934110709342108093BB -:1040C000431090934410E0903D10F0903E1000910A -:1040D0003F10109140102091391030913A104091CA -:1040E0003B1050913C1060913510709136108091CA -:1040F000371090913810CEEFDCE0DF93CF93EEEDE8 -:104100008E2EEDED9E2EE5E1AE2EE1E4BE2EF1E425 -:10411000CF2EF0E1DF2E0E9451870F94988326E680 -:1041200036E646E651E4609141107091421080916C -:104130004310909144100F94EFB36093411070932B -:1041400042108093431090934410E0903D10F09003 -:104150003E1000913F101091401020913910309185 -:104160003A1040913B1050913C1060913510709185 -:1041700036108091371090913810DF93CF93A4E4DC -:104180008A2E982CA8E6AA2EA1E4BA2E0E94518766 -:104190000F94988320E030E040E152E460914110B8 -:1041A0007091421080914310909144100F94EFB39E -:1041B0006093411070934210809343109093441089 -:1041C000E0903D10F0903E1000913F101091401093 -:1041D0002091391030913A1040913B1050913C1091 -:1041E0006091351070913610809137109091381091 -:1041F000DF93CF93BCEB8B2EBBEB9B2EB9EBAB2E9F -:10420000B1E4BB2E0E9451870F94988326E636E6D0 -:1042100046E651E460914110709142108091431044 -:10422000909144100F94EFB360934110709342103B -:104230008093431090934410E0903D10F0903E1016 -:1042400000913F10109140102091391030913A1098 -:1042500040913B1050913C10609135107091361098 -:104260008091371090913810DF93CF93C4E48C2E57 -:10427000982CC8E6AC2EC1E4BC2E0E9451870F9446 -:1042800098838DB79EB708960FB6F8949EBF0FBE61 -:104290008DBF711002C01092320FDF91CF911F912C -:1042A0000F91FF90EF90DF90CF90BF90AF909F90D5 -:1042B0008F907F9008952F923F924F925F926F92CE -:1042C0007F928F929F92AF92BF92CF92DF92EF92A6 -:1042D000FF920F931F93CF93DF93CDB7DEB7629713 -:1042E0000FB6F894DEBF0FBECDBF8A8B362E10926C -:1042F0002E0EE091FE0CF0E0EE0FFF1FE757FA4E96 -:1043000060817181072E000C880B990B0F948EAE83 -:104310002B013C0180913D1090913E10A0913F10E7 -:10432000B09140108D839E83AF83B8878091351004 -:1043300090913610A0913710B091381089879A87E4 -:10434000AB87BC878091391090913A10A0913B10B7 -:10435000B0913C108D879E87AF87B88B212C198A2E -:10436000A3E0B0E0B0932302A09322028091360F25 -:10437000882369F084E690E00F94BD12F7CF809116 -:10438000C606833049F484E690E00F94BD12109184 -:10439000350F1123A1F31CC08A30A9F380912E0F91 -:1043A0008823B1F0C0900C10D0900D10E0900E104A -:1043B000F0900F10B0EECB0EB3E9DB1EB4E0EB1EB5 -:1043C000F11C0F9425886C157D058E059F05D8F28C -:1043D0001092350F80912E0E11116DC18111DCC02C -:1043E00080914502882329F080E00F942737E1E08F -:1043F000E98B0F949883F1E0F0932E0E8BE590E516 -:104400009F938F930F9493ADE091FE0CF0E0EE0F2D -:10441000FF1FE757FA4E60817181072E000C880B51 -:10442000990B0F948EAE2B013C010F900F90BA891F -:10443000BB2309F4A7C080913D1090913E10A0913C -:104440003F10B09140108D839E83AF83B8878091D9 -:10445000351090913610A0913710B091381089879F -:104460009A87AB87BC878091391090913A10A091C0 -:104470003B10B0913C108D879E87AF87B88B20E0B2 -:1044800030E040EA51E46D817E818F8198850F9400 -:10449000EFB36B017C0120E030E042E553E40F9480 -:1044A0003AB618164CF0C0923D10D0923E10E092F1 -:1044B0003F10F09240100CC080E090E0A2E5B3E421 -:1044C00080933D1090933E10A0933F10B093401006 -:1044D000E0903D10F0903E1000913F101091401080 -:1044E000AEEFBCE0BF93AF93812C912C70E7A72E69 -:1044F00071E4B72EE1E4CE2EE0E1DE2E2D853E857F -:104500004F85588969857A858B859C850E9451875E -:104510000F94988380E090E0A8E4B2E48093351093 -:1045200090933610A0933710B093381080E090E04D -:10453000AEE3B3E48093391090933A10A0933B100C -:10454000B0933C10E0903D10F0903E1000913F1071 -:1045500010914010AEEFBCE0BF93AF93812C912C33 -:10456000F8E4AF2EF2E4BF2E20E030E04EE353E457 -:10457000C501B4010E9451870F9498830F900F904A -:104580000F900F90332041F019821A821B821C82F7 -:10459000CE0101960F947F76211007C088E192E545 -:1045A0000F9493072224239420C0E091FE0CF0E0A6 -:1045B000EE0FFF1FE757FA4E60817181072E000C46 -:1045C000880B990B0F948EAE20E030E0A9010F9478 -:1045D00088AE811105C0332019F08BEE91E502C041 -:1045E0008AEB91E50F949307212C0F94423264E0FB -:1045F00080E00F946E320091FE0C10E01F92F1E00B -:10460000FF93F801EE0FFF1FE757FA4E60817181AB -:10461000072E000C880B990B0F948EAE20E030E033 -:1046200040E05FE30F94EFB30F944EB57F936F9329 -:10463000000F111F000F111FF801E452F04F20E08E -:1046400030E040E05FE360817181828193810F946B -:10465000EFB30F944EB57F936F931F9222E02F9389 -:1046600084E792E59F938F930F942A31B9E0B81BAA -:104670008B2F0F941C310FB6F894DEBF0FBECDBF49 -:1046800012E30F946B30882379F00091FE0C10E058 -:10469000000F111F07571A4EC301B2010F944EB5F8 -:1046A000D8016D937C935CCE84E690E00F94BD12AC -:1046B000115039F755CE882309F4EBC084E490E516 -:1046C0009F938F930F9493AD0F900F90332009F425 -:1046D0005FC00F941D370091FE0C10E0C301B201C2 -:1046E0000F944EB5F801EE0FFF1FE757FA4E718396 -:1046F0006083072E000C880B990B0F948EAE000F71 -:10470000111F000F111FF801E452F04F2081318179 -:10471000428153810F94EEB320E030E040EA50E450 -:104720000F943AB6181644F48AE991E50F9493076A -:1047300088EB9BE00F94BD126090FE0C712CF3018E -:10474000EE0FFF1FE757FA4E60817181072E000CB4 -:10475000880B990B0F948EAEF301EE0FFF1FEE0F37 -:10476000FF1FE452F04F20813181428153810F9429 -:10477000EEB320E030E040EA50E40F943AB6181669 -:104780003CF488EE93E00F94BD120E944DFDD4CF0F -:10479000BA89BB2309F473C00F941D378DE791E5E7 -:1047A0000F94930789859A85AB85BC8580933510D6 -:1047B00090933610A0933710B09338108D859E8556 -:1047C000AF85B8898093391090933A10A0933B102D -:1047D000B0933C10E0903D10F0903E1000913F10DF -:1047E000109140108EEF682E8CE0782E7F926F92A1 -:1047F000812C912C98E4A92E92E4B92E21E4C22EAA -:1048000020E1D22E2D853E854F85588969857A8590 -:104810008B859C850E9451870F9498838D819E8102 -:10482000AF81B88580933D1090933E10A0933F10C8 -:10483000B09340102091391030913A1040913B10C4 -:1048400050913C1060913510709136108091371066 -:10485000909138107F926F92812C912CE0E7AE2ED0 -:10486000E1E4BE2EED80FE800F8118850E94518705 -:104870000F9498830F900F900F900F900AC00F9491 -:104880001D3789E691E50F94930788EE93E00F9426 -:10489000BD129989992319F081E00F942737149854 -:1048A000000062960FB6F894DEBF0FBECDBFDF9159 -:1048B000CF911F910F91FF90EF90DF90CF90BF901D -:1048C000AF909F908F907F906F905F904F903F90B0 -:1048D0002F90089590EF980F953010F4149A0000DF -:1048E0008093360F1092350F08957F928F929F928A -:1048F000AF92BF92CF92DF92EF92FF920F931F93EE -:10490000CF93DF93853008F09AC0762ED82F20E021 -:1049100030E04FE253E46091DC0F7091DD0F809145 -:10492000DE0F9091DF0F0F943AB618160CF078C096 -:104930000F949883C1E080914502811101C0C0E0CD -:1049400080E00F9427370F941D3761E080E00F94CB -:104950006E3282E692E50F94953120E030E040EA35 -:1049600052E46091411070914210809143109091F7 -:1049700044100F94EEB360934110709342108093F3 -:10498000431090934410E0903D10F0903E10009141 -:104990003F10109140102091391030913A10409101 -:1049A0003B1050913C106091351070913610809101 -:1049B000371090913810EEEFFCE0FF93EF93812CCD -:1049C000912CE4E2AE2EE2E4BE2EF1E4CF2EF0E133 -:1049D000DF2E0E9451870F94988380E58D0F7ADF38 -:1049E00060E080E068DC0F900F90772049F082E370 -:1049F00092E50F94410880E66DDF60E080E05BDCCB -:104A00008C2FDF91CF911F910F91FF90EF90DF904E -:104A1000CF90BF90AF909F908F907F900D9427374D -:104A2000DF91CF911F910F91FF90EF90DF90CF908A -:104A3000BF90AF909F908F907F900C9443FF87E141 -:104A400091E5DF91CF911F910F91FF90EF90DF9053 -:104A5000CF90BF90AF909F908F907F900D94BBAD03 -:104A600061E084E042CF61E083E03FCF61E082E03B -:104A70003CCF61E081E039CF61E080E036CFCF9379 -:104A8000C82F20E030E04FE253E46091DC0F7091DA -:104A9000DD0F8091DE0F9091DF0F0F943AB618165C -:104AA0000CF051C0C0932C0E80E00F9427370F9468 -:104AB0001D3761E080E00F946E3282EC91E30F9439 -:104AC000953189E596E00F94103160912C0E70E0DD -:104AD0006F5F7F4F072E000C880B990B0F94F530FA -:104AE00080912C0E805FF6DE61E081E0E4DB6CED0E -:104AF00075E080E090E00F940D8780E3EBDE80911D -:104B00002C0E80932D0EB3DA0E946EEA0F949883D8 -:104B100082E090E09093410E8093400E82EC91E30E -:104B20000F94EE510F94388A81E00F9427370E943A -:104B300024FF8FEB94E10F94EE511092410E1092EE -:104B4000400ECF910895CF910C9443FF84E097CF0E -:104B500083E095CF82E093CF81E091CF80E08FCF4B -:104B60006F927F928F929F92AF92BF92CF92DF927D -:104B7000EF92FF920F931F93CF93DF9320E030E0EB -:104B80004FE253E46091DC0F7091DD0F8091DE0FF6 -:104B90009091DF0F0F943AB618160CF081C00F9465 -:104BA000988380E00F9427370F941D3761E080E0F1 -:104BB0000F946E3282E99AE30F94953189E596E07D -:104BC0000F94103160912D0E70E06F5F7F4F072EB4 -:104BD000000C880B990B0F94F530CFE6D0E5FEEF73 -:104BE0006F2EFCE07F2EFE01259135914591549169 -:104BF0006091411070914210809143109091441047 -:104C00000F94EFB360934110709342108093431060 -:104C100090934410FE01349685909590A590B490A1 -:104C2000E0903D10F0903E1000913F101091401028 -:104C30002091391030913A1040913B1050913C1026 -:104C40006091351070913610809137109091381026 -:104C50007F926F92E1E4CE2EE0E1DE2E0E9451873A -:104C60000F94988328960F900F9080E5C73CD80743 -:104C700009F0B9CF80E42EDE61E080E01CDB81E04A -:104C8000DF91CF911F910F91FF90EF90DF90CF9028 -:104C9000BF90AF909F908F907F906F900D9427372B -:104CA000DF91CF911F910F91FF90EF90DF90CF9008 -:104CB000BF90AF909F908F907F906F900C9443FF28 -:104CC00060E08CE40F94DC858FE891E00197F1F7C8 -:104CD00000C0000061E08CE40D94DC85CF9388E88F -:104CE0009DE40E949AC4C82F813009F436D98C2FD4 -:104CF000CF910895CF92DF92EF92FF92CF93DF93FF -:104D0000E091C6068E2FEE0F990BAA0BBB0BFC0190 -:104D10003596EA31F10508F081C38827E857FF4F3F -:104D20008F4F0D94D0B88CE89DE40E949AC48130D6 -:104D300011F413D902C018162CF480E490E54AD976 -:104D40008EEF5BC00F94258861337547810591050F -:104D500008F464C382E290E50F94BBAD1092C606DE -:104D60005DC3BCDF18160CF059C382E592E09F9337 -:104D70008F938FE190E59F938F9380E190E19F93D4 -:104D80008F930F9477AD8BE190E524D98DEF5AC0C6 -:104D9000A5DF18160CF042C380E592E09F938F9335 -:104DA00088E190E59F938F9380E190E19F938F93AB -:104DB0000F9477AD0F900F900F900F900F900F9072 -:104DC00080915002909151028335910574F41F92A5 -:104DD00083E58F9383E99DE49F938F930F9493AD25 -:104DE00060E081E391E50F940A0E86E090E50F9470 -:104DF000BBAD82E090E5EED88CEF8093C6060EC383 -:104E00006DDF18160CF00AC38EEF9FE4F4CF66DF57 -:104E100018160CF003C38AE792E09F938F9389EFF3 -:104E20009FE49F938F9380E190E19F938F930F94E2 -:104E300077AD8BEE9FE40F94BBAD0E94449E81E062 -:104E400080937B138093C6060F900F900F900F9066 -:104E50000F900F90E3C2C091360FCC2309F40CC120 -:104E60008091340F81116CC0C43209F452C030F506 -:104E7000C43109F445C088F4C131E1F130F4C031E6 -:104E800009F05CC087EE9FE458C0C231B1F1C33174 -:104E900009F054C08BED9FE450C0C132A1F130F451 -:104EA000C03209F04BC083ED9FE447C0C23271F1BC -:104EB000C33209F043C087EC9FE43FC0C23591F193 -:104EC00078F4C03449F128F4C033C1F58FEB9FE486 -:104ED00034C0C03521F1C13589F583EB9FE42DC085 -:104EE000C43531F110F1C03631F1C13839F58FE9EF -:104EF0009FE423C083EE9FE420C08FED9FE41DC09C -:104F000087ED9FE41AC08FEC9FE417C08BEC9FE401 -:104F100014C083EC9FE411C08BEB9FE40EC087EBC1 -:104F20009FE40BC08FEA9FE408C08BEA9FE405C0B2 -:104F300087EA9FE402C083EA9FE44CD88AE05DCF11 -:104F40001092340F80EF8C0F853038F5D0E06097E9 -:104F500080917B0290917C02C817D90799F0DF936A -:104F6000CF9381E99FE49F938F930F9493AD8DE846 -:104F70009FE430D883E08093C6060F900F900F9087 -:104F80000F9006C089E89FE425D883E08093C60689 -:104F9000D0937C02C0937B026CC080EE8C0F853076 -:104FA00068F4D0E0A097DF93CF938BE79FE49F93C3 -:104FB0008F930F9493AD87E79FE435C0C03379F4A6 -:104FC00064E670E080E090E00F940D878AE69FE44D -:104FD0009F938F930F9493AD86E69FE443C0C034B4 -:104FE00089F489E59FE49F938F930F9493AD85E5B2 -:104FF0009FE40F94EA1F86EF9FEF90937C028093CB -:105000007B0232C080EB8C0F8530B8F4D0E0C05505 -:10501000D109DF93CF9387E49FE49F938F930F94FD -:1050200093AD83E49FE40F94EA1F83E08093C60668 -:105030000F900F900F900F901CC0C03649F486E37C -:105040009FE49F938F930F9493AD82E39FE40AC0F4 -:10505000C13879F48EE09FE49F938F930F9493ADC2 -:105060008AE09FE40F94EA1F83E08093C6060F90C6 -:105070000F901092360FD2C1C090370FD090380FDA -:10508000E090390FF0903A0F84EFC80E81E0D81EFF -:10509000E11CF11C0F942588C616D706E806F90610 -:1050A00008F0BCC180912E0F8111B8C186E09FE449 -:1050B0000F94EA1F82E0A1CE11DE18160CF066C034 -:1050C0008AE792E09F938F9381E09FE49F938F9371 -:1050D00080E190E19F938F930F9477AD0F900F90A5 -:1050E0000F900F900F900F9080917A02811164C001 -:1050F00080918016811105C080913C07882309F4B6 -:105100005BC080912C0F90912D0F8835924009F44F -:1051100053C080913F0E81114FC08091FF06909146 -:105120000007981709F448C08091FF0690E027E532 -:1051300030910007381789F0289FF0011124EA57B1 -:10514000F84F4485558566857785452B462B472B3B -:1051500009F09F5F8F5F8F70EBCF992369F180918A -:105160004002882349F10E94229F81EF9EE40F9420 -:10517000B1768091E606882309F44BC18091400204 -:10518000882309F446C187EE9EE445C1C0900C1007 -:10519000D0900D10E0900E10F0900F1088EBC80E1C -:1051A0008BE0D81EE11CF11C0F942588C616D7068B -:1051B000E806F90608F032C181E01FCE8FED9DE4CC -:1051C0000E949AC4813019F40F94AD1F02C01816C2 -:1051D000C4F486EB9EE49F938F930F9493AD0F904E -:1051E0000F9080914002811102C00E94449EC1E054 -:1051F000C0932E0FC09341020E940C9CC093C60620 -:105200000DC16CDD1816C4F480912E0F882351F067 -:1052100010922E0F86EA9EE49F938F930F9493AD86 -:105220000F900F9089E99EE49F938F930F9493AD15 -:1052300081E08093350F2EC083EE9DE40E949AC4D6 -:10524000813019F40F94AD1F02C018161CF48FE7BB -:105250009EE419C0C0900C10D0900D10E0900E107C -:10526000F0900F1020EEC20E23E9D21E24E0E21EC1 -:10527000F11C0F942588C616D706E806F90608F033 -:10528000CDC085E69EE49F938F930F9493AD1092CB -:10529000350F84E18093C6060F900F90BFC0C09178 -:1052A000360FC43209F456C038F5C43109F449C088 -:1052B00090F4C13109F43FC030F4C03109F07BC033 -:1052C0008FE29EE45BC0C231C9F1C33109F073C003 -:1052D00083E29EE453C0C132B9F130F4C03209F028 -:1052E0006AC08BE19EE44AC0C23289F1C33209F040 -:1052F00062C08FE09EE442C0C235A9F188F4C03498 -:1053000061F130F4C03309F056C087E09EE436C046 -:10531000C03531F1C13509F04EC08BEF9DE42EC090 -:10532000C43539F118F1C03639F1C13809F043C03C -:1053300087EE9DE423C08BE29EE420C087E29EE4DA -:105340001DC08FE19EE41AC087E19EE417C083E18F -:105350009EE414C08BE09EE411C083E09EE40EC086 -:105360008FEF9DE40BC087EF9DE408C083EF9DE4C1 -:1053700005C08FEE9DE402C08BEE9DE40E949AC4AE -:10538000813059F40F9425886093370F7093380F4C -:105390008093390F90933A0F02C0181664F41F924D -:1053A000CF938DE49EE49F938F930F9493AD81E010 -:1053B0008093340F1EC0C0900C10D0900D10E09060 -:1053C0000E10F0900F1088EEC80E83E0D81EE11C7E -:1053D000F11C0F942588C616D706E806F906F0F4E6 -:1053E0001F92CF9383E39EE49F938F930F9493AD8B -:1053F00081E08093C6060F900F900F900F900EC023 -:105400006DDC18165CF481E08093C6068093350F3E -:1054100005C082EE9EE40F94B176CECEDF91CF919F -:10542000FF90EF90DF90CF9008951092FD0C1092B6 -:10543000FC0C0E94C6AC863E40F40F949E0C6CEFB0 -:105440007CE088EF9FE00C949EFD08958F929F92E0 -:10545000AF92BF92CF92DF92EF92FF920F931F9382 -:10546000CF93DF939B01AC01C5E3D0E168857985DB -:105470008A859B850F94EEB37B018C012C813D8145 -:105480004E815F81688179818A819B81EEEFFCE0AA -:10549000FF93EF93812C912CE0EAAE2EE1E4BE2E37 -:1054A000F1E4CF2EF0E1DF2E0E9451870F94988314 -:1054B0000F900F90DF91CF911F910F91FF90EF9080 -:1054C000DF90CF90BF90AF909F908F900D94C95D6B -:1054D0006091FC0C7091FD0C072E000C880B990B51 -:1054E0000F948EAE209185103091861040918710D8 -:1054F000509188100F94DDB4A9DF1092FD0C10922A -:10550000FC0C089582E00F94858360933D107093A6 -:105510003E1080933F10909340100D94C95D8F9280 -:105520009F92AF92BF92CF92DF92EF92FF920F9332 -:105530001F934B015C01E5E3F0E1E084F184028517 -:1055400013852481358146815781608171818281F3 -:105550009381EEEFFCE0FF93EF93E1E4CE2EE0E1E8 -:10556000DE2E0E9451870F900F901F910F91FF9098 -:10557000EF90DF90CF90BF90AF909F908F900D9461 -:105580009883CF93DF930F94D266C5E3D0E180E098 -:1055900090E0A0EAB0E488879987AA87BB8765E591 -:1055A00075E585E591E4BBDF8DEC9CECACE4BEE3F6 -:1055B00088839983AA83BB8383E393E3A3E7B0EC57 -:1055C0008C839D83AE83BF8369E370E1CE010E942B -:1055D0006BA860E070E088E492E4A1DF8AE999E9D1 -:1055E000A9E1BEE388879987AA87BB8765E575E54A -:1055F00085E591E4DF91CF9192CF4F925F926F92C8 -:105600007F928F929F92AF92BF92CF92DF92EF9252 -:10561000FF920F931F93CF93DF9305E310E1C5E350 -:10562000D1E1288139814A815B81F80160817181F2 -:10563000828193810F94EEB34B015C012C813D81FB -:105640004E815F81F80164817581868197810F9415 -:10565000EEB36B017C01C4E0DDE0288139814A8131 -:105660005B81C501B4010F94F5A72B013C012C818E -:105670003D814E815F81C701B6010F94F5A79B0163 -:10568000AC01C301B2010F94EFB3F80160837183E1 -:1056900082839383288539854A855B85C501B4015A -:1056A0000F94F5A74B015C012C853D854E855F85E8 -:1056B000C701B6010F94F5A79B01AC01C501B40168 -:1056C0000F94EFB3F8016483758386839783DF912A -:1056D000CF911F910F91FF90EF90DF90CF90BF90EF -:1056E000AF909F908F907F906F905F904F900895B4 -:1056F0004F925F926F927F928F929F92AF92BF92E2 -:10570000CF92DF92EF92FF920F931F93CF93DF938D -:10571000CDB7DEB728970FB6F894DEBF0FBECDBF6A -:10572000DC01CD90DD90ED90FC901397C0923D117F -:10573000D0923E11E0923F11F092401114960D91DB -:105740001D912D913C91179709831A832B833C83DC -:10575000009345111093461120934711309348113F -:10576000DB010D911D912D913C9113970D831E83AB -:105770002F833887009341111093421120934311D6 -:105780003093441114964D905D906D907C901797D6 -:105790004092491150924A1160924B1170924C11F3 -:1057A000FA016081718182819381609335117093D8 -:1057B0003611809337119093381184809580A6809C -:1057C000B7808092391190923A11A0923B11B09219 -:1057D0003C1120E030E0A9010F9488AE81110CC08B -:1057E00020E030E0A901C501B4010F9488AE811119 -:1057F00003C010924D1103C081E080934D1120E051 -:1058000030E040E85FE3C701B6010F9488AE811134 -:1058100021C020E030E0A9016D817E818F819885D3 -:105820000F9488AE811116C020E030E0A901698193 -:105830007A818B819C810F9488AE81110BC020E00E -:1058400030E040E85FE3C301B2010F9488AE8823E3 -:1058500009F45EC080914D11826080934D11A301C7 -:105860009201C701B6010F94F5A74B015C012D8190 -:105870003E814F81588569817A818B819C810F940B -:10588000F5A79B01AC01C501B4010F94EEB34B0128 -:105890005C019B01AC01C301B2010F94DDB46093C4 -:1058A000040D7093050D8093060D9093070D6D8187 -:1058B0007E818F8198859058A50194010F94DDB465 -:1058C0006093080D7093090D80930A0D90930B0D52 -:1058D00069817A818B819C819058A50194010F94F4 -:1058E000DDB460930C0D70930D0D80930E0D9093AD -:1058F0000F0DA5019401C701B6010F94DDB46093AB -:10590000100D7093110D8093120D9093130D24C000 -:1059100080E090E0A0E8BFE38093040D9093050D34 -:10592000A093060DB093070D1092080D1092090D6B -:1059300010920A0D10920B0D10920C0D10920D0D7D -:1059400010920E0D10920F0D8093100D9093110D6B -:10595000A093120DB093130D28960FB6F894DEBFE6 -:105960000FBECDBFDF91CF911F910F91FF90EF90B0 -:10597000DF90CF90BF90AF909F908F907F906F906F -:105980005F904F900895CF93DF93CDB7DEB76897C0 -:105990000FB6F894DEBF0FBECDBF80E090E0A0E868 -:1059A000BFE389839A83AB83BC831D821E821F82DF -:1059B000188619861A861B861C868D879E87AF8758 -:1059C000B88B198A1A8A1B8A1C8A1D8A1E8A1F8A0A -:1059D000188EAE014F5E5F4FBE01675F7F4FCE01F5 -:1059E000019686DE68960FB6F894DEBF0FBECDBF77 -:1059F000DF91CF91089580914D118823C9F0C3DFC5 -:105A00000F94988380E00F94858360933510709392 -:105A10003610809337109093381081E00F9485836F -:105A20006093391070933A1080933B1090933C1020 -:105A30000895CF93DF934FEF5FEFBA0185EE9FE0BC -:105A40000F9487B34FEF5FEFBA0189EE9FE00F9499 -:105A500087B34FEF5FEFBA018DED9FE00F9487B3EF -:105A60004FEF5FEFBA0181EE9FE00F9487B34FEFE6 -:105A70005FEFBA0185ED9FE00F9487B34FEF5FEFC3 -:105A8000BA0189ED9FE00F9487B3C5ECDFE04FEFDB -:105A90005FEFBA01CE010F9487B32496C53D8FE026 -:105AA000D807A9F7DF91CF9108952F923F924F9297 -:105AB0005F926F927F928F929F92AF92BF92CF929E -:105AC000DF92EF92FF921F93CF93DF93CDB7DEB7B4 -:105AD00064970FB6F894DEBF0FBECDBF1C017C8B60 -:105AE0006B8B5E874D878DED9FE00F946BB34B0101 -:105AF0005C01D1016D937D938D939C93139781EEFF -:105B00009FE00F946BB32B013C01F101648375831B -:105B10008683978385ED9FE00F946BB369837A83C7 -:105B20008B839C83AB89BC896D937D938D939C9370 -:105B3000139789ED9FE00F946BB36B017C01EB89A8 -:105B4000FC89648375838683978385EE9FE00F9439 -:105B50006BB36D837E838F839887AD85BE856D9390 -:105B60007D938D939C93139789EE9FE00F946BB375 -:105B700069877A878B879C87ED85FE85648375832B -:105B8000868397838D819E81AF81B8858F3F9F4F9C -:105B9000AF4FBF4F99F089859A85AB85BC858F3F04 -:105BA0009F4FAF4FBF4F51F08B208A2089208094A8 -:105BB00029F0472046204520409429F53ADF80E02F -:105BC00090E0A0E8BFE3F10180839183A283B383D7 -:105BD0001482158216821782EB89FC891082118249 -:105BE0001282138284839583A683B783AD85BE8595 -:105BF0001D921D921D921C921397FD011482158215 -:105C000016821782CFC089819A81AB81BC818F3F78 -:105C10009F4FAF4FBF4F91F2CF20CE20CD20C094E9 -:105C200069F2D1018D919D910D90BC91A02D898338 -:105C30009A83AB83BC83D10114968D919D910D9075 -:105C4000BC91A02D8F87988BA98BBA8B29813A8123 -:105C50004B815C81CA01B9010F94F5A76B017C01EE -:105C60002F85388949895A89CA01B9010F94F5A746 -:105C70009B01AC01C701B6010F94EFB30F9473B74A -:105C80006B017C0126E636E646E65FE30F9488AEBC -:105C900011E087FD0BC02DEC3CEC4CE85FE3C70145 -:105CA000B6010F943AB618160CF010E0EB89FC8997 -:105CB00080809180A280B380448055806680778008 -:105CC000A5019401C501B4010F94F5A76B017C01F6 -:105CD000A3019201C301B2010F94F5A79B01AC018E -:105CE000C701B6010F94EFB30F9473B76B017C013A -:105CF00026E636E646E65FE30F9488AE87FD0AC0E7 -:105D00002DEC3CEC4CE85FE3C701B6010F943AB6CA -:105D100018160CF411E02D813E814F815885CA017F -:105D2000B9010F94F5A76B017C0129853A854B8554 -:105D30005C85CA01B9010F94F5A79B01AC01C701AD -:105D4000B6010F94EFB30F9473B720E030E040E753 -:105D500051E40F943AB618160CF411E0A501940121 -:105D600069817A818B819C810F94F5A76B017C01FD -:105D7000A30192016F85788989899A890F94F5A783 -:105D80009B01AC01C701B6010F94EFB39F772DECD7 -:105D90003CEC4CEC5DE30F943AB618160CF40ECFC5 -:105DA00011110CCF64960FB6F894DEBF0FBECDBFB5 -:105DB000DF91CF911F91FF90EF90DF90CF90BF9038 -:105DC000AF909F908F907F906F905F904F903F909B -:105DD0002F900895CF93DF93CDB7DEB768970FB6B6 -:105DE000F894DEBF0FBECDBFAE014F5E5F4FBE0168 -:105DF000675F7F4FCE01019658DEAE014F5E5F4F69 -:105E0000BE01675F7F4FCE01019672DC68960FB6C8 -:105E1000F894DEBF0FBECDBFDF91CF9108950F93F1 -:105E20001F938091B219082F10E020E030E04091DC -:105E3000AC195091AD196091AE197091AF1940171E -:105E400051076207730774F090E00197092E000C68 -:105E5000AA0BBB0B8093AC199093AD19A093AE190C -:105E6000B093AF198091AC192091430E30E02D5FB3 -:105E70003F4F482F50E0241735076CF49DEF980FE3 -:105E80009093430E91E09093860284508093B119D1 -:105E90008FEF8093B0191F910F9108958091AC19E5 -:105EA0009091AD19A091AE19B091AF198130904881 -:105EB000A105B10544F01092AC191092AD191092E1 -:105EC000AE191092AF198091AC199091AD19A091B3 -:105ED000AE19B091AF19B7FF08C01092AC1910926B -:105EE000AD191092AE191092AF194091AC195091A2 -:105EF000AD196091AE197091AF198091430E90E089 -:105F0000A0E0B0E0481759076A077B0714F44093F4 -:105F1000430E8091430E8093B119809104108470D8 -:105F20008093AB19089590918602981710F480938E -:105F3000860280914502882339F0E091E006F091D5 -:105F4000E106309709F01994089580910101846069 -:105F5000809301018091010790910207009711F051 -:105F6000019711F40C9422BD0895EFDF82E0809335 -:105F700086021092BE1981E0089582E08093860225 -:105F80001092BE19E2CF0F93F894E091DE06F091E3 -:105F9000DF06E817F907D1F09093DF068093DE065D -:105FA0004093AC195093AD196093AE197093AF192B -:105FB0007894002339F080E2EBE8F9E1DF011D92EB -:105FC0008A95E9F7222319F00F91D7CF78940F9192 -:105FD00008950F93DC019091C4199530E0F4E92FF6 -:105FE000F0E09F01220F331FE20FF31FE55CF04F3B -:105FF0002091DE063091DF06318320839F5F9093EE -:10600000C4198091AC19828300E021E040E050E0A7 -:10601000BA01CD01B8DF0F9108950F93DC01909183 -:10602000C4199530E0F4E92FF0E09F01220F331FEF -:10603000E20FF31FE55CF04F2091DE063091DF06A2 -:10604000318320839F5F9093C4198091AC19828320 -:1060500001E021E040E050E0BA01CD0194DF0F9172 -:1060600008950F93E091C419EE23B1F0E150E0934D -:10607000C419F0E0CF01880F991FE80FF91FE55C04 -:10608000F04F4281042E000C550B660B770B00E09D -:1060900021E08081918177DF0F9108950F93E09146 -:1060A000C419EE23B1F0E150E093C419F0E0CF0140 -:1060B000880F991FE80FF91FE55CF04F4281042E0D -:1060C000000C550B660B770B01E021E0808191817C -:1060D0005ADF0F910895CF9380910410C1E082FDA3 -:1060E00002C0C0E002C00E94D49B8C2FCF910895C3 -:1060F000F2DF882311F041DFD1CF0895ECDF811169 -:10610000CDCF08958F929F92AF92BF92CF92DF92A0 -:10611000EF92FF920F931F93CF93DF93CDB7DEB72C -:10612000A0970FB6F894DEBF0FBECDBF6115710505 -:1061300081059105A9F480E3A0960FB6F894DEBF1F -:106140000FBECDBFDF91CF911F910F91FF90EF90C8 -:10615000DF90CF90BF90AF909F908F900C949D9ABE -:106160008E010F5F1F4FC12CD12C7601842E912CF4 -:10617000A12CB12C2FEFC21AD20AE20AF20AA50111 -:1061800094010F94B3B3F80161938F01B901CA016F -:10619000611571058105910569F7F1E0CF1AD10804 -:1061A000E108F108FE01EC0DFD1D81818A3010F43B -:1061B000805D01C0895C0E949D9AC114D104E104F4 -:1061C000F10459F7A0960FB6F894DEBF0FBECDBF0D -:1061D000DF91CF911F910F91FF90EF90DF90CF90C3 -:1061E000BF90AF909F908F900895CF92DF92EF92E3 -:1061F000FF926B017C0197FF0BC08DE20E949D9A7C -:10620000F094E094D094C094C11CD11CE11CF11C0A -:106210004AE0C701B601FF90EF90DF90CF9072CFB8 -:10622000CF93DF93EC018991882319F00E949D9A06 -:10623000FACFDF91CF910895CF93C82FCC2341F0AF -:1062400067EC76E080E290E00F940EADC150F6CF9F -:10625000CF910895CF93DF93CDB7DEB7AE014A5FFC -:106260005F4FFA0161917191AF0187EC96E00F9455 -:106270001BAEDF91CF9108959F92AF92BF92CF92C4 -:10628000DF92EF92FF920F931F93CF93DF93CDB7DF -:10629000DEB765970FB6F894DEBF0FBECDBFF82E00 -:1062A000E62ED72EC42EB52E862F972F0F9445ACF1 -:1062B000982EA92E63EC7FE58E010F5F1F4FC8015A -:1062C0000F943EAC892D9A2D8031910514F08FE00A -:1062D00090E0F801E81BF90B1786BF92CF921F934D -:1062E0000F93DF92EF928F2D0F2C000C990B9F9341 -:1062F000FF9289ED92E59F938F93ACDF0FB6F894F0 -:10630000DEBF0FBECDBF65960FB6F894DEBF0FBEE1 -:10631000CDBFDF91CF911F910F91FF90EF90DF9054 -:10632000CF90BF90AF909F90089567EC76E00D946A -:106330004AAD4F925F926F927F92BF92CF92DF925F -:10634000EF92FF920F931F93CF93DF93CDB7DEB7FA -:1063500065970FB6F894DEBF0FBECDBFD82EC62E00 -:10636000B72E7A01862F972F0F9445AC3C0163EC32 -:106370007FE58E010F5F1F4FC8010F943EACC30134 -:106380008031910514F08FE090E0F801E81BF90BE3 -:106390001486B701FF0C880B990B40908F19509011 -:1063A00090196090911970909219ED2C0D2C000CA1 -:1063B000FF0846165706680679067CF01F930F9370 -:1063C000BF92CF92FF92DF9287EE92E59F938F93D9 -:1063D00041DF88E593E5A9DF1DC00F948EAE20E074 -:1063E00030E04AE754E40F94DDB420E030E040E8C8 -:1063F0005FE30F94EFB39F938F937F936F931F93FC -:106400000F93BF92CF92FF92DF928AEA91E49F931B -:106410008F9320DF0FB6F894DEBF0FBECDBF659619 -:106420000FB6F894DEBF0FBECDBFDF91CF911F91A5 -:106430000F91FF90EF90DF90CF90BF907F906F9083 -:106440005F904F9008950F931F93CF93DF938B012D -:10645000877028E0829FC001112480640E949B9A6B -:10646000C0E0D0E0F801EC0FFD1F849161E00E94D4 -:10647000499A2196C830D105A9F7DF91CF911F9194 -:106480000F91089567EC72E581E0DDCF6FEB72E567 -:1064900081E0D9DF67EB72E582E0D5CF6FEA72E584 -:1064A00080E0D1DF67EC72E581E0CDDF67EA72E57D -:1064B00082E0C9DF6FE972E583E0C5DF67E972E575 -:1064C00084E0C1DF6FE872E585E0BDDF67E872E573 -:1064D00086E0B9DF6FE772E587E0B5CFCF93DF9352 -:1064E000CDB7DEB728970FB6F894DEBF0FBECDBF8D -:1064F00098E0EDEFF2E0DE01119601900D929A9591 -:10650000E1F790919113691710F06FEF690F6093A5 -:106510009013FE013196E60FF11DE60FF11D9081FB -:10652000890F806828960FB6F894DEBF0FBECDBFE6 -:10653000DF91CF910C949B9A2F923F924F925F9252 -:106540006F927F928F929F92AF92BF92CF92DF9283 -:10655000EF92FF920F931F93CF93DF93CDB7DEB7E8 -:1065600027970FB6F894DEBF0FBECDBF2091210252 -:106570002E83109221023091DB0F3F831092DB0FAC -:106580001092DA0F0F94D266BE016F5F7F4F89EFD2 -:106590009BE10F9481078981843010F083E0898327 -:1065A000698180E09BDF61E070E080E090E01DDECB -:1065B00083EF9BE1BADE80E090E0A0EAB0E4809354 -:1065C0003D1090933E10A0933F10B093401065E5AE -:1065D00075E585E591E40F948F2AE0E1F3E5859177 -:1065E0009591A591B4918093351090933610A09316 -:1065F0003710B0933810E4E1F3E585919591A591BA -:10660000B4918093391090933A10A0933B10B093BB -:106610003C1069E370E185E390E10E946BA860E0C3 -:1066200070E088E492E40F948F2A80E1E5E3F0E1E2 -:10663000A9ECBFE001900D928A95E1F781E080938B -:10664000210240E050E061E082E090E00F94DD66DE -:106650008091010D811109C08091060186FF05C05E -:1066600060E08FE593E50F940A0E1092210260E03E -:1066700070E080E291EC0F949D42882389F3809131 -:106680003D1090913E10A0913F10B091401080932A -:106690008D1590938E15A0938F15B093901508E1EA -:1066A00013E532E0C32ED12CE12CF12C412C512CDE -:1066B00040EA642E40E4742E53E0A52E62E0962E4C -:1066C00077E0B72E88248A948C0C0F94D26640927F -:1066D0003D1050923E1060923F107092401065E560 -:1066E00075E585E591E40F948F2AF80185919591E0 -:1066F000A591B4918093351090933610A0933710E4 -:10670000B0933810F801349685919591A591B49184 -:106710008093391090933A10A0933B10B0933C10A3 -:1067200069E370E185E390E10E946BA860E070E0AE -:1067300088E492E40F948F2A698180E0CFDEC7015C -:10674000B60153DD83EF9BE1F0DD60E070E080E2B5 -:1067500091EC0F949D42382E882309F481CF882D27 -:106760006A2D0F9480B880FF03C0E92DE91B9E2F8E -:106770002B2D382F3203F0011124E90FF11D97FD65 -:10678000FA95EE0FFF1FEE0FFF1FE457FA4E8091B0 -:106790003D1090913E10A0913F10B0914010818328 -:1067A0009283A383B483085F1F4F8FEFC81AD80A60 -:1067B000E80AF80AEAE0CE16D104E104F10409F08F -:1067C00081CFE0908D15F0908E1500918F1510916E -:1067D00090159CE8A92E95E1B92E4501EB82FC822B -:1067E0000D83212EF3E0FA83C12CD12CF401EC0DA2 -:1067F000FD1D41805280638074809201A301B70126 -:10680000C8010F9488AE87FD02C072018301920116 -:10681000A3016B817C818D81922D0F943AB618165D -:1068200024F04B825C826D82272C24E0C20ED11CA6 -:106830003CE0C316D104D1F68A8181508A83ECE111 -:106840008E0E911C8111D0CF9701A8016B817C81A4 -:106850008D81922D0F94EEB320E030E040E450E4BF -:106860000F943AB6181694F4E3EFF2E584918F0191 -:10687000882339F00E946EAD0F5F1F4FF80184919D -:10688000F7CF8AE00E946EAD312C4BC010E085EC52 -:10689000E82E8FE0F82E650100E0011102C01123FF -:1068A00029F120918D1530918E1540918F155091C1 -:1068B0009015F60161817281838194810F94EEB30A -:1068C00020E030E048EC52E40F94F5A720E030E0FF -:1068D00040E05FE30F94EFB30F9483B50F944EB590 -:1068E000C7010F948FB3F2E0EF0EF11C0F5F24E0AD -:1068F000C20ED11C033089F61F5F3CE1A30EB11C10 -:10690000133049F60F940D6181E080938C150F943C -:10691000C12A8E8180932102EF81E093DB0F1092D8 -:10692000DA0F832D27960FB6F894DEBF0FBECDBFCA -:10693000DF91CF911F910F91FF90EF90DF90CF905B -:10694000BF90AF909F908F907F906F905F904F908F -:106950003F902F90089580918602882309F447C0C4 -:1069600080918F1990919019A0919119B0919219DD -:106970004091AC195091AD196091AE197091AF1959 -:10698000481759076A077B0744F48093AC19909322 -:10699000AD19A093AE19B093AF198091931990914E -:1069A0009419A0919519B09196194091AC195091F4 -:1069B000AD196091AE197091AF1984179507A607AC -:1069C000B70744F48093AC199093AD19A093AE1916 -:1069D000B093AF1961E080E081DD4091AC19509136 -:1069E000AD1960918B1970918C1980E2A2DC8091B5 -:1069F000041082FF08C0E0918D19F0918E198091EA -:106A0000AC1980832ECB089580918602882309F4E7 -:106A100047C080918F1990919019A0919119B091D0 -:106A200092194091AC195091AD196091AE197091C5 -:106A3000AF19481759076A077B0744F48093AC19CC -:106A40009093AD19A093AE19B093AF19809193199B -:106A500090919419A0919519B09196194091AC1903 -:106A60005091AD196091AE197091AF1984179507C7 -:106A7000A607B70744F48093AC199093AD19A0937F -:106A8000AE19B093AF1961E080E028DD4091AC19F8 -:106A90005091AD1960918B1970918C1980E2ECDBEB -:106AA0008091041082FF0BC0E0918D19F0918E1936 -:106AB0008091AC199091AD1991838083D2CA0895C9 -:106AC0008F929F92AF92BF92CF92DF92EF92FF92FE -:106AD0000F931F93CF93DF93F091B219E091B11907 -:106AE000FE137BC079016A01EB018C018091860263 -:106AF0008823E9F06091B01980E0F0DC4881598189 -:106B00008091B21990E0A0E0B0E08090AC19909034 -:106B1000AD19A090AE19B090AF1988159905AA05C6 -:106B2000BB0511F080E201C08EE3B801A5DB8091C6 -:106B3000AB19882309F451C08091B21990E0A0E00C -:106B4000B0E04091AC195091AD196091AE197091BF -:106B5000AF1984179507A607B70709F03EC08EE462 -:106B600091E037DA10938C1900938B19D0938E191A -:106B7000C0938D19A601DD0C660B770B40938F191E -:106B8000509390196093911970939219C701FF0C5B -:106B9000AA0BBB0B8093931990939419A09395190A -:106BA000B093961988819981092E000CAA0BBB0B12 -:106BB0008093AC199093AD19A093AE19B093AF190F -:106BC000DF91CF911F910F91FF90EF90DF90CF90C9 -:106BD000BF90AF909F908F90C8C98091B2198F5F7E -:106BE0008093B21980E0DF91CF911F910F91FF90B8 -:106BF000EF90DF90CF90BF90AF909F908F900895CF -:106C00001F93CF93DF93C82FD62F172F6091B01902 -:106C100080E064DC2C2F0C2E000C330B8091B21919 -:106C200090E0A0E0B0E04091AC195091AD196091B6 -:106C3000AE197091AF1984179507A607B70711F021 -:106C400080E201C08EE33F93CF931F93DF931F92A7 -:106C50008F938FEC92E59F938F93FCDA2DB73EB71D -:106C6000285F3F4F0FB6F8943EBF0FBE2DBFDF9198 -:106C7000CF911F910895CF93DF933091B219209156 -:106C8000B119321327C0EB01BC0180918602882321 -:106C900011F080E2B5DF8091AB198823D9F08091A3 -:106CA000B21990E0A0E0B0E04091AC195091AD195C -:106CB0006091AE197091AF1984179507A607B707B1 -:106CC00049F4209721F061E0CE010E9465DBDF915D -:106CD000CF914BC98091B2198F5F8093B21980E038 -:106CE000DF91CF910895CF93DF933091B219209126 -:106CF000B11932132EC0EB01BC01809186028823AA -:106D000011F080E27DDF8091AB19882311F1809131 -:106D1000B21990E0A0E0B0E04091AC195091AD19EB -:106D20006091AE197091AF1984179507A607B70740 -:106D300081F41092AB190E94D49B109245022097C7 -:106D400011F0FE01199581E080934502DF91CF910A -:106D50000CC98091B2198F5F8093B21980E0DF91E6 -:106D6000CF9108953091B2192091B11932131FC0FB -:106D7000BC0180918602882311F083E041DF80917D -:106D8000AB198823A1F08091B21990E0A0E0B0E0A7 -:106D90004091AC195091AD196091AE197091AF1935 -:106DA00084179507A607B70711F478D9DEC8809134 -:106DB000B2198F5F8093B21980E00895CF93DF936B -:106DC0003091B2192091B119321323C0EB01BC01EB -:106DD00080918602882311F08EE712DF8091AB1933 -:106DE0008823B9F08091B21990E0A0E0B0E0409122 -:106DF000AC195091AD196091AE197091AF1984170B -:106E00009507A607B70729F4CE0107D9DF91CF91DF -:106E1000ACC88091B2198F5F8093B21980E0DF9186 -:106E2000CF910895CF93DF93EA0158DB67EC76E0CA -:106E3000CE01DF91CF910D944AAD81E00E949B9AE3 -:106E40008FEF98E10197F1F700C00000089590914D -:106E50004502981759F180934502882339F1109221 -:106E6000AC191092AD191092AE191092AF19109280 -:106E7000BD1981E596E10E943EDD0F942588DC0175 -:106E8000CB010197A109B1098093051090930610D9 -:106E9000A0930710B0930810D0DFE091E206F091C4 -:106EA000E306309709F0199582E03DC808958230D5 -:106EB00040F0823019F484EF91E0089580E090E092 -:106EC00008958EEA91E008957F928F929F92AF92FB -:106ED000BF92CF92DF92EF92FF920F931F93CF93C7 -:106EE000DF9380917F0F1F928F9385E997E59F93A2 -:106EF0008F930F9493AD70907F0F872D83700F90B9 -:106F00000F900F900F9019F00F94994303C07720C2 -:106F100009F465C039E1A32E32E0B32E4DE1C42E51 -:106F200042E0D42E50E1E52E57E0F52E09E113E0C2 -:106F3000C0E0D0E088248394912CC4010C2E01C0C1 -:106F4000880F0A94EAF78721C1F1809118078130F0 -:106F500069F424E030E040E050E060E88C2F0E94CB -:106F600094C620E030E0A90164E924C0F501208145 -:106F7000F6014081F70160818C2F0E94E1C6F80183 -:106F80002081822F90E0A0E0B0E0AC0133272227DF -:106F90006DEE8C2F0E9494C68C2F89DF9C0140E0FF -:106FA00050E064E98C2F0E9494C620E831E340E071 -:106FB00050E060E88C2F0E9494C62196FFEFAF1A34 -:106FC000BF0A2FEFC21AD20A8FEFE81AF80A0F5F32 -:106FD0001F4FC330D10509F0B0CF10927F0F109230 -:106FE0003907DF91CF911F910F91FF90EF90DF90C4 -:106FF000CF90BF90AF909F908F907F9008957F9299 -:107000008F929F92AF92BF92CF92DF92EF92FF92B8 -:107010000F931F93CF93DF93782E1F928F938FE65A -:1070200097E59F938F930F9493AD872D83700F9067 -:107030000F900F900F9011F00F94994339E1A32E08 -:1070400033E0B32E45E1C42E43E0D42E5DE1E52EBE -:1070500052E0F52E00E117E0C0E0D0E088248394F0 -:10706000912CC4010C2E01C0880F0A94EAF7272D39 -:10707000282399F190917F0F892B80937F0F20E037 -:1070800030E0A90160E88C2F0E9494C6F5012081B0 -:10709000822F90E0A0E0B0E0AC01332722276DEE14 -:1070A0008C2F0E9494C68C2F02DF9C0140E050E0A0 -:1070B00064E98C2F0E9494C6F6012081F70140817B -:1070C000F80160818C2F0E94E1C620E831E340E0A6 -:1070D00050E060E88C2F0E9494C62196FFEFAF1A13 -:1070E000BF0A2FEFC21AD20A8FEFE81AF80A0F5F11 -:1070F0001F4FC330D10509F0B4CFDF91CF911F915D -:107100000F91FF90EF90DF90CF90BF90AF909F9046 -:107110008F907F9008953F924F925F926F927F92EF -:107120008F929F92AF92BF92CF92DF92EF92FF9297 -:107130000F931F93CF93DF93A09AA29A9FB7F894CF -:10714000809108018062809308019FBF9FB7F894E7 -:10715000809108018061809308019FBF989A9A9A54 -:10716000809107018062809307018091070180610F -:1071700080930701809107018B7F809307018091A5 -:1071800007018F7780930701809107018F7B8093A0 -:10719000070180910701877F8093070149E1842ED1 -:1071A00042E0942E5DE1A52E52E0B52E60E1C62EA0 -:1071B00067E0D62E79E1E72E73E0F72E01E113E0C8 -:1071C000CDE0D3E0E9E06E2EE3E07E2EF5E04F2E39 -:1071D000F3E05F2E312CF40121914F01F501419133 -:1071E0005F01F60161916F01832D0E94E1C620E0ED -:1071F00030E0A90161E9832D0E9494C6F701219135 -:107200007F01822F90E0A0E0B0E0AC01332722277D -:107210006DEE832D0E9494C680911807813031F065 -:10722000832D45DE9C0140E050E003C020E030E0CB -:10723000A90164E9832D0E9494C6809118078130CA -:1072400029F020E831E340E050E004C024E030E0E1 -:1072500040E050E060E8832D0E9494C6F80131912F -:107260008F012991F30141913F01F20181912F0199 -:1072700090E0A0E0B0E0942B2370A22B232F21708C -:10728000422F50E060E070E022E1440F551F661F7E -:10729000771F2A95D1F79A01AB01282B392B4A2B5E -:1072A0005B2B60EF832D0E9494C620E030E0A901A3 -:1072B00063E9832D0E9494C63394F2E03F128BCF92 -:1072C00020911B0240911F026091120782E00E94F0 -:1072D000E1C620E030E0A90161E982E00E9494C6A5 -:1072E00020E030E044E050E06DEE82E00E9494C681 -:1072F00080911807813031F082E0D9DD9C0140E0B7 -:1073000050E003C020E030E0A90164E982E00E947F -:1073100094C680911807813029F020E831E340E0DD -:1073200050E004C024E030E040E050E060E882E05B -:107330000E9494C628EC34E046E050E060EF82E022 -:107340000E9494C620E030E0A90163E982E00E9437 -:1073500094C620911C02409120026091130783E0A3 -:107360000E94E1C620E030E0A90161E983E00E94CB -:1073700094C620E831E340E050E060E883E00E94FA -:1073800094C61092780F1092770F10927A0F109285 -:10739000790F10927C0F10927B0F10927E0F10923B -:1073A0007D0F1092700F10926F0F1092720F10924B -:1073B000710F1092740F1092730F1092760F10923B -:1073C000750F6091140780E00F946B5B6091150757 -:1073D00081E00F946B5B6091160782E00F946B5B0A -:1073E0006091170783E0DF91CF911F910F91FF907C -:1073F000EF90DF90CF90BF90AF909F908F907F9055 -:107400006F905F904F903F900D946B5B8EBD0DB46D -:1074100007FEFDCF8EB508954F925F926F927F92D7 -:107420008F929F92AF92BF92CF92DF92EF92FF9294 -:107430000F931F93CF93DF93A3EBB3E521E030E0ED -:10744000FD0145915491841795070CF05DC0B90179 -:1074500061507109660F771F660F771FEB01CF54DC -:10746000DC4AFE01E590F49061557C4AFB014591B0 -:107470005491F901EE0FFF1FEE0FFF1FEF54FC4A6E -:1074800005911491FE01A590B490FD01C591D49190 -:10749000FB01C590D490BC01641B750B072E000C3A -:1074A000880B990B0F948EAE2B013C01B8016A1921 -:1074B0007B09072E000C880B990B0F948EAE9B0155 -:1074C000AC01C301B2010F94F5A74B015C01CC19CB -:1074D000DD09BE01DD0F880B990B0F948EAE9B0169 -:1074E000AC01C501B4010F94DDB44B015C01B701DF -:1074F000FF0C880B990B0F948EAE9B01AC01C5015C -:10750000B4010F94EFB311C02F5F3F4F1496203298 -:10751000310509F095CFEDE2F4E565917491072E00 -:10752000000C880B990B0F948EAEDF91CF911F91B9 -:107530000F91FF90EF90DF90CF90BF90AF909F9012 -:107540008F907F906F905F904F900895CF93DF93CF -:1075500000D01F92CDB7DEB719821A821B821C821F -:10756000CE0101960F947F761092030D1092020DBA -:1075700010928A151092891510925C0F75981092CE -:10758000030D1092020D10925B0FA5980F900F90B3 -:107590000F900F90DF91CF910895CF93DF932091BB -:1075A0008E0F30918F0F809107029091080228175B -:1075B00039070CF439C0CADF80915E0F811127C0F2 -:1075C000E4E7FEE58491EF01882331F00E946EAD7F -:1075D0002196FE018491F8CF60E070E0CB010E941B -:1075E000F7AD8AE00E946EADE2E4F7E58491EF0129 -:1075F000882331F00E946EAD2196FE018491F8CF70 -:107600008AE00E946EAD85E397E50F945A530F947C -:10761000CB0D8091C80F882339F060E08CE590E0B5 -:10762000DF91CF910D94BE02DF91CF9108951F920B -:107630000F920FB60F9211240BB60F920F931F9358 -:107640002F933F934F935F936F937F938F939F936A -:10765000AF93BF93CF93DF93EF93FF9380918D0F01 -:10766000811190C281E080938D0F789480915D0F9D -:10767000811198C08091560F87FF89C08F70E82FC5 -:10768000F0E021E030E0082E02C0220F331F0A9400 -:10769000E2F74091E7065091E80624233523232B97 -:1076A00071F42091780030917900EE0FFF1FE85BB4 -:1076B000F04F40815181240F351F318320838F5F2C -:1076C0008730E8F18091470F8F5F8093470F8031BB -:1076D000A8F18091480F9091490F90938F0F80935C -:1076E0008E0F80914E0F90914F0F9093810F80934A -:1076F000800F80914C0F90914D0F9093830F80934A -:10770000820F8091500F9091510F9093A80E80930B -:10771000A70E8091520F9091530F9093860F8093F4 -:10772000850F8091540F9091550F9093A60E8093E2 -:10773000A50E81E080935D0F0E94A3DC80E0982F6E -:1077400020E041E050E0BA016F757270672B29F0BC -:107750003FEF390F992331F0932F440F551F2F5FBF -:10776000203189F7922F9F7023FF04C020917B0066 -:10777000286003C020917B00277F20937B0020910D -:107780007C00287F9770922B90937C0008C080919A -:107790007A00806480937A008091560F806880938D -:1077A000560FE9C020918E0F30918F0F8091EB061C -:1077B0009091EC06821793070CF46AC0C7DE8091A3 -:1077C0005E0F811127C0E4E7FEE58491EF01882375 -:1077D00031F00E946EAD2196FE018491F8CF60E0F9 -:1077E00070E0CB010E94F7AD8AE00E946EADE4E745 -:1077F000F6E58491EF01882331F00E946EAD219669 -:10780000FE018491F8CF8AE00E946EAD87E696E58E -:107810000F945A530F94CB0D809101018062809395 -:107820000101809101018860809301018091010133 -:107830008460809301019FB7F89480910201886071 -:10784000809302019FBF9FB7F894809102018062EC -:10785000809302019FBF80910107909102070397D7 -:1078600040F49FB7F89480910201846080930201F4 -:107870009FBF8FEF90E09093BC198093BB198091CC -:10788000C80F882329F060E08DE590E00F94BE02D8 -:107890002091820F3091830F8091E9069091EA0642 -:1078A0008217930754F11092030D1092020DA598C0 -:1078B00080915E0F81111FC0E4E7FEE58491EF0126 -:1078C000882331F00E946EAD2196FE018491F8CF9D -:1078D000E2EBF6E58491EF01882331F00E946EAD72 -:1078E0002196FE018491F8CF8AE00E946EAD81EA74 -:1078F00096E50F945A530F94CB0D8091850F90917C -:10790000860F81329D432CF0659900C11092840F3F -:1079100032C043DE2091820F3091830F80910502A7 -:10792000909106022817390734F1A59880915E0FCF -:1079300081111FC0E4E7FEE58491EF01882331F057 -:107940000E946EAD2196FE018491F8CFECEFF6E532 -:107950008491EF01882331F00E946EAD2196FE01E3 -:107960008491F8CF8AE00E946EAD8BEE96E50F947D -:107970005A530F94CB0DC0910301C2FBCC27C0F921 -:1079800081E0C8278091030181FFC26080910001DE -:1079900086FD12C081E596E10E943EDD8091591678 -:1079A000882309F4BDC068EC70E089E596E10E9487 -:1079B000C4DC8111B5C010C08091BE19882351F07C -:1079C00089E596E10E94EDDC8091880F811104C069 -:1079D000C46002C01092880FC09304109C2F917055 -:1079E000C1FD92608091870F891721F19130F1F0EC -:1079F00028F0923089F09330A1F01CC0813021F43E -:107A00008091BD198F5F05C08230A1F48091BD19AE -:107A100081508093BD190EC0882391F3833051F4B7 -:107A2000F5CF823069F3813029F4F0CF833041F310 -:107A3000882361F39093870F80917D02811112C09A -:107A400080915C0F80938C0F882311F0759A01C090 -:107A5000759880915B0F80938B0F882311F0A59A06 -:107A600001C0A59890918C0F80917D02981708F421 -:107A7000759890918B0F80917D02981708F4A598C6 -:107A800080917D028F5F8F7780937D0200E010E010 -:107A9000E801CC0FDD1FC755D14F88819981181699 -:107AA00019064CF4F89461E0802F0F94DA828881F3 -:107AB000998101970AC0892B59F0F89460E0802FD2 -:107AC0000F94DA82888199810196998388837894CA -:107AD0000F5F1F4F03301105D9F69CB14091890FFC -:107AE00096FB992790F9941771F02091570F3091D8 -:107AF000580F2F5F3F4F3093580F2093570F81E05F -:107B000084278093890F10928D0F3CC08091840F41 -:107B1000833310F042DD2FCF8F5F8093840F2BCF04 -:107B200089E596E10E94EDDC89E696E10E943EDD62 -:107B30008091BE1981110CC08091880F811108C0FD -:107B400086E596E10E94EDDC81E08093BE1944CF8A -:107B500068EE73E086E596E10E94C4DC882309F4B0 -:107B60003BCF81E08093880FE091E406F091E50639 -:107B7000309709F431CF80914502882309F42CCF46 -:107B800019952ACFFF91EF91DF91CF91BF91AF91DE -:107B90009F918F917F916F915F914F913F912F9125 -:107BA0001F910F910F900BBE0F900FBE0F901F9063 -:107BB00018950F931F93CF93DF93D82FC62F81E093 -:107BC00080935A0E0F944A8380918016882321F067 -:107BD000109280160F9437570E942DDCB7DC179A4D -:107BE0001092FF0C169A1092000D149A0F94BC7DFF -:107BF00080E00F94932F80910107909102070397E3 -:107C000040F49FB7F8948091020184608093020150 -:107C10009FBF8BEC97E00197F1F79FB7F8948091A5 -:107C200002018B7F809302019FBF8BE891E0019757 -:107C3000F1F7DD2309F45BC00F94CB0DCC2319F0D1 -:107C400085E596E502C087E496E50F945A53E4E78C -:107C5000FEE584918F01882339F00E946EAD0F5F9D -:107C60001F4FF8018491F7CFCC23A9F1E3E2F6E5A9 -:107C70008491EF01882331F00E946EAD2196FE01C0 -:107C80008491F8CF8AE00E946EAD809101018062FC -:107C900080930101809101018860809301019FB769 -:107CA000F894809102018062809302019FBF6FEF80 -:107CB00070E086E00F9446868FEF90E09093BC19B9 -:107CC0008093BB198BE39FE10197F1F7DF91CF918F -:107CD0001F910F910895E0E0F6E58491EF0188236C -:107CE00089F20E946EAD2196FE018491F8CFCC23DB -:107CF00019F08CEE95E502C08CED95E50F945A5382 -:107D0000E4E7FEE584918F01882339F00E946EAD8F -:107D10000F5F1F4FF8018491F7CFCC2399F0E3EC6C -:107D2000F5E58491EF01882331F00E946EAD219634 -:107D3000FE018491F8CF8AE0DF91CF911F910F91DE -:107D40000C946EADEBEAF5E58491EF01882399F38D -:107D50000E946EAD2196FE018491F8CF2F923F9242 -:107D60004F925F926F927F928F929F92AF92CF923B -:107D7000DF92EF92FF920F931F93CF93DF93CDB7D4 -:107D8000DEB72C970FB6F894DEBF0FBECDBF1C0137 -:107D90002A013B0109831A832B833C83A11009C06C -:107DA0002DE230E03A87298780E090E0A0E7B1E457 -:107DB00008C0A8E6B1E0BA87A98780E090E0A0EA11 -:107DC000B0E48D839E83AF83B8870F9425888101AB -:107DD000000F111F000F111FD801A15AB04FBC870F -:107DE000AB870F948CAEEB85FC85608371838283B7 -:107DF000938320E030E0A901C701B6010F9488AE5B -:107E0000811107C0F101EE0FFF1FE054F04F118206 -:107E1000108298012055304F3C872B87A301920197 -:107E2000AB85BC856D917D918D919C910F9488AEB1 -:107E3000882309F45CC020E030E0A901C301B2014D -:107E40000F943AB6F801E056F04F1816CCF580E0E2 -:107E500090E0A0E8BFE380839183A283B383EB85A6 -:107E6000FC854082518262827382F801E856F04FAD -:107E700089819A81AB81BC8180839183A283B38302 -:107E8000F101EE0FFF1FEC56F04F118210829C01A2 -:107E9000AD01C301B2010F943AB618160CF0A6C09A -:107EA0004101880C991CF401EC56F04F80819181BE -:107EB000019691838083A11035C028E030E034C062 -:107EC0001082118212821382AB85BC854D925D9225 -:107ED0006D927C92139729813A814B815C81C30119 -:107EE000B2010F943AB618160CF4A4C07FC02981D1 -:107EF0003A814B815C81C301B2010F943AB61816E6 -:107F00000CF074C020E030E040E85FE3F801E05698 -:107F1000F04F60817181828193810F9488AE8111CD -:107F200089C0BECF20E130E0281739070CF005C129 -:107F3000F801E856F04F20813181428153816981F7 -:107F40007A818B819C810F94EEB320E030E040E099 -:107F500050E40F9488AEF101EE0FFF1FFC87EB8712 -:107F600087FF09C0F401E057F04F808191810196AD -:107F70009183808306C0EB85FC85E057F04F11822A -:107F80001082F401E057F04F20813181A11003C02D -:107F900085E090E002C082E090E082179307ACF4A5 -:107FA0008091C80F882329F060E080E090E00F9472 -:107FB000BE026A2D81E0FDDD8091C80F882329F083 -:107FC00060E08BE590E00F94BE02F801E856F04FB8 -:107FD00089819A81AB81BC8180839183A283B383A1 -:107FE000AB85BC85AC56B04F1D921C9229813A815D -:107FF0004B815C81C301B2010F9488AE1816D4F096 -:1080000020E030E040E85FE3F801E056F04F6081A7 -:108010007181828193810F9488AE81110BC080E0C1 -:1080200090E0A0E0B0E4F801E056F04F8083918347 -:10803000A283B38320E030E0A901C701B6010F9409 -:108040003AB618160CF085C02D813E814F815885B7 -:10805000C301B2010F94EEB39B01AC0169817A8137 -:108060008B819C810F943AB61816D4F42D813E81F1 -:108070004F815885C301B2010F94EFB39B01AC014E -:1080800069817A818B819C810F9488AE87FF08C0BB -:10809000F101EE0FFF1FE054F04F1182108259C022 -:1080A000F801E056F04F20E030E040E85FE3608107 -:1080B0007181828193810F943AB618160CF049C0F1 -:1080C000F101EE0FFF1FE054F04F80819181019686 -:1080D00091838083880F991FE985FA85E817F9074E -:1080E000C4F58091C80F882329F060E080E090E01B -:1080F0000F94BE026A2D80E05CDD8091C80F88235A -:1081000041F160E08AE590E02C960FB6F894DEBF6E -:108110000FBECDBFDF91CF911F910F91FF90EF90D8 -:10812000DF90CF90AF909F908F907F906F905F90F7 -:108130004F903F902F900D94BE0229813A814B8140 -:108140005C81C301B2010F9488AE18160CF067CFA2 -:1081500071CF2C960FB6F894DEBF0FBECDBFDF9166 -:10816000CF911F910F91FF90EF90DF90CF90AF9044 -:108170009F908F907F906F905F904F903F902F9047 -:1081800008954F925F926F927F928F929F92AF92DB -:10819000BF92CF92DF92EF92FF920F931F93CF93F4 -:1081A000DF93A3E3B4E521E030E0FD014591549174 -:1081B000841795070CF05EC0B90161507109660F14 -:1081C000771F660F771F8B010F5C1B4AF801C59163 -:1081D000D491615D7B4AFB0145915491F901EE0F09 -:1081E000FF1FEE0FFF1FEF5CFB4AC590D490F80114 -:1081F000A590B490FD01E590F490FB0105911491D8 -:10820000BC01641B750B072E000C880B990B0F9497 -:108210008EAE2B013C01B6016A197B09072E000CBA -:10822000880B990B0F948EAE9B01AC01C301B20178 -:108230000F94F5A74B015C01B701601B710B072E72 -:10824000000C880B990B0F948EAE9B01AC01C501FD -:10825000B4010F94DDB46B017C01BE01DD0F880B0E -:10826000990B0F948EAE9B01AC01C701B6010F9420 -:10827000EFB311C02F5F3F4F14962D33310509F036 -:1082800094CFE1E2F5E565917491072E000C880B1F -:10829000990B0F948EAE6B017C0120E030E040E240 -:1082A00052E4C701B6010F943AB687FD1BC020E027 -:1082B00030E048E452E4C701B6010F9488AE1816C6 -:1082C0008CF020E030E040E252E4C701B6010F94A8 -:1082D000EEB320E030E040E05FE30F94F5A79B01B0 -:1082E000AC013FC020E030E048E452E4C701B601F1 -:1082F0000F943AB618163CF520E030E048EC52E412 -:10830000C701B6010F9488AE1816ECF020E030E0FB -:1083100040EA50E4C701B6010F94EFB34B015C0192 -:1083200020E030E048E452E4C701B6010F94EEB318 -:108330002DEC3CEC4CEC5DE30F94F5A79B01AC01FC -:10834000C501B40110C020E030E048EC52E4C701A0 -:10835000B6010F943AB6181654F420E030E040E22B -:1083600051E4C701B6010F94EFB36B017C01C70163 -:10837000B601DF91CF911F910F91FF90EF90DF90A9 -:10838000CF90BF90AF909F908F907F906F905F90B5 -:108390004F9008954F925F926F927F928F929F922B -:1083A000AF92BF92CF92DF92EF92FF920F931F9303 -:1083B000CF93DF9360E080918E0F90918F0F2CD838 -:1083C0006093DC0F7093DD0F8093DE0F9093DF0FCF -:1083D0008091800F9091810FD4DE6093A10E7093F5 -:1083E000A20E8093A30E9093A40E2091850F30913E -:1083F000860FA7E2B5E581E090E0FD01459154913B -:10840000241735070CF05DC0BC0161507109660F7F -:10841000771F660F771FEB01CB5DDA4AFE01E5900F -:10842000F4906D5D7A4AFB0145915491FC01EE0F89 -:10843000FF1FEE0FFF1FEB5DFA4A05911491FE013D -:10844000A590B490FD01C591D491FB01C590D49045 -:10845000B901641B750B072E000C880B990B0F9448 -:108460008EAE2B013C01B8016A197B09072E000C66 -:10847000880B990B0F948EAE9B01AC01C301B20126 -:108480000F94F5A74B015C01CC19DD09BE01DD0F8E -:10849000880B990B0F948EAE9B01AC01C501B40102 -:1084A0000F94DDB44B015C01B701FF0C880B990BF5 -:1084B0000F948EAE9B01AC01C501B4010F94EFB3D4 -:1084C00010C0019614968232910509F096CFE9EA20 -:1084D000F5E565917491072E000C880B990B0F94AC -:1084E0008EAE60939D0E70939E0E80939F0E909320 -:1084F000A00E8091820F9091830F43DE6093080756 -:108500007093090780930A0790930B07A8958FB77C -:10851000F89410925D0F8FBFDF91CF911F910F9153 -:10852000FF90EF90DF90CF90BF90AF909F908F9093 -:108530007F906F905F904F9008954F925F926F92EF -:108540007F928F929F92AF92BF92CF92DF92EF92E3 -:10855000FF920F931F93CF93DF932B013C0181E098 -:108560000F949C661091210281E08093210200917A -:10857000DB0F1092DB0F1092DA0F8091DA0F10925E -:10858000DA0F40923D1050923E1060923F10709270 -:10859000401065E575E585E591E40F948F2A0F9409 -:1085A000822A8091DA0F1092DA0F882309F481C0B1 -:1085B0008091060186FD7DC0C0E0D0E0812C912C29 -:1085C000540120E030E040E05FE360913D107091A5 -:1085D0003E1080913F10909140100F94EFB3609344 -:1085E0003D1070933E1080933F109093401065E5CE -:1085F00075E585E591E40F948F2A40923D105092E5 -:108600003E1060923F107092401065E575E585E57B -:1086100090E40F948F2A0F94822A8091DA0F10929F -:10862000DA0F882309F445C08091060186FD41C018 -:10863000CC2309F469C0BE010D2E000C880B990BE8 -:108640000F948EAE9B01AC01C501B4010F94DDB453 -:108650009B01AC0160913D1070913E1080913F10E4 -:10866000909140100F94EEB36B017C0120E030E05C -:10867000A9010F943AB6181624F0F7FAF094F7F817 -:10868000F09420913D1030913E1040913F10509158 -:108690004010C501B4010F94EFB34B015C012DEC08 -:1086A0003CEC4CE45DE3C701B6010F943AB61816F2 -:1086B0005CF4109321020093DB0F1092DA0F80E03C -:1086C0000F949C6680E024C02196C330D10509F048 -:1086D00078CF20E030E040E450E4C501B4010F94CD -:1086E000DDB460933D1070933E1080933F109093E3 -:1086F0004010109321020093DB0F1092DA0F80E0FC -:108700000F949C6681E004C0C12CD12C7601B9CFB6 -:10871000DF91CF911F910F91FF90EF90DF90CF905D -:10872000BF90AF909F908F907F906F905F904F9091 -:108730000895FF920F931F93CF93DF93CDB7DEB7CA -:1087400028970FB6F894DEBF0FBECDBF08EE13E03A -:108750001D821E821F82188619821A821B821C8229 -:10876000AE014B5F5F4F6FE680E00E9438C6AE01FE -:108770004F5F5F4F6FE681E00E9438C68D819E811A -:10878000AF81B885B7FF0CC089819A81AB81BC816C -:108790008827B7FD83959927AA27BB27F82E01C004 -:1087A000F12C0E94AEC7F11003C00150110981F6EF -:1087B0008F2D28960FB6F894DEBF0FBECDBFDF9188 -:1087C000CF911F910F91FF900895AF92BF92CF92DA -:1087D000DF92EF92FF920F931F93CF93DF93CDB76A -:1087E000DEB76B970FB6F894DEBF0FBECDBF2091FA -:1087F0008116222309F456C2D62E8C018091A91825 -:10880000882309F411C14111E2C08091C118882365 -:1088100041F1E4E7FEE584918F01882339F00E945D -:108820006EAD0F5F1F4FF8018491F7CFE3EDF8E5D0 -:1088300084918F01882339F00E946EAD0F5F1F4F26 -:10884000F8018491F7CF61E070E080E090E00E9451 -:10885000F7AD8AE00E946EAD61E088E094E00F948D -:108860000A0EE6E9FEE584917F01882341F00E942B -:108870006EADFFEFEF1AFF0AF7018491F6CFEAEB36 -:10888000F8E584917F01882341F00E946EADFFEFEF -:10889000EF1AFF0AF7018491F6CF7801F701819171 -:1088A0007F01882319F00E946EADF8CFEFEAF8E55A -:1088B00084917F01882341F00E946EADFFEFEF1A93 -:1088C000FF0AF7018491F6CFE090C118FDE8EF9E12 -:1088D000C00111249C012A53374E8FE2F901819384 -:1088E0007F01B12CCC24C3948BE1A82E2B2D30E03A -:1088F00080911A1890911B1828173907C0F4A29E6E -:10890000C001A39E900D1124B701845F984E0E9470 -:1089100066E3C7017C010196F7012081222329F03B -:10892000FDE8CF1611F0C394F5CFB394DFCFC7FCA9 -:1089300006C0B70186EA98E10E9466E302C0F7012B -:108940001082E090C118FDE8EF9EC00111249C0147 -:108950002A53374E7901F70181917F01882319F05D -:108960000E946EADF8CFE9EAF8E584917F01882393 -:1089700041F00E946EADFFEFEF1AFF0AF7018491FC -:10898000F6CF60915B1970915C1980915D1990919F -:108990005E194AE00E9486AD8AE00E946EAD809129 -:1089A000C11824E0829FF0011124EE53F74E40914C -:1089B0005B1950915C1960915D1970915E1940834B -:1089C0005183628373838F5F8093C11828C0E6E967 -:1089D000FEE584917F01882341F00E946EAD3FEF58 -:1089E000E31AF30AF7018491F6CFE8E9F8E58491F8 -:1089F0007F01882341F00E946EADFFEFEF1AFF0A5E -:108A0000F7018491F6CF7801F70181917F018823E6 -:108A100019F00E946EADF8CF8AE00E946EAD86EA32 -:108A200098E10E94CAE32AC01092C118E6E9FEE567 -:108A300084917F01882341F00E946EADFFEFEF1A11 -:108A4000FF0AF7018491F6CFE7E8F8E584917F010A -:108A5000882341F00E946EADFFEFEF1AFF0AF70185 -:108A60008491F6CF7801F70181917F01882319F075 -:108A70000E946EADF8CF8AE00E946EAD1092801613 -:108A80001092821619821C8284ED96E19093F01662 -:108A90008093EF160115110589F0F80180818F325E -:108AA00039F4BE016F5F7F4FC8010F942B5906C088 -:108AB00081EF96E19093F0168093EF166091EF1698 -:108AC0007091F016DD2009F49EC021E0A80186EA2D -:108AD00098E10E9491E5882309F46EC08091B7184F -:108AE0009091B818A091B918B091BA188093531901 -:108AF00090935419A0935519B0935619EEE3F9E5E4 -:108B000084917F01882341F00E946EADFFEFEF1A40 -:108B1000FF0AF7018491F6CF7801F70181917F0177 -:108B2000882319F00E946EADF8CFE6E3F9E5849151 -:108B30007F01882341F00E946EADFFEFEF1AFF0A1C -:108B4000F7018491F6CF6091531970915419809177 -:108B50005519909156194AE00E9486AD8AE00E940C -:108B60006EAD10925B1910925C1910925D19109203 -:108B70005E19E8E2F9E584917F01882341F00E94C3 -:108B80006EADFFEFEF1AFF0AF7018491F6CF8AE08E -:108B90000E946EADB80180E090E00F944457809140 -:108BA0009C16882319F08CE996E101C0C8010F9446 -:108BB00060538AE896E070C0E0E0FDE584917F01B3 -:108BC000882341F00E946EADFFEFEF1AFF0AF70114 -:108BD0008491F6CFF80181918F01882319F00E94CA -:108BE0006EADF8CFE5E8F8E584918F01882339F080 -:108BF0000E946EAD0F5F1F4FF8018491F7CF8AE09E -:108C00000E946EAD4BC026E5A80186EA98E10E945D -:108C100091E5811123C0E0E0FDE584917F01882387 -:108C200041F00E946EADFFEFEF1AFF0AF701849149 -:108C3000F6CFF80181918F01882319F00E946EAD63 -:108C4000F8CFE3E8F8E584918F018823C1F20E9410 -:108C50006EAD0F5F1F4FF8018491F7CF81E08093D5 -:108C60007E16E6E1F9E584917F01882341F00E94B8 -:108C70006EADFFEFEF1AFF0AF7018491F6CF78018E -:108C8000F70181917F01882319F00E946EADF8CF22 -:108C90008AE00E946EADC8010F946053CE01019628 -:108CA0000E94BDA76B960FB6F894DEBF0FBECDBF76 -:108CB000DF91CF911F910F91FF90EF90DF90CF90B8 -:108CC000BF90AF9008950F9498838091C118882326 -:108CD000A1F186EA98E10E94CAE38091C11881500F -:108CE0008093C1182DE8829FC001112441E061E00A -:108CF0008A53974E6ADDE091C11884E0E89FF00145 -:108D00001124EE53F74E408151816281738140936B -:108D10005B1950935C1960935D1970935E1986EA34 -:108D200098E10E940EE080918116882381F081E015 -:108D3000809380161092821608950F944A8386EAD3 -:108D400098E10E94CAE3109280160D94F183089571 -:108D50002F923F924F925F926F927F928F929F924B -:108D6000AF92BF92CF92DF92EF92FF920F931F9339 -:108D7000CF93DF93CDB7DEB7C854D1090FB6F894BF -:108D8000DEBF0FBECDBF2DB73EB725963FAF2EAF8E -:108D900025978091C80F8111CBC180910301382F95 -:108DA00031703FAB80FDC4C189E09FE00F9463B395 -:108DB00088AF823009F4BCC182E090E09093230236 -:108DC0008093220280911C1890911D18892B21F00C -:108DD00010921D1810921C180F94EA568C010097DF -:108DE00009F483C14DB75EB75CAF4BAF85369105D3 -:108DF00030F08AE298E50F94410804E610E00F9401 -:108E00001D376BE778E581E00F9423324CE158E59C -:108E100061E080E00F941237C801880F991F880F16 -:108E2000991FEDB7FEB7E81BF90B0FB6F894FEBF1C -:108E30000FBEEDBF2DB73EB72F5F3F4F3AAF29AF03 -:108E4000109298161092991610929A1610929B16DC -:108E50000130110509F433C169012EE1A22E28E188 -:108E6000B22EE12CF12C8091030180FD36C10F94CC -:108E7000BC7DF501E1925F01809198169091991661 -:108E8000A0919A16B0919B16F60181939193A193AC -:108E9000B1936F0160E070E0C7010F944457FFEF9A -:108EA000EF1AFF0A0E151F05F1F6B801615071099E -:108EB00080E090E00F948CAE20E030E040E05FE393 -:108EC0000F94F5A76B017C01B80180E090E00F944E -:108ED0008CAE9B01AC01C701B6010F94F5A70F94AE -:108EE00054B53801C12CD12C76019B0140E050E0F3 -:108EF00029962CAF3DAF4EAF5FAF299731E0631A93 -:108F0000710809F4DEC08091030180FDE6C0A4E68B -:108F1000B0E0A70196010F94D5B329962CAD3DADD5 -:108F20004EAD5FAD29970F94B3B3822F65E00F94D8 -:108F300080B8A82E880FBB08812C912C8A149B0422 -:108F40003CF462E0882D0F946E3281E00E949D9A7D -:108F50004FEF841A940A54E18516910479F78FEF44 -:108F6000C81AD80AE80AF80A9EE1892E98E1992ED3 -:108F7000412C212C312C8091030180FDAEC00F9437 -:108F8000BC7DF40121914F012DAF3FEF231A330A2D -:108F900040814EAFA42EB12C5FEFC51AD50AE50A69 -:108FA000F50AE9ADFAAD84E0289FE00DF11D11242A -:108FB00060817181828193810F948B5780919C167F -:108FC000811103C063E876E102C06CE976E1CE016D -:108FD00001960F9447B9E0919216F091931621965D -:108FE000FFAFEEAF21972091901630919116239606 -:108FF0003FAF2EAF23975090D116AA0CBB1CAA0CE2 -:10900000BB1CE9ADFAADEA0DFB1D60817181828167 -:1090100093810F948B5780919C16811103C063E854 -:1090200076E102C06CE976E138AD31112AC0809159 -:10903000D116581223C080919216909193162196C2 -:109040004EAD5FAD21974817590781F48091901676 -:10905000909191162396EEADFFAD23978E179F0743 -:1090600008F12614370408F486CF26C021962EADC9 -:109070003FAD219782179307A8F0F3CF511012C08C -:10908000F0CF38AD313069F78091D116581208C051 -:10909000CE0101960F9415B9181619061CF0E1CFF0 -:1090A0005110DFCFF40131974EAD40832DADF40167 -:1090B000208344244394D5CF411020CF02C0109286 -:1090C0001E1810931D1800931C184BAD5CAD0FB605 -:1090D000F8945EBF0FBE4DBF08C08BAD9CAD0FB600 -:1090E000F8949EBF0FBE8DBF23C062E08FA90F947E -:1090F0006E3281E00E949D9A9FA99F5F9FAB943141 -:10910000A1F76CE271E080E090E00F940D870F947E -:1091100042320F941D3782E00F94932F81E090E04C -:10912000909323028093220281E596E10E943EDD26 -:109130002596EEADFFAD25970FB6F894FEBF0FBE96 -:10914000EDBFC85BDF4F0FB6F894DEBF0FBECDBFDB -:10915000DF91CF911F910F91FF90EF90DF90CF9013 -:10916000BF90AF909F908F907F906F905F904F9047 -:109170003F902F900895CF92DF92EF92FF921F932E -:10918000CF93DF93109281168091D716882321F018 -:1091900084ED96E10E94CAE310928618109283181B -:1091A0008DE4809382180F942588EB0161E0809113 -:1091B00082180F940A8682E898E10E946EE660E0C9 -:1091C00082E30F940A8661E083E30F940A8661E0EC -:1091D00084E30F940A8661E085E30F940A8661E0D8 -:1091E00085E30F94DC8585E08093841882E58CBD4F -:1091F0001DBC1AE08FEF0E9473E61150D9F720E0F2 -:1092000030E0A90160E082E898E10E947FE6182F33 -:1092100080938518813049F00F9425886C1B7D0B55 -:10922000613D774060F381E054C02AEA31E040E0DC -:1092300050E068E082E898E10E947FE682FF03C088 -:10924000109386180EC014E00E9478E6809385186B -:109250001150D1F78A3A11F082E03BC082E080934E -:10926000861880918618823021F0C12CD12C76018D -:1092700005C0C12CD12CE12C80E4F82E20E030E098 -:10928000A90167E382E898E10E947FE6A7019601C1 -:1092900069E282E898E10E947FE68093851888233E -:1092A00049F00F9425886C1B7D0B613D774030F3AE -:1092B0008AE00FC080918618823021F520E030E0EE -:1092C000A9016AE382E898E10E947FE6882361F0C1 -:1092D00088E08093831882E898E10E946EE6E6E9D0 -:1092E000FEE58491EF011AC00E9478E6807C803C04 -:1092F00019F483E0809386180E9478E60E9478E64D -:109300000E9478E682E898E10E946EE61092841846 -:1093100081E00F94D05781114CC02EC0882331F0CA -:109320000E946EAD2196FE018491F8CFEFE0F8E542 -:109330008491EF01882331F00E946EAD2196FE01E9 -:109340008491F8CF8AE00E946EAD8BE1E4EDF6E106 -:10935000A1EFB6E101900D928A95E1F784ED96E1D7 -:109360009093F0168093EF16DF91CF911F91FF90AD -:10937000EF90DF90CF90ECCC80E00F94D05781112C -:1093800018C0E4E7FEE58491EF01882331F00E94E4 -:109390006EAD2196FE018491F8CFECEFF7E5849154 -:1093A000EF01882379F20E946EAD2196FE0184912F -:1093B000F8CF68E878E184ED96E10E94BCDF811186 -:1093C00019C0E4E7FEE58491EF01882331F00E94A3 -:1093D0006EAD2196FE018491F8CFECEEF7E5849115 -:1093E000EF01882309F4AECF0E946EAD2196FE01F5 -:1093F0008491F7CF81E080938116E6E9FEE58491C0 -:10940000EF01882331F00E946EAD2196FE01849118 -:10941000F8CFE1EEF7E58491EF01882309F492CFCC -:109420000E946EAD2196FE018491F7CF2F923F925C -:109430004F925F926F927F928F929F92AF92BF9264 -:10944000CF92DF92EF92FF920F931F93CF93DF9310 -:1094500000D01F92CDB7DEB75C014B018091A918F7 -:10946000813009F58091A71881FF1DC082FF21C0BE -:109470004091B7185091B8186091B9187091BA1806 -:109480008091AE189091AF18A091B018B091B1181A -:1094900084179507A607B70761F086EA98E10E944E -:1094A0000EE0811106C081E08093A6188FEF9FEF38 -:1094B00049C17401212C32E0332E88C08091BF183D -:1094C0009091C018DC0114967C907A94B901A8019F -:1094D00029E076956795579547952A95D1F7742297 -:1094E0001170772009F47FC0C101801B910B6701C7 -:1094F0008E159F0508F46C01E091BF18F091C0181B -:109500008091AA189091AB18A091AC18B091AD18A9 -:109510000297A109B109058404C0880F991FAA1FE9 -:10952000BB1F0A94D2F74685578560897189840FDD -:10953000951FA61FB71F9C01AD01270D311D411DB1 -:10954000511D29013A01C11432E0D30609F09AC035 -:1095500080914E1390914F13A0915013B0915113DD -:10956000481659066A067B0669F4109256138FEF67 -:109570009FEFDC0180934E1390934F13A0935013F1 -:10958000B09351139501B301A201809157139091AB -:1095900058130E9467DD882309F485CF8091AE18A7 -:1095A0009091AF18A091B018B091B1188C0D9D1D7D -:1095B000A11DB11D8093AE189093AF18A093B01861 -:1095C000B093B118AC0CBD1CEC18FD080091AE189E -:1095D0001091AF182091B0183091B118E114F10436 -:1095E00009F06CCF88C00115110509F07DCF4091BD -:1095F000AA185091AB186091AC187091AD18411534 -:1096000051056105710569F48091BB189091BC18F2 -:10961000A091BD18B091BE180097A105B10549F5FC -:1096200021C09E012F5F3F4F0E94D5DE882309F4A1 -:109630003ACF89819A81AB81BC81E091BF18F091CA -:10964000C0182789203139F4883FEFEF9E07A10524 -:10965000B10540F40EC0883FFFEF9F07AF07FFE062 -:10966000BF0738F086EA98E10E94A8E081113CCF5C -:109670001ACF8093AA189093AB18A093AC18B0930C -:10968000AD1832CF0115110531F54091AE1850914A -:10969000AF186091B0187091B1188091B71890917F -:1096A000B818A091B918B091BA18481759076A07A5 -:1096B0007B0788F00E94CFDD882309F4F4CE81E097 -:1096C0008093561340924E1350924F136092501352 -:1096D0007092511308C041E0C301B2010E940DDE37 -:1096E000882309F4E0CEA601B501C801825B9E4E35 -:1096F0000F9405B953CF8091B7189091B818A091E5 -:10970000B918B091BA1880179107A207B30768F487 -:109710000093B7181093B8182093B9183093BA185B -:109720008091A71880688093A7188091A71883FD5F -:1097300002C0C40107C086EA98E10E9499E3811142 -:10974000F8CFB1CE0F900F900F900F90DF91CF9187 -:109750001F910F91FF90EF90DF90CF90BF90AF904F -:109760009F908F907F906F905F904F903F902F9041 -:109770000895EF92FF920F931F93CF93DF93CDB78E -:10978000DEB76B970FB6F894DEBF0FBECDBF7C017E -:1097900019821C828091F416882319F001EF16E1DA -:1097A00002C004ED16E121E0A701B801CE01019647 -:1097B0000E9491E5811127C0E6E9FEE584918F01C1 -:1097C000882339F00E946EAD0F5F1F4FF80184911E -:1097D000F7CFEBECF7E584918F01882339F00E94F5 -:1097E0006EAD0F5F1F4FF8018491F7CF8701F8012D -:1097F00081918F01882319F00E946EADF8CF8AE025 -:109800000E946EAD35C020911A1830911B182A3075 -:10981000310520F5C901019690931B1880931A1801 -:109820004BE1429FC001439F900D1124845F984EED -:10983000F6E1813F9F0751F02BE1FC01DC015B96D3 -:1098400001900D922A95E1F74B97F2CF8BE1F80149 -:10985000ACE0B7E101900D928A95E1F78BE1FE0152 -:109860003196A1EFB6E101900D928A95E1F770DA99 -:10987000CE0101960E94BDA76B960FB6F894DEBF8D -:109880000FBECDBFDF91CF911F910F91FF90EF9051 -:10989000089583B182958170089583B18295817016 -:1098A00091E0892708958091091090910A100895F8 -:1098B000CF92DF92EF92FF920F931F93E0910B10E4 -:1098C0008C0120E030E08091251090912610A0912D -:1098D0002710B0912810E0FF0DC0801B910BA20B48 -:1098E000B30B8093251090932610A0932710B0936C -:1098F00028100CC0080F191F2A1F3B1F00932510AA -:10990000109326102093271030932810CB01A0E04D -:10991000B0E00091291010912A1020912B10309165 -:109920002C10E1FF09C068017901C81AD90AEA0AB6 -:10993000FB0AD701C60104C0800F911FA21FB31FED -:109940008093291090932A10A0932B10B0932C1081 -:10995000CA01A0E0B0E040912D1050912E1060910E -:109960002F1070913010E2FF09C07A018B01E81AC4 -:10997000F90A0A0B1B0BD801C70104C0840F951FFD -:10998000A61FB71F80932D1090932E10A0932F1019 -:10999000B09330101F910F91FF90EF90DF90CF9018 -:1099A00008958091DE069091DF06815C9E4B11F454 -:1099B0000D9442326BE47BE581E00D94233280E02C -:1099C00090E0A0E8BFE38093F60F9093F70FA09389 -:1099D000F80FB093F90F8AEB99EF0D940D30CF92F9 -:1099E000DF92EF92FF920F931F93CF93DF93F82EA6 -:1099F000E62E6A01E901682F8E2D0F946E3281E008 -:109A0000C816D10429F192E0C916D10409F03FC06B -:109A1000CE010F941031FE0101900020E9F731973B -:109A2000CF018C1B9D0B6F2D8E0D0F946E328FE727 -:109A300095E00F941031FE0101900020E9F78E2D82 -:109A40008E0F6F2D8C1B0F946E3284EC94E020C02F -:109A5000CE010F941031FE0101900020E9F73197FB -:109A6000CF018C1B9D0B6F2D8E0D0F946E328FE7E7 -:109A700095E00F941031FE0101900020E9F78E2D42 -:109A80008E0F6F2D8C1B0F946E32C80101C0CE015A -:109A9000DF91CF911F910F91FF90EF90DF90CF90CA -:109AA0000D9410319091840289133DC0EDEDFCE5D9 -:109AB000E4919FEF90938402E230C9F050F4EE23DA -:109AC00099F0E13081F590916F009D7F90936F0048 -:109AD0002AC0E43019F1E0F0E53029F590917300E7 -:109AE0009D7F909373001FC010926E001CC09091D8 -:109AF00070009D7F9093700091E09093B0009091E2 -:109B0000B100987F94609093B1001092B3000BC0A5 -:109B1000909171009D7F9093710005C090917200AB -:109B20009D7F9093720060E00D94DC851F920F92F0 -:109B30000FB60F9211240BB60F922F933F934F93B2 -:109B40005F936F937F938F939F93AF93BF93EF93A5 -:109B5000FF938091211090912210A0912310B09139 -:109B60002410892B8A2B8B2B51F190911E10E091A0 -:109B70001F10F0912010808189278083809121100F -:109B800090912210A0912310B0912410181619065C -:109B90001A061B06BCF48091211090912210A0910E -:109BA0002310B09124100197A109B10980932110CD -:109BB00090932210A0932310B093241003C080919F -:109BC000840270DFFF91EF91BF91AF919F918F91D0 -:109BD0007F916F915F914F913F912F910F900BBEAD -:109BE0000F900FBE0F901F9018952F923F924F929B -:109BF0005F926F927F928F929F92AF92BF92CF921D -:109C0000DF92EF92FF920F931F93CF93DF93CDB725 -:109C1000DEB728970FB6F894DEBF0FBECDBFF901AF -:109C2000C0902510D0902610E0902710F0902810BA -:109C30007C01EC18FD088091291090912A10A091C8 -:109C40002B10B0912C10681B790B80912D109091E6 -:109C50002E10A0912F10B09130109A01281B390BB3 -:109C60003A8329835F2D551F5527551F372F331FE3 -:109C70003327331F330F932F952B3A81331F33270D -:109C8000331F330F330F392B30930B1090910B018F -:109C9000987B5AE0352730FD916031FD926032FDAE -:109CA0009460906490930B010000002329F007FD5D -:109CB00006C080E791E005C080E090E002C08EED34 -:109CC00091E09093FB0C8093FA0CF0930A10E093D0 -:109CD000091089819A8198878F8397FF05C0919594 -:109CE0008195910998878F838B0177FF03C0119528 -:109CF00001951109F7FE03C0F194E194F108980170 -:109D0000D8010F94D8B84B015C012F813885D90157 -:109D10000F94D8B8860E971EA81EB91E9701D701BA -:109D20000F94D8B8680D791D8A1D9B1D0F948CAEB9 -:109D30000F9473B720E030E040E05FE30F94EFB39F -:109D40000F9454B53B014B015B016B012B011E824B -:109D50001D821C821B82212C312C1A8219824114F3 -:109D6000510409F45DC0E091FA0CF091FB0C3097BE -:109D700029F4EC14FD0430F480E00DC0199588231B -:109D8000C1F34EC0C60CD71C29813A812F5F3F4FCB -:109D90003A83298381E00A151B0530F08260A60C06 -:109DA000B71C3FEF231A330A2F8138852815390550 -:109DB00048F08460860C971C2B813C812F5F3F4FBD -:109DC0003C832B836114710439F484602D813E81BE -:109DD0002F5F3F4F3E832D83CE18DF08A01AB10AB4 -:109DE0002F813885821A930A0E943EBDE091F60CBD -:109DF000F091F70C309739F0B301C2011995823018 -:109E0000910550F002C084EF91E0880F991F880FF0 -:109E1000991F05970197F1F731E0431A51089FCF39 -:109E2000E091F80CF091F90C309741F02D813E81D2 -:109E30004B815C81B10189819A81199581E0452826 -:109E400009F480E028960FB6F894DEBF0FBECDBFB0 -:109E5000DF91CF911F910F91FF90EF90DF90CF9006 -:109E6000BF90AF909F908F907F906F905F904F903A -:109E70003F902F9008952F923F924F925F926F9252 -:109E80007F928F929F92AF92BF92CF92DF92EF928A -:109E9000FF920F931F93CF93DF93CDB7DEB76897F1 -:109EA0000FB6F894DEBF0FBECDBF9A87898780EAD0 -:109EB0009BE59F938F930F9493AD80912510909184 -:109EC0002610A0912710B09128109A838983809042 -:109ED000291090902A10A0902B10B0902C109C82EA -:109EE0008B82C0902D10D0902E10E0902F10F0900B -:109EF00030109F938F9388E99BE59F938F930F94E6 -:109F000093AD9F928F9280E99BE59F938F930F94DF -:109F100093ADDF92CF9288E89BE59F938F930F9448 -:109F200093AD960120573E4F3E832D83809029109C -:109F300090902A10A0902B10B0902C10809125109A -:109F400090912610A0912710B09128100FEF24EFC8 -:109F500031E04D815E81B40148DE30E9C31A31E061 -:109F6000D30A8090291090902A10A0902B10B090C6 -:109F70002C108091251090912610A0912710B0915F -:109F8000281001E024EF31E0A601B4012EDE80901C -:109F9000291090902A10A0902B10B0902C10809136 -:109FA000251090912610A0912710B09128100FEF46 -:109FB00024EF31E04D815E81B40117DE80902910DD -:109FC00090902A10A0902B10B0902C10809125100A -:109FD00090912610A0912710B091281001E024EF55 -:109FE00031E0A601B40101DE80912D1090912E1078 -:109FF000A0912F10B0913010AC0144515109588FED -:10A000004F8BC0902910D0902A10E0902B10F09028 -:10A010002C108091251090912610A0912710B091BE -:10A02000281000E024EF31E0B601DFDD588D5F93AA -:10A030008F898F938EE79BE59F938F930F9493ADBA -:10A040000FB6F894DEBF0FBECDBF9DE2292E312C96 -:10A05000412C512C32011D821E821F8218862B81B9 -:10A060003C81032E000C440B550B2F87388B498BFA -:10A070005A8B89819A81092E000CAA0BBB0B8B8B02 -:10A080009C8BAD8BBE8BB101032C000C880B990B04 -:10A090000F948EAE2BED3FE049E450E40F94F5A70A -:10A0A00020E030E044E353E40F94DDB46B017C0125 -:10A0B0000F94DAB46B877C878D879E87C701B601C2 -:10A0C0000F9468B74B015C016F85788989899A89FB -:10A0D0000F948EAE6B017C0120E030E046E154E449 -:10A0E000C501B4010F94F5A79B01AC01C701B601EE -:10A0F0000F94EFB30F944EB56B017C016B897C8993 -:10A100008D899E890F948EAE4B015C0120E030E07A -:10A1100046E154E46B857C858D859E850F94F5A77B -:10A120009B01AC01C501B4010F94EFB30F944EB580 -:10A13000DC01CB010FEF29853A854F89588DB60197 -:10A1400054DD81110EC03F922F9281E79BE59F93D2 -:10A150008F930F9493AD0F900F900F900F9010E08E -:10A160007AC08091251090912610A0912710B0916F -:10A170002810092E000CAA0BBB0B2D813E814F81AC -:10A180005885280F391F4A1F5B1F2D833E834F833D -:10A1900058878091291090912A10A0912B10B0918E -:10A1A0002C10092E000CAA0BBB0B480E591E6A1E60 -:10A1B0007B1E00E029853A854F89588D6B817C8113 -:10A1C00089819A8112DD3AE5230E311C45E9241676 -:10A1D00041E0340609F057CF81E08F9385E98F93F2 -:10A1E0008DE69BE59F938F930F9493AD84E0C82EEB -:10A1F000D12CE12CF12C6D817E818F819885A70176 -:10A2000096010F94B4B8B22EA32E222E332E3A828A -:10A210002982C301B201A70196010F94B4B8122F8D -:10A22000F32E822F932F9C838B83AF92BF9285E670 -:10A230009BE59F938F930F9493ADFF921F938DE5B2 -:10A240009BE59F938F930F9493AD0FB6F894DEBF69 -:10A250000FBECDBF11E000E029853A854F89588DAA -:10A260006B817C8189819A81C0DC812F68960FB6D1 -:10A27000F894DEBF0FBECDBFDF91CF911F910F913C -:10A28000FF90EF90DF90CF90BF90AF909F908F9016 -:10A290007F906F905F904F903F902F9008958EBD6C -:10A2A0000DB407FEFDCF8EB50895459885E0F7DF24 -:10A2B0008FEFF5DF459A80FDF8CF0895459886E049 -:10A2C000EEDF459A0895CF933D9A459A8CE58CBD73 -:10A2D0001DBC459880E9E3DF80E0E1DF80E0DFDF5F -:10A2E00080E0DDDF8FEFDBDFC82F8FEFD8DF982F27 -:10A2F000459ACF3E19F481E0913109F080E0CF9189 -:10A3000008950F931F93CF93DF93CDB7DEB72897B0 -:10A310000FB6F894DEBF0FBECDBF00E010E0F8012D -:10A32000ED5AF44A6491C8010F9475B30F5F1F4F43 -:10A330000A301105A1F7CE0101960F94116488230C -:10A34000C1F069817A818AE090E00F948FB36B81CC -:10A350007C818CE090E00F948FB36D817E818EE0E4 -:10A3600090E00F948FB36F81788580E190E00F9437 -:10A370008FB328960FB6F894DEBF0FBECDBFDF9126 -:10A38000CF911F910F910895982F8F7D49F087EFFE -:10A39000890F823028F081E09D3019F080E0089527 -:10A3A00081E00895E0EEFFE001900020E9F73197A9 -:10A3B000E05EFF401E161F065CF4E052F04F80E2A4 -:10A3C0009F01205E3F402431310514F48193F8CF82 -:10A3D0001092F40F82E08093860208952091F50F89 -:10A3E00021110AC0BC0144E150E080EE9FE00F94CF -:10A3F00074AC1092F40FD6CF08950F931F938091F1 -:10A400000301817091E089272091DD068217D9F040 -:10A4100082E0809386028091030181709827909357 -:10A42000DD060E94149A8091DD06882329F00F949E -:10A43000BB4887E19BE506C01092801610928116FA -:10A440008AE09BE5CBDF0F942588009105101091E1 -:10A4500006102091071030910810061717072807DB -:10A46000390708F09EC08091BD19282F082E000CD6 -:10A47000330B37FF03C03195219531092430310565 -:10A4800054F190918602911103C091E0909386025D -:10A4900087FD8D5F85958595082E000C990BAA0B7D -:10A4A000BB0B4091AC195091AD196091AE197091F0 -:10A4B000AF19840F951FA61FB71F8093AC199093F7 -:10A4C000AD19A093AE19B093AF191092BD1981E5E3 -:10A4D00096E10E943EDD8091041082FF04C081E578 -:10A4E00096E10E943EDDE091DE06F091DF061995CF -:10A4F0008091DE069091DF068C5C9D4F51F440E91F -:10A500005FE561E070E081E596E10E94F9DC811190 -:10A5100018C08091DE069091DF062EEB813C9207F9 -:10A5200009F4A2C08C5C9D4F09F49EC040E355E73E -:10A5300060E070E081E596E10E94F9DC882309F48F -:10A5400093C0E091DE06F091DF06309731F081E0B4 -:10A55000809303101995109203100F941D370F94D8 -:10A56000388A82E08093860280918602823011F4DC -:10A570000F941D3780918602882319F081508093B3 -:10A5800086020F942588DC01CB018C599F4FAF4F79 -:10A59000BF4F8093051090930610A0930710B093BF -:10A5A00008108091D7199091D819A091D919B0911C -:10A5B000DA19823A924AA105B10551F1809101015F -:10A5C00084608093010180910107909102070397B5 -:10A5D00040F49FB7F8948091020184608093020157 -:10A5E0009FBF68EE73E080E090E00F940D879FB707 -:10A5F000F894809102018B7F809302019FBF8FEDC1 -:10A600009AE50F94930788EE93E00F94BD12FBCF69 -:10A610008091C80F81110F9425888091C80F8823DD -:10A62000C9F0809128078823A9F00F94258800910C -:10A63000FD0F1091FE0F2091FF0F30910010DC01F3 -:10A64000CB01801B910BA20BB30B81319742A1056B -:10A65000B105D8F48091011090910210089739F556 -:10A660001F910F910D940D138091DE069091DF06DE -:10A67000815C9E4B11F480E002C08091FA0F109231 -:10A68000FA0F882309F470CF5CCF8091270760917F -:10A69000FC0F90E00F94BE020F9425886093FD0F8D -:10A6A0007093FE0F8093FF0F90930010D3CF1F91F4 -:10A6B0000F91089593DE81E08093F50F0D94388A11 -:10A6C0002091F50F211108C0BC0144E150E080EE5B -:10A6D0009FE00F945CB966CE08957F928F929F920F -:10A6E000AF92BF92CF92DF92EF92FF920F931F93A0 -:10A6F000CF93DF93EC016B015A01722E480180E089 -:10A700000F942737AC14BD042CF021EAE22E26E08A -:10A71000F22E04C09FE9E92E96E0F92E71100F94F5 -:10A720001D3760E080E00F946E32CF3F8FEFD80787 -:10A7300011F0209729F48CE190E60F94953118C020 -:10A74000C130D10529F48CE190E60F94953118C001 -:10A75000C230D10529F48DEC9AE50F94953118C0DB -:10A76000C330D10529F48BEB9AE50F94953120C0C5 -:10A77000C430D10529F489EA9AE50F94953120C0B7 -:10A78000C530D10529F487E99AE50F9495311BC0AE -:10A79000C630D10529F485E89AE50F94953119C0A2 -:10A7A000C730D10529F483E79AE50F94953117C096 -:10A7B000C830D10529F483E79AE50F94953115C087 -:10A7C000C930D10519F0CA30D10519F481E69AE5EE -:10A7D00011C0CB30D10519F48FE49AE50BC0CC3011 -:10A7E000D10519F48DE39AE505C0CD30D10521F4EA -:10A7F0008AE39BE50F94953161E080E00F946E321F -:10A8000085E29BE50F949531CE010196039708F5FB -:10A810004FE25AE562E080E00F94123762E082E195 -:10A820000F946E32CF3F8FEFD80711F4C70102C0EB -:10A8300084EC94E00F94103144E25AE563E080E048 -:10A840000F94123763E082E10F946E32219789F002 -:10A8500015C0CE010997029798F443E15AE562E0EA -:10A8600080E00F94123762E082E10F946E322997F4 -:10A8700029F084EC94E00F94103173C0C701FBCF32 -:10A88000C930D1050CF06DC0C330D10531F0C330F3 -:10A89000D10534F042E050E005C041E050E002C094 -:10A8A00040E050E0870123EA36E069E070E083E0B1 -:10A8B00090E095D8C430D10531F0C430D10534F0E2 -:10A8C00042E050E005C041E050E002C040E050E00E -:10A8D00087012AEA36E062E070E082E090E07FD80B -:10A8E000C530D10531F0C530D10534F042E050E03B -:10A8F00005C041E050E002C040E050E087012EE496 -:10A9000036E068E070E082E090E069D8C630D105BA -:10A9100031F0C630D10534F042E050E005C041E0EE -:10A9200050E002C040E050E087012CEA36E06EE0E3 -:10A9300070E082E090E053D8C730D10529F0279726 -:10A9400034F042E050E005C041E050E002C040E099 -:10A9500050E087012EEA36E060E070E083E090E0AE -:10A960003ED8181419041CF4C4010F94BD12B6018A -:10A970006F5F7F4FAA0CBB1CA616B70614F0CB0165 -:10A9800002C080E090E0DF91CF911F910F91FF9086 -:10A99000EF90DF90CF90BF90AF909F908F907F907F -:10A9A0000895EF92FF920F931F93CF93DF938C0143 -:10A9B000EB017A010F94A52F10928A151092891538 -:10A9C0001092030D1092020D0F94BC7D80E00F9445 -:10A9D000680E0F941D3760E080E00F946E3282E0C5 -:10A9E0009AE50F94953161E080E00F946E3283EF29 -:10A9F00099E50F949531F8013197EB30F10508F0A6 -:10AA0000A5C062E08827EE55FF4F8F4F0D94D0B858 -:10AA100080E00F946E3281EE99E50F94953163E0FA -:10AA200080E00F946E3283ED99E58EC080E00F9444 -:10AA30006E3286EC99E580C080E00F946E3280EB38 -:10AA400099E50F94953163E080E00F946E3289EBC5 -:10AA500099E50F94953163E081E163C080E00F9444 -:10AA60006E328AEA99E50F94953162E082E10F94A3 -:10AA70006E32CE010F94103163E080E00F946E329D -:10AA800082EA99E50F94953163E082E10F946E328A -:10AA9000C7014AC080E00F946E3282E999E519C07F -:10AAA00080E00F946E328BE090E605C080E00F945A -:10AAB0006E328AEF9FE50F94953163E080E00F944A -:10AAC0006E3289EB99E529C080E00F946E3285E8FB -:10AAD00099E50F94953163E080E00F946E328AEA35 -:10AAE00099E51BC080E00F946E3289E799E50F94D9 -:10AAF000953163E080E00F946E3284E799E50DC0F4 -:10AB000080E00F946E3284E699E50F94953163E00E -:10AB100080E00F946E328CE599E50F94953163E0F7 -:10AB200082E10F946E32CE010F9410310FC080E09D -:10AB30000F946E328CE499E50F94953163E080E0D8 -:10AB40000F946E3289EB99E50F94953168EE73E0BE -:10AB500080E090E00F940D870F94A52F64E670E0DD -:10AB600080E090E00F940D870F94BC7D80E00F94FF -:10AB7000680E0F946B30882389F38DE39AE59ADD94 -:10AB8000DF91CF911F910F91FF90EF900D94388A34 -:10AB90005F926F927F928F929F92AF92BF92CF926D -:10ABA000DF92EF92FF920F931F93CF93DF93582E74 -:10ABB0008823E1F0609108077091090780910A07E6 -:10ABC00090910B070F944EB5EB016091DC0F7091E3 -:10ABD000DD0F8091DE0F9091DF0F0F944EB57B015A -:10ABE00024EB822E912C80E090E01BC06091DC0F62 -:10ABF0007091DD0F8091DE0F9091DF0F0F944EB5B5 -:10AC0000EB01609108077091090780910A07909104 -:10AC10000B070F944EB57B019CE3892E912C88EC99 -:10AC200090E090938A1580938915511003C080E0BD -:10AC300090E002C084E690E09093030D8093020DB3 -:10AC40000F94BC7D81E00F94680E81E090E09093BA -:10AC5000230280932202A12CB12CC12CD12C85E09F -:10AC6000682E712C8FEFC81AD80A0F94BC7D81E032 -:10AC70000F94680E00E911E020E042E050E0B501D9 -:10AC8000552019F087E090E002C083E090E025DDD8 -:10AC90005C01C601B3010F94A1B8892B11F40E9485 -:10ACA000C7F2C814D904F1F610928A1510928915CA -:10ACB0001092030D1092020D0F94BC7DB701FF0C92 -:10ACC000880B990B552069F1C0900807D0900907AF -:10ACD000E0900A07F0900B070F948EAE9B01AC0139 -:10ACE0006091DC0F7091DD0F8091DE0F9091DF0F8E -:10ACF0000F94EEB30F944EB56A3071050CF045C059 -:10AD0000BE01DD0F880B990B0F948EAE9B01AC0139 -:10AD1000C701B6010F94EEB30F944EB583E090E0F7 -:10AD20002BC0C090DC0FD090DD0FE090DE0FF090D4 -:10AD3000DF0F0F948EAE9B01AC01609108077091FC -:10AD4000090780910A0790910B070F94EEB30F94B7 -:10AD50004EB563307105CCF4BE01DD0F880B990B45 -:10AD60000F948EAE9B01AC01C701B6010F94EEB3F8 -:10AD70000F944EB58AE090E06817790774F448E0C4 -:10AD800054E0BA0181E090E005C048E054E0BA0127 -:10AD900082E090E006DEC0E001C0C1E00F94BC7D1F -:10ADA00081E00F94680E82E090E0909323028093FC -:10ADB00022028C2FDF91CF911F910F91FF90EF9086 -:10ADC000DF90CF90BF90AF909F908F907F906F90CB -:10ADD0005F900895EF92FF920F931F93CF93DF93AD -:10ADE000CDB7DEB76B970FB6F894DEBF0FBECDBF01 -:10ADF0008FEEE82E86E1F82E81EF96E1D7018D9354 -:10AE00009C9381E090E0909361198093601902E631 -:10AE100019E1F8011182108281EF96E10E94A4E00D -:10AE2000D701ED91FC918BE1DE01119601900D921D -:10AE30008A95E1F740E050E0BE016F5F7F4F88E008 -:10AE400094E00F94787BCE0101960E94BDA7F80193 -:10AE5000808191816B960FB6F894DEBF0FBECDBF97 -:10AE6000DF91CF911F910F91FF90EF90089586EAA7 -:10AE700098E10E9499E386EA98E10E94CAE3EEE72E -:10AE8000F6E1108211820895EF92FF920F931F93C3 -:10AE9000CF93DF93CDB7DEB76B970FB6F894DEBFD5 -:10AEA0000FBECDBF7B010FEE16E121EF36E1D801D9 -:10AEB0002D933C9322E030E0309361192093601988 -:10AEC000909363198093621981EF96E10E94A4E048 -:10AED000D801ED91FC918BE1DE01119601900D926C -:10AEE0008A95E1F7A701BE016F5F7F4F88E094E08C -:10AEF0000F94787BCE0101960E94BDA76B960FB68A -:10AF0000F894DEBF0FBECDBFDF91CF911F910F919F -:10AF1000FF90EF9008950F931F93CF93DF93CDB7DA -:10AF2000DEB76B970FB6F894DEBF0FBECDBFAB0197 -:10AF3000BC010FEE16E181EF96E1D8018D939C9351 -:10AF400082E090E0909361198093601910926319E8 -:10AF50001092621981EF96E10E940EE0D801ED9106 -:10AF6000FC918BE1DE01119601900D928A95E1F73B -:10AF700040E050E0BE016F5F7F4F88E094E00F94A7 -:10AF8000787BCE0101960E94BDA76B960FB6F89410 -:10AF9000DEBF0FBECDBFDF91CF911F910F910895FE -:10AFA0008F929F92AF92BF92CF92DF92EF92FF92D9 -:10AFB0001F93CF93DF93C82F82E898E190935813A3 -:10AFC0008093571310929F1882E090E0A0E0B0E0C9 -:10AFD0008093881890938918A0938A18B0938B183F -:10AFE000109256131092521310925313109254133E -:10AFF000109255138FEF9FEFDC0180934E139093C7 -:10B000004F13A0935013B0935113CC2379F1C53053 -:10B0100008F0F8C040E060E070E0CB010E940DDE77 -:10B02000882309F4EFC020E1C29FC0011124825C93 -:10B030009E4EFC01E254FE4F20812F7709F0E2C0C2 -:10B040003C9640815181628173814436510561058E -:10B05000710508F4D7C03497C080D180E280F380B6 -:10B06000C114D104E104F10421F4CCC0C12CD12CD1 -:10B07000760140E0C701B6010E940DDE182F88233B -:10B0800009F4C0C08091591190915A1181159240D4 -:10B0900009F0B8C0A0915E11AA2309F4B3C0609171 -:10B0A0005C1170915D116115710509F4ABC02091BF -:10B0B0005B11222309F4A6C0A0939A1820938C1840 -:10B0C00080E030E041E050E0C82FFA01082E02C0D5 -:10B0D000EE0FFF1F0A94E2F72E173F0739F08F5F3C -:10B0E000C83091F789E0809395188CC080939518AB -:10B0F00020916411309165112115310519F040E05E -:10B1000050E008C020917211309173114091741178 -:10B110005091751120938D1830938E1840938F188D -:10B120005093901846015701860E971EA11CB11C22 -:10B1300080929B1890929C18A0929D18B0929E1895 -:10B14000E0915F11F0916011F093A118E093A018C5 -:10B15000B0E00F94D5B3860E971EA81EB91E80923C -:10B16000A2189092A318A092A418B092A51885E0F6 -:10B17000EE0FFF1F8A95E1F7E150FE4FEF2FFF27FB -:10B18000E6958E0E9F1EA11CB11C8092961890927F -:10B190009718A0929818B092991820916111309147 -:10B1A00062112115310521F0A90160E070E008C0AD -:10B1B00040916E1150916F116091701170917111E9 -:10B1C000D701C60188199909AA09BB09840F951FDF -:10B1D000A61FB71F04C0B695A79597958795CA95E2 -:10B1E000D2F78093911890939218A0939318B093EC -:10B1F0009418853F2FE09207A105B10528F48CE053 -:10B2000080939F1810E01AC0853F9F4FA105B1059C -:10B2100010F480E111C080917A1190917B11A0917E -:10B220007C11B0917D118093A2189093A318A093E4 -:10B23000A418B093A51880E280939F18812FDF9106 -:10B24000CF911F91FF90EF90DF90CF90BF90AF9084 -:10B250009F908F900895AF92BF92CF92DF92EF921E -:10B26000FF920F931F93CF93DF93CDB7DEB72D9748 -:10B270000FB6F894DEBF0FBECDBF6B018C010F5F20 -:10B280001F4FF8018081882309F463C06FE270E0EA -:10B29000C8010F9433B97C01009709F45AC008170C -:10B2A000190708F056C01D86AC01401B510B4D30EC -:10B2B000510510F04CE050E0B801CE0101960F941A -:10B2C0005CB9CE0101965C018C01F80181918F017E -:10B2D000882319F00E946EADF8CF8AE00E946EAD0F -:10B2E0006091EF167091F01621E0AE014F5F5F4F55 -:10B2F000C6010E9491E5811126C0E0E0FDE5849140 -:10B300008F01882339F00E946EAD0F5F1F4FF80147 -:10B310008491F7CFF50181915F01882319F00E9494 -:10B320006EADF8CFEEEFFCE584918F01882339F004 -:10B330000E946EAD0F5F1F4FF8018491F7CF8AE036 -:10B340000E946EAD06C0D092F016C092EF16870133 -:10B3500096CF2D960FB6F894DEBF0FBECDBFDF910E -:10B36000CF911F910F91FF90EF90DF90CF90BF9002 -:10B37000AF9008952F923F924F925F926F927F927B -:10B380008F929F92AF92BF92CF92DF92EF92FF92F5 -:10B390000F931F93CF93DF9300D000D0CDB7DEB7CC -:10B3A000D62E7E838D83C92E49015A01270138018B -:10B3B00080914D11882309F463C020913D11309193 -:10B3C0003E1140913F11509140118D810F94F5A78E -:10B3D00069837A838B839C83209141113091421140 -:10B3E0004091431150914411C501B4010F94F5A748 -:10B3F0009B01AC0169817A818B819C810F94EFB3B1 -:10B4000020913511309136114091371150913811FA -:10B410000F94EFB3262E072F182F392E20914511A8 -:10B420003091461140914711509148116D2D7E8108 -:10B430008D819C2D0F94F5A76B017C012091491102 -:10B4400030914A1140914B1150914C11C501B401FA -:10B450000F94F5A79B01AC01C701B6010F94EFB3A0 -:10B460002091391130913A1140913B1150913C118A -:10B470000F94EFB34B015C01D22C0E831D83C32CC0 -:10B4800020917D1030917E1040917F10509180105E -:10B490006D2D7E818D819C2D0F94F5A70F94E7B6BD -:10B4A0006093691070936A1080936B1090936C1086 -:10B4B000209181103091821040918310509184101E -:10B4C000C501B4010F94F5A70F94E7B660936D1012 -:10B4D00070936E1080936F109093701080918C1504 -:10B4E0008823A9F0A50194016D2D7E818D819C2D6D -:10B4F0000F948E77A30192010F94EFB320918510E2 -:10B500003091861040918710509188100AC0209188 -:10B510008510309186104091871050918810C3019A -:10B52000B2010F94F5A70F94E7B660937110709372 -:10B5300072108093731090937410809141109091C9 -:10B540004210A0914310B091441089839A83AB8339 -:10B55000BC832091891030918A1040918B105091BA -:10B560008C10BC01CD010F94F5A70F94E7B6609342 -:10B5700075107093761080937710909378108D2DBE -:10B580009E81AD81BC2D8093591090935A10A09349 -:10B590005B10B0935C1080925D1090925E10A09250 -:10B5A0005F10B092601040926110509262106092F1 -:10B5B00063107092641089819A81AB81BC81809301 -:10B5C000651090936610A0936710B09368108FB7C2 -:10B5D000F8944091691050916A1060916B107091CD -:10B5E0006C10409325105093261060932710709391 -:10B5F000281040916D1050916E1060916F107091F5 -:10B6000070104093291050932A1060932B10709360 -:10B610002C104091711050917210609173107091C4 -:10B62000741040932D1050932E1060932F10709330 -:10B630003010409175105091761060917710709194 -:10B640007810409331105093321060933310709300 -:10B6500034108FBF10925510109256101092571040 -:10B6600010925810109245101092461010924710E8 -:10B67000109248101092491010924A1010924B10DC -:10B6800010924C1010924D1010924E1010924F10BC -:10B69000109250101092511010925210109253109C -:10B6A0001092541026960FB6F894DEBF0FBECDBF91 -:10B6B000DF91CF911F910F91FF90EF90DF90CF908E -:10B6C000BF90AF909F908F907F906F905F904F90C2 -:10B6D0003F902F9008952F923F924F925F926F92DA -:10B6E0007F928F929F92AF92BF92CF92DF92EF9212 -:10B6F000FF920F931F93CF93DF93CDB7DEB72997B8 -:10B700000FB6F894DEBF0FBECDBF782E6E3198F025 -:10B71000693C08F068EC70E068517C4F80E090E094 -:10B720000F948CAE20E030E04AE754E40F94DDB48F -:10B730001B012C0103C0212C312C210180911D0300 -:10B7400090911E03A0911F03B091200389839A83D7 -:10B75000AB83BC838091210390912203A0912303AA -:10B760008D839E83AF8320E030E047EF50E069EEA9 -:10B77000872D0E9494C6812C912C540110E0FF2447 -:10B78000F39400E0612CC12CD12C96012F7133274A -:10B7900039872887232B19F4812C912C540120E020 -:10B7A00030E0A901C201B1010F9488AEA6010D2CB1 -:10B7B000000C660B770B81112AC0CB01BA010F94E4 -:10B7C0008EAE2BED3FE049EC50E40F94F5A72BED46 -:10B7D0003FE049E450E40F94EFB320E030E040E86C -:10B7E0005AE30F94F5A70F9468B720E030E048E7DC -:10B7F00053E40F94F5A720E030E040E05FE30F94BE -:10B80000EFB30F9454B5EE24EA94E60E25C0CB01B5 -:10B81000BA010F948EAE2BED3FE049EC50E40F944B -:10B82000F5A720E030E040E85AE30F94F5A70F9425 -:10B8300068B7A20191010F941AB720E030E047E702 -:10B8400053E40F94F5A720E030E040E05FE30F946D -:10B85000EFB30F9454B5E62E8E2D8619801709F498 -:10B860005FC08F1509F4BFC080174CF5882379F0AD -:10B870008130C9F08F3F09F056C0E2E0F0E0EC0FF4 -:10B88000FD1FE10FF11D1082F12C0FEF41C0E2E02E -:10B89000F0E0EC0FFD1FE10FF11D31E03083FF24DC -:10B8A000F39400E035C0E2E0F0E0EC0FFD1FE10FA3 -:10B8B000F11D82E08083E2E0FE2E01E029C0F8164F -:10B8C00094F5823079F08330C1F0813061F5E2E0A7 -:10B8D000F0E0EC0FFD1FE10FF11D8083FF24F394D6 -:10B8E00000E079C0E2E0F0E0EC0FFD1FE10FF11D98 -:10B8F000808372E0F72E01E06EC0E2E0F0E0EC0F32 -:10B90000FD1FE10FF11D808363E0F62E02E063C0AE -:10B91000E5E0F0E0EC0FFD1FE10FF11DC0821F5FBD -:10B92000143008F465C02A81822F90E0A0E0B0E0D6 -:10B93000AC01BD0182E0440F551F661F771F8A9539 -:10B94000D1F79B81892F90E0A0E0B0E024E0880F40 -:10B95000991FAA1FBB1F2A95D1F7482B592B6A2B79 -:10B960007B2B89818A019B01082BD901C8012C817D -:10B97000422F50E060E070E036E0440F551F661F34 -:10B98000771F3A95D1F7482B592B6A2B7B2B8D814A -:10B99000582B8E81682B8F819A01AB01582B68EE52 -:10B9A000872D29960FB6F894DEBF0FBECDBFDF916D -:10B9B000CF911F910F91FF90EF90DF90CF90BF90AC -:10B9C000AF909F908F907F906F905F904F903F903F -:10B9D0002F900C9494C6E5E0F0E0EC0FFD1FE10F12 -:10B9E000F11DC0821F5F143008F09DCF6894B7F836 -:10B9F000288539852F31310571F4B60155E07595EB -:10BA000067955A95E1F7605A6068A5019401872D02 -:10BA10000E9494C604C0B694A794979487943FEF6D -:10BA2000C31AD30AC11481E0D80609F47CCF6E2C66 -:10BA3000ACCE8F929F92AF92BF92CF92DF92EF9255 -:10BA4000FF920F931F93CF93C82F8A01C62ED12C3C -:10BA50001F934F9383E08F9388EE8F931F9282E022 -:10BA60008F931F926F931F92CF938EED9CE59F93C0 -:10BA70008F930F9493AD8DB79EB70C960FB6F89435 -:10BA80009EBF0FBE8DBF80E090E040E051E0282FC8 -:10BA9000BA01082E02C0769567950A94E2F7061758 -:10BAA000170729F001968830910589F728E0E22EE2 -:10BAB000F12C88E090E08E199F0924E030E05901D4 -:10BAC00002C0AA0CBB1C8A95E2F78C2F0E94C8C644 -:10BAD0009C01C43030F4EC2FF0E0EC5DFC4F908121 -:10BAE00001C090E00E2C02C0369527950A94E2F72B -:10BAF0008601021B130B61E017FD04C0992341F07E -:10BB000060E006C0911101C060E011950195110936 -:10BB1000C501969587958017910734F481E06827D1 -:10BB2000C501801B910B8C018C2F0E94F8C58BE8FE -:10BB300091E00197F1F78C2F0E94C8C6A12CB12C7F -:10BB40002BE9822E2FE0922E0A151B05B1F02FEF64 -:10BB5000A21AB20A0E2C02C0969587950A94E2F7B3 -:10BB60008C159D0551F08C2F0E94DFC5C4010197F3 -:10BB7000F1F78C2F0E94C8C6E7CFCF911F910F918C -:10BB8000FF90EF90DF90CF90BF90AF909F908F90FD -:10BB9000089560913D1070913E1080913F109091FA -:10BBA00040106093611070936210809363109093C3 -:10BBB000641020918510309186104091871050912B -:10BBC00088100F94F5A70F94E7B6E9E6F0E16087D7 -:10BBD0007187828793878FB7F89440815181628102 -:10BBE0007381A5E2B0E14D935D936D937C931397C0 -:10BBF000448155816681778114964D935D936D9351 -:10BC00007C931797408551856285738518964D936F -:10BC10005D936D937C931B974485558566857785E9 -:10BC20001C964D935D936D937C931F978FBF0895E2 -:10BC30008F929F92AF92BF92CF92DF92EF92FF923C -:10BC40001F93CF93DF93EC0180918402843521F020 -:10BC50008F3F09F0BEC204C0EDEDFCE51491D3C0E6 -:10BC600084E580938402EDEDFCE514911F3F09F417 -:10BC7000B0C2123009F466C028F5112309F449C096 -:10BC8000113009F0C0C010928000109281008091A4 -:10BC90008100886080938100809181008160809321 -:10BCA0008100EBEDFCE5E491F0E0EE0FFF1FE359BE -:10BCB000F34A85919491EBE6FCE5E491E0935C1303 -:10BCC00011E046C1143009F47FC008F45EC015309D -:10BCD00009F099C010922001109221018091210158 -:10BCE00088608093210180912101816080932101EE -:10BCF000EBEDFCE5E491F0E0EE0FFF1FE359F34AB2 -:10BD000085919491EBE6FCE5E491E093591315E0FD -:10BD10001FC114BC15BC84B5826084BD85B581602B -:10BD200085BDEBEDFCE5E491F0E0EE0FFF1FE3597C -:10BD3000F34A85919491EBE6FCE5E491E0935D1381 -:10BD400010E042C21092B0001092B1008091B00099 -:10BD500082608093B0008091B10081608093B100D7 -:10BD6000EBEDFCE5E491F0E0EE0FFF1FE359F34A41 -:10BD7000859194919093201080931F10EBE6FCE541 -:10BD8000E491E0931E1012E01FC2109290001092F6 -:10BD90009100809191008860809391008091910042 -:10BDA000816080939100EBEDFCE5E491F0E0EE0F13 -:10BDB000FF1FE359F34A85919491EBE6FCE5E4918A -:10BDC000E0935B1313E0C4C01092A0001092A10096 -:10BDD0008091A10088608093A1008091A100816082 -:10BDE0008093A100EBEDFCE5E491F0E0EE0FFF1F86 -:10BDF000E359F34A85919491EBE6FCE5E491E093F5 -:10BE00005A1314E0A5C017FDE4C161E084E50F9466 -:10BE10000A86812F8D7F09F09FC06E01E12CF12CE5 -:10BE200060E072E18AE790E0A70196010F94B4B850 -:10BE300049015A01BA01A901415051096109710929 -:10BE40004F3F51056105710509F008F445C060E4F4 -:10BE500072E48FE090E0A70196010F94B4B8BA01A4 -:10BE6000A90141505109610971091230E9F44F3FAC -:10BE700051056105710509F008F446C160E970EDEE -:10BE800083E090E0A70196010F94B4B8BA01A9012C -:10BE900041505109610971094F3F51056105710513 -:10BEA00009F020F583E04DC04F3F51056105710554 -:10BEB000A9F0A0F068E478EE81E090E0A701960197 -:10BEC0000F94B4B8BA01A90141505109610971092F -:10BED000112309F41BC170C181E001C082E011117E -:10BEE00030C095B5987F892B85BD93C068E478EE06 -:10BEF00081E090E0A70196010F94B4B8BA01A901BE -:10BF000041505109610971094F3F510561057105A2 -:10BF100009F008F4F7C064E274EF80E090E0A70154 -:10BF200096010F94B4B8BA01A901415051096109B1 -:10BF300071094F3F51056105710511F008F015C1F8 -:10BF400085E09091B100987F892B8093B10050C01B -:10BF500061E084E50F940A866E01E12CF12C60E02B -:10BF600072E18AE790E0A70196010F94B4B8BA0194 -:10BF7000A90141505109610971094115510581E03B -:10BF80006807710580F068E478EE81E090E0A70131 -:10BF900096010F94B4B8BA01A90141505109610941 -:10BFA000710983E001C081E0113039F49091810082 -:10BFB000987F892B809381003EC0133039F4909193 -:10BFC0009100987F892B809391005DC0143039F4E3 -:10BFD0009091A100987F892B8093A10069C01530B2 -:10BFE00039F490912101987F892B8093210175C0AC -:10BFF0001230B1F134F4112361F0113009F0E9C0CD -:10C000001AC0143009F454C0F4F1153009F465C0B5 -:10C01000E0C047BD8FEF9FEFDC0180936E139093DC -:10C020006F13A0937013B093711380916E008260B0 -:10C0300080936E00CEC050938900409388008FEFAC -:10C040009FEFDC0180936A1390936B13A0936C13A2 -:10C05000B0936D1380916F00826080936F00B9C0C0 -:10C060004093B3008FEF9FEFDC01809321109093FA -:10C070002210A0932310B09324108091700082604E -:10C0800080937000A6C050939900409398008FEF62 -:10C090009FEFDC018093661390936713A09368135E -:10C0A000B09369138091710082608093710091C098 -:10C0B0005093A9004093A8008FEF9FEFDC0180937D -:10C0C000621390936313A0936413B09365138091EC -:10C0D00072008260809372007CC05093290140936B -:10C0E00028018FEF9FEFDC0180935E1390935F1325 -:10C0F000A0936013B093611380917300826080936A -:10C10000730067C084E01DCF82E01BCF4F3F510515 -:10C110006105710541F138F162E17AE780E090E074 -:10C12000A70196010F94B4B8BA01A9014150510971 -:10C13000610971094F3F51056105710591F088F062 -:10C14000D501C4013AE0B595A795979587953A959D -:10C15000D1F7AC01BD01415051096109710985E078 -:10C16000C0CE84E0BECE83E0BCCE62E17AE780E060 -:10C1700090E0A70196010F94B4B8BA01A90141500B -:10C180005109610971094F3F51056105710591F030 -:10C1900088F0D501C4012AE0B595A79597958795B4 -:10C1A0002A95D1F7AC01BD014150510961097109CE -:10C1B00087E0C7CE86E0C5CE4F3F510561057105CA -:10C1C00009F098F684E08BCE61E084E50F940A864E -:10C1D00024CEDF91CF911F91FF90EF90DF90CF9011 -:10C1E000BF90AF909F908F90089510928C158CE81F -:10C1F00095E120E030E0FC01E20FF31F1182128292 -:10C20000138214822C5F3F4F2C313105A1F74C96DD -:10C2100026E18035920769F708952F923F924F9259 -:10C220005F926F927F928F929F92AF92BF92CF92C6 -:10C23000DF92EF92FF920F931F93CF93DF93CDB7CF -:10C24000DEB72C970FB6F894DEBF0FBECDBF8CE8DB -:10C25000282E85E1382E38862F82EF81F88581855A -:10C260009285A385B485818F928FA38FB48F8581AA -:10C270009681A781B08585879687A787B08BFA833B -:10C28000E98301E010E00330110509F487C0B8012B -:10C29000012E000C880B990B0F948EAE25E535E529 -:10C2A00047E052E40F94F5A720E030E04CE052E480 -:10C2B0000F94EFB36B017C0120E030E848E053E4D9 -:10C2C0000F94EEB32B013C0120E030E04EE653E446 -:10C2D000C701B6010F94EEB34B015C0120E030E0E2 -:10C2E0004CE052E4C701B6010F94EEB36B017C0140 -:10C2F000EF81F8852181328143815481C301B201EC -:10C300000F94F5A7A50194010F94F5A720E039EF4C -:10C3100040EA56E40F94DDB46B837C838D839E8367 -:10C32000EF81F8852585368547855089C701B60197 -:10C330000F94F5A7A50194010F94F5A720E039EF1C -:10C3400040E256EC0F94DDB49B01AC016B817C8123 -:10C350008D819E810F94EFB34B015C01EF81F885D5 -:10C36000218D328D438D548DC701B6010F94F5A7F1 -:10C37000A30192010F94F5A720E039EF40EA56E4BB -:10C380000F94DDB49B01AC01C501B4010F94EFB370 -:10C39000E981FA8165837683878390870F5F1F4FDA -:10C3A00029813A812C5F3F4F3A832983063011055A -:10C3B00009F069CF8F8198854C9698878F83805E2E -:10C3C000954109F04ACF25EC35E13A832983E9818B -:10C3D000FA8181919191A191B191FA83E9839101BF -:10C3E00027553F4F3C832B83F90180839183A283A0 -:10C3F000B383F101858D968DA78DB0A1E981FA8176 -:10C40000808F918FA28FB38F810121E030E03C8734 -:10C410002B878B859C858330910509F484C0BC01F2 -:10C42000990F880B990B0F948EAE2BEA3AEA42E0F3 -:10C4300052E40F94F5A720E030E040EC50E40F9474 -:10C44000EFB36B017C0120E030E040ED52E40F944B -:10C45000EEB32B013C0120E030E04AE453E4C70195 -:10C46000B6010F94EEB34B015C0120E030E040ECEC -:10C4700050E4C701B6010F94EEB36B017C01F101EA -:10C480002181328143815481C301B2010F94F5A708 -:10C49000A50194010F94F5A720E030E146E956E4A8 -:10C4A0000F94DDB46F83788789879A87E981FA8151 -:10C4B000208D318D428D538DC701B6010F94F5A7A4 -:10C4C000A50194010F94F5A720E030E146E156EC78 -:10C4D0000F94DDB49B01AC016F81788589859A85C5 -:10C4E0000F94EFB34B015C01EB81FC812081318122 -:10C4F00042815381C701B6010F94F5A7A3019201B0 -:10C500000F94F5A720E030E146E956E40F94DDB43E -:10C510009B01AC01C501B4010F94EFB3F801658F25 -:10C52000768F878F90A32B853C852F5F3F4F3C876D -:10C530002B87045E1F4F2630310509F06ACF34E0A7 -:10C54000230E311C88EA281685E1380609F03FCF12 -:10C550002C960FB6F894DEBF0FBECDBFDF91CF9102 -:10C560001F910F91FF90EF90DF90CF90BF90AF9011 -:10C570009F908F907F906F905F904F903F902F9003 -:10C5800008952F923F924F925F926F927F928F9277 -:10C590009F92AF92BF92CF92DF92EF92FF920F9352 -:10C5A0001F93CF93DF93CDB7DEB76C970FB6F89498 -:10C5B000DEBF0FBECDBF6C015B014A0119011887B8 -:10C5C0000F83FA82E982E114F10451F0D7018D91D1 -:10C5D0009C9160ED72E00F948DB89C8F8B8F02C0A0 -:10C5E0001C8E1B8EBC8DBF93EB8DEF933F922F92D1 -:10C5F0001F9284E68F939F928F92BF92AF92DF92A9 -:10C60000CF928FED9BE59F938F930F9493AD0FB6D1 -:10C61000F894DEBF0FBECDBF8827992782199309F2 -:10C620009E878D87C401990CAA0BBB0B8F87988BB3 -:10C63000A98BBA8BC501BB0CAA0BBB0B8B8B9C8B3C -:10C64000AD8BBE8BC601DD0CAA0BBB0B8F8B988FFD -:10C65000A98FBA8F1214130464F48B8D9C8D6CE334 -:10C6600070E00F948DB810E1161B2B8D3C8DD1011D -:10C670000FC02FEC32E0AB8DBC8D2A1B3B0BC901E8 -:10C680006CE370E00F948DB810E1161BAD85BE858C -:10C690000F94DEB80F948CAE20E030E044E354E415 -:10C6A0000F94DDB42B013C016F817885EB8DFC8DFF -:10C6B0006E0F7F1F80E090E00F948CAE2BED3FE07B -:10C6C00049E450E40F94F5A720E030E044E353E45C -:10C6D0000F94DDB46B017C010F94DAB46B837C831F -:10C6E0008D839E83C701B6010F9468B74B015C012F -:10C6F0006F85788989899A890F948EAE6B017C0148 -:10C700002B8D3C8DA4E6B0E00F94DFB30F948EAE7A -:10C7100020E030E044E354E40F94DDB49B01AC012D -:10C72000C701B6010F94EEB30F944EB569877A87AF -:10C730008B879C876B897C898D899E890F948EAEAF -:10C740006B017C01A3019201C501B4010F94F5A70F -:10C750009B01AC01C701B6010F94EFB30F944EB526 -:10C760006B017C016F89788D898D9A8D0F948EAEC7 -:10C770004B015C01A30192016B817C818D819E81C3 -:10C780000F94F5A79B01AC01C501B4010F94EFB361 -:10C790000F944EB5DC01CB0101E020E431E0498586 -:10C7A0005A85B6010F94F54D212F30E0882349F0CA -:10C7B0008B8D9C8D0196820F931F9C8F8B8F81E0B8 -:10C7C0000DC02F5F3F4FAB8DBC8DA20FB31FBC8F31 -:10C7D000AB8FA03DB24008F43DCF80E029813A8183 -:10C7E0002115310529F0EB8DFC8DD901ED93FC93DA -:10C7F0006C960FB6F894DEBF0FBECDBFDF91CF9120 -:10C800001F910F91FF90EF90DF90CF90BF90AF906E -:10C810009F908F907F906F905F904F903F902F9060 -:10C8200008958F929F92AF92BF92CF92DF92EF9234 -:10C83000FF920F931F93CF93DF93CDB7DEB7279768 -:10C840000FB6F894DEBF0FBECDBF6C01E3ECFBE585 -:10C85000849180538A3010F43196FACF84918E32CD -:10C8600009F001C17F018FEFE81AF80AF7019491EE -:10C8700090539A3010F43196FACF84918E3209F0A9 -:10C88000F2C05F01AFEFAA1ABA0A8501F8019491CC -:10C8900090539A3018F40F5F1F4FF8CFF80184912E -:10C8A0000F94C451811105C0F80184918D3209F0B3 -:10C8B000DAC0C701835C9B458150853008F0D3C046 -:10C8C000882E912CA40163EC7BE5CE0101960F9498 -:10C8D0002AACE1E0F0E0EC0FFD1FE80DF91D10823D -:10C8E0001F821E824AE050E0BE016A5F7F4FCE0188 -:10C8F00001960F941DAAD6016D937C93EE81FF8162 -:10C9000080818111B0C045018E189F088FEF880D7E -:10C91000853008F0A8C0882E912CA401B701CE0163 -:10C9200001960F942AACE1E0F0E0EC0FFD1FE80D5A -:10C93000F91D10824AE050E0BE016A5F7F4FCE01D0 -:10C9400001960F941DAAF60173836283EE81FF8125 -:10C950008081811188C0C8018A199B09853008F03F -:10C9600082C07C01FF24A701B501CE0101960F947E -:10C970002AACE1E0F0E0EC0FFD1FEE0DFF1D108290 -:10C980004AE050E0BE016A5F7F4FCE0101960F94EE -:10C990001DAAD60115967C936E931497EE81FF81A4 -:10C9A0008081811160C08FE790E017969C938E93F1 -:10C9B0001697F80184918D3221F54801FFEF8F1A07 -:10C9C0009F0A7401F70184910F94C451B82E81110C -:10C9D00004C0FFEFEF1AFF0AF5CFE818F908AE2CF4 -:10C9E000C70199278330910579F44E2D6BED7BE5D6 -:10C9F000C4010F94A6A681112AC0F60117821682DF -:10CA000048C0BB24B39445C08530910581F44E2DB8 -:10CA100065ED7BE5C4010F94A6A6811118C081E0E5 -:10CA200090E0D60117969C938E93169732C0049788 -:10CA300071F44E2D60ED7BE5C4010F94A6A6811123 -:10CA400006C082E090E0F6019783868322C08EEFD5 -:10CA50008E0D823040F442E06DEC7BE5C4010F9412 -:10CA6000A6A6882311F0B12C14C0F2E0AF1203C0C7 -:10CA700083E090E0D6CFF8013396849180538A30DA -:10CA800090F7E491F0E0BE97D6011796FC93EE93F1 -:10CA900016978B2D27960FB6F894DEBF0FBECDBF2D -:10CAA000DF91CF911F910F91FF90EF90DF90CF908A -:10CAB000BF90AF909F908F9008958F929F92AF926A -:10CAC000BF92CF92DF92EF92FF920F931F93CF937B -:10CAD000DF9382E69DE59F938F930F9493AD0F9024 -:10CAE0000F9080917B138823E9F190912C0EC92F30 -:10CAF000D0E080E2890F853268F01F929F9387E42F -:10CB00009DE59F938F930F9493AD0F900F900F908F -:10CB10000F9023C00F946A2480E00F9427370F945E -:10CB20001D3761E080E00F946E3282EC91E30F9448 -:10CB3000953189E596E00F941031BE016F5F7F4F0C -:10CB4000072E000C880B990B0F94F53060E080E005 -:10CB50000F945B2181E00F94273780912C0E8093F6 -:10CB60002D0EDDC0159882E090E09093410E8093E9 -:10CB7000400E82EC91E30F94EE5120E030E040E271 -:10CB800052E4609141107091421080914310909155 -:10CB900044100F94EFB36093411070934210809350 -:10CBA000431090934410E0903D10F0903E1000919F -:10CBB0003F10109140102091391030913A1040915F -:10CBC0003B1050913C10609135107091361080915F -:10CBD000371090913810EEEFFCE0FF93EF93812C2B -:10CBE000912CA0ECAA2EA0E4BA2EB1E4CB2EB0E199 -:10CBF000DB2E0E9451870F949883C0903D10D090F7 -:10CC00003E10E0903F10F09040100F900F9020E009 -:10CC100030E040EA51E4C701B6010F9488AE87FFC7 -:10CC200010C020E030E040EF51E4C701B6010F949E -:10CC3000EFB360933D1070933E1080933F1090933C -:10CC4000401020E030E040EF51E4609141107091DD -:10CC5000421080914310909144100F94EFB3609371 -:10CC60004110709342108093431090934410E090D1 -:10CC70003D10F0903E1000913F1010914010209117 -:10CC8000391030913A1040913B1050913C10609116 -:10CC90003510709136108091371090913810EEEF6A -:10CCA000FCE0FF93EF93812C912CE0ECAE2EE0E4BE -:10CCB000BE2EF1E4CF2EF0E1DF2E0E9451870E94BC -:10CCC0006EEA0F9498830F900F90809101079091D6 -:10CCD0000207029720F484EF91E00F94185E82E33C -:10CCE00090E00F94BD1284E50F94524D8091C80FCF -:10CCF000811105C08091760E81110E9424FF81E090 -:10CD00000F94273782E00F94932F8FEB94E10F94C9 -:10CD1000EE511092760E1092410E1092400EDF915D -:10CD2000CF911F910F91FF90EF90DF90CF90BF9028 -:10CD3000AF909F908F900895CF93DF93D82F8FEF70 -:10CD40009FE00F9463B3C82F8130B1F40F949883A0 -:10CD5000F894CD27C09318070E94B9BD0F948B3863 -:10CD6000B19A109285001092840080ED97E0909324 -:10CD70008900809388007894DF91CF91089588EBA3 -:10CD800091E00F94185E69E170E080E090E00F940C -:10CD90000D8784E50F94524D64E170E080E090E0EF -:10CDA0000D940D870F9425886093FF0E7093000FEC -:10CDB0008093010F9093020F08952F923F924F920C -:10CDC0005F926F927F928F929F92AF92BF92CF921B -:10CDD000DF92EF92FF920F931F93CF93DF93CDB724 -:10CDE000DEB768970FB6F894DEBF0FBECDBF988F41 -:10CDF0008F8B688B5B8B4A8B209121022E8B41E0BD -:10CE0000409321028230910508F057C3FC01EC5B8E -:10CE1000F24A54915987852F082E000C990B9D8B4F -:10CE20008C8BAF89B88DAA0FBB1FAA0FBB1FBE8307 -:10CE3000AD83FD01EF52FD4F80819181A281B381CD -:10CE40008A879B87AC87BD8780937E0290937F0201 -:10CE5000A0938002B093810281E00F8801C0880F07 -:10CE60000A94EAF70F94FF37AD81BE81AB5CBF4EE9 -:10CE7000B887AF83FD011082118212821382E09085 -:10CE80003D10F0903E1000913F1010914010209105 -:10CE9000391030913A1040913B1050913C10609104 -:10CEA00035107091361080913710909138100F9492 -:10CEB000BA590E940AA6F9856F2FFF0F770B880BCE -:10CEC000990B0F948EAE2B013C014D815E8147532F -:10CED000504F5A83498320E030E040E450EC0F94F7 -:10CEE000F5A7A981BA816D937D938D939C93139738 -:10CEF00020E030E040E752E460917E0270917F02D2 -:10CF000080918002909181020F94DDB44B015C010D -:10CF1000E090D10FF090D20F0091D30F1091D40F69 -:10CF20002091CD0F3091CE0F4091CF0F5091D00F67 -:10CF30006091C90F7091CA0F8091CB0F9091CC0F67 -:10CF4000EEEF2E2EECE03E2E3F922F92F5EDCF2EFF -:10CF5000FFE0DF2E0E9451870F9498830E94D2BC7D -:10CF600010922102EF81F8851082118212821382C1 -:10CF7000E0903D10F0903E1000913F101091401055 -:10CF80002091391030913A1040913B1050913C1053 -:10CF90006091351070913610809137109091381053 -:10CFA0000F94BA59A981BA814D925D926D927C928B -:10CFB000139720E030E040E752E460917E027091E8 -:10CFC0007F0280918002909181020F94DDB44B0129 -:10CFD0005C01E090D10FF090D20F0091D30F10912F -:10CFE000D40F2091CD0F3091CE0F4091CF0F5091A3 -:10CFF000D00F6091C90F7091CA0F8091CB0F9091A3 -:10D00000CC0F3F922F920E9451870F949883B1E0EA -:10D01000B0932102ED81FE81E85CF24A8590959003 -:10D02000A590B4902DEC3CEC4CE85FE3C301B20159 -:10D030000F94F5A7A50194010F94F5A7E981FA8152 -:10D04000608371838283938320E030E040E752E481 -:10D0500060917E0270917F028091800290918102A6 -:10D060000F94DDB44B015C01E090D10FF090D20F32 -:10D070000091D30F1091D40F2091CD0F3091CE0F8E -:10D080004091CF0F5091D00F6091C90F7091CA0F8E -:10D090008091CB0F9091CC0F3F922F920E9451879D -:10D0A0000F9498834A895B895F874E879889892F77 -:10D0B00090E0998B888B0F900F900F900F900F90AE -:10D0C0000F90212C312CA889B9892A163B0609F426 -:10D0D000DEC00E94D2BC10922102EF81F88510823E -:10D0E000118212821382E0903D10F0903E10009168 -:10D0F0003F10109140102091391030913A1040911A -:10D100003B1050913C106091351070913610809119 -:10D110003710909138100F94BA5920E030E040E277 -:10D1200051ECC301B2010F94F5A7A981BA816D93A7 -:10D130007D938D939C93139720E030E040E752E479 -:10D1400060917E0270917F028091800290918102B5 -:10D150000F94DDB44B015C01E090D10FF090D20F41 -:10D160000091D30F1091D40F2091CD0F3091CE0F9D -:10D170004091CF0F5091D00F6091C90F7091CA0F9D -:10D180008091CB0F9091CC0FEEEFFCE0FF93EF93EB -:10D19000B5EDCB2EBFE0DB2E0E9451870F94988314 -:10D1A0000E94D2BCB1E0B093210220E030E040E325 -:10D1B00051E4C301B2010F94F5A7E981FA816083BC -:10D1C0007183828393838A859B85AC85BD8580939B -:10D1D0007E0290937F02A0938002B093810220E0B0 -:10D1E00030E040E752E4BC01CD010F94DDB44B01C7 -:10D1F0005C01E090D10FF090D20F0091D30F10910D -:10D20000D40F2091CD0F3091CE0F4091CF0F509180 -:10D21000D00F6091C90F7091CA0F8091CB0F909180 -:10D22000CC0FAEEFBCE0BF93AF930E9451870F9439 -:10D2300098838F890E94C8C60F900F900F900F900F -:10D240009C0114E0369527951A95E1F74A895B8988 -:10D25000452B19F0AE85BF852C939F938F933F93F9 -:10D260002F933F922F92E0E2FDE5FF93EF930F940F -:10D2700093AD4FEF241A340A8E859F8501969F87C0 -:10D280008E870FB6F894DEBF0FBECDBF1CCF0E94B5 -:10D29000D2BC1092210280910C078823B1F1EF8952 -:10D2A000F88DE35FF84F6081603478F5EF89F88D91 -:10D2B000E15FFD4F0081BF8840E051E0EF89F88DCC -:10D2C000E05FF84F008002C0569547950A94E2F758 -:10D2D0008B2D0F94195D002391F110E06985619504 -:10D2E0008F890E94F8C58BE891E00197F1F7ABE9CF -:10D2F000EA2EAFE0FA2E8B2D0E94DFC5C701019701 -:10D30000F1F701501109B9F71AC0BF886985619515 -:10D310008B2D0E94F8C58BE891E00197F1F709E0A9 -:10D3200010E0FBE9EF2EFFE0FF2E0150110939F06C -:10D330008B2D0E94DFC5C7010197F1F7F6CF0F943F -:10D3400064378F89988D0E9449A7EF89F88DE15045 -:10D35000F34F81E080836C897D89719561957109B6 -:10D36000072E000C880B990B0F948EAE2AE037ED38 -:10D3700043E25CE30F94F5A74B015C01EF89F88D64 -:10D38000E35FFD4F608170E080E090E00F948EAE2F -:10D390009B01AC01C501B4010F94F5A74B015C01E1 -:10D3A0004D815E814B5C5F4E5A8349839B01AC018A -:10D3B000A981BA816D917D918D919C910F94EEB36D -:10D3C000E981FA816083718382839383E0903D10C9 -:10D3D000F0903E1000913F101091401020913910B4 -:10D3E00030913A1040913B1050913C1060913510B3 -:10D3F0007091361080913710909138100F94BA596F -:10D40000A981BA812D913D914D915C91C501B401E5 -:10D410000F94EFB3E981FA816083718382839383F0 -:10D42000ED81FE81E753F04F6083718382839383A4 -:10D4300020E030E040E05FE360917E0270917F0287 -:10D4400080918002909181020F94F5A720E030E056 -:10D4500040E752E40F94DDB44B015C01E090D10F42 -:10D46000F090D20F0091D30F1091D40F2091CD0FD7 -:10D470003091CE0F4091CF0F5091D00F6091C90FD6 -:10D480007091CA0F8091CB0F9091CC0FEEEFFCE022 -:10D49000FF93EF93E5EDCE2EEFE0DE2E0E94518755 -:10D4A0000F94988310927E0210927F021092800255 -:10D4B000109281020F900F9059C14F89588D4230C0 -:10D4C000510509F053C181E037DCE6E4FDE55491F4 -:10D4D000598310923D1010923E1010923F101092FE -:10D4E00040102091391030913A1040913B105091EA -:10D4F0003C106091351070913610809137109091EA -:10D500003810E12CF12C87010F94BA59E0E4FDE5C5 -:10D5100085909590A590B490A9816A2FAA0F770B5A -:10D52000880B990B0F948EAE2B013C0120E030E06C -:10D5300040EC5FE3C501B4010F94F5A7A30192018C -:10D540000F94F5A77B018C016093D10F7093D20FDC -:10D550008093D30F9093D40F80E090E0A8E4B4E4DC -:10D5600080937E0290937F02A0938002B093810209 -:10D570002091CD0F3091CE0F4091CF0F5091D00F11 -:10D580006091C90F7091CA0F8091CB0F9091CC0F11 -:10D59000EEEFFCE0FF93EF93A5E58A2E982CA82CE4 -:10D5A000A1E4BA2EB5EDCB2EBFE0DB2E0E94518751 -:10D5B0000F949883809106010F900F9086FDF2C022 -:10D5C00010923D1010923E1010923F101092401099 -:10D5D0002091391030913A1040913B1050913C10FD -:10D5E00060913510709136108091371090913810FD -:10D5F000E12CF12C87010F94BA598CE1282E8DE58E -:10D60000382EF10185919591A591B491BC01CD0180 -:10D610009058A30192010F94F5A769837A838B83B5 -:10D620009C836093D10F7093D20F8093D30F90930C -:10D63000D40F20E030E040E752E460917E02709128 -:10D640007F0280918002909181020F94DDB44B01A2 -:10D650005C012091CD0F3091CE0F4091CF0F5091B2 -:10D66000D00F6091C90F7091CA0F8091CB0F90912C -:10D67000CC0FEEEFFCE0FF93EF93E5EDCE2EEFE065 -:10D68000DE2EE980FA800B811C810E9451870F9465 -:10D690009883F10165917591859194919B01AC01FD -:10D6A0000F94EFB3A30192010F94F5A77B018C01B6 -:10D6B0006093D10F7093D20F8093D30F9093D40FB8 -:10D6C00080E090E0A8ECB3E480937E0290937F0228 -:10D6D000A0938002B09381022091CD0F3091CE0FA4 -:10D6E0004091CF0F5091D00F6091C90F7091CA0F28 -:10D6F0008091CB0F9091CC0FEEEFFCE0FF93EF9376 -:10D70000F5E58F2E982CF5EDAF2EF0E4BF2E0E949C -:10D7100051870F949883809106010F900F900F907E -:10D720000F9086FD3FC082E090E00E9449A7809163 -:10D730003D1090913E10A0913F10B0914010809309 -:10D74000D10F9093D20FA093D30FB093D40F109218 -:10D750007E0210927F0210928002109281020E943B -:10D76000D2BCB1E0B093010D80E0E6DABE89B0939F -:10D77000210268960FB6F894DEBF0FBECDBFDF91D1 -:10D78000CF911F910F91FF90EF90DF90CF90BF90BE -:10D79000AF909F908F907F906F905F904F903F9051 -:10D7A0002F90089580E0C8DA60E08FE593E50F944C -:10D7B0000A0E2F923F924F925F926F927F928F92BA -:10D7C0009F92AF92BF92CF92DF92EF92FF920F9310 -:10D7D0001F93CF93DF93CDB7DEB72D970FB6F89495 -:10D7E000DEBF0FBECDBF382E2A013B012A83EB825C -:10D7F000FC820D831E832C2C8F829886A986BA8684 -:10D800000F94988381E08093580E8A81381206C065 -:10D810003C1409F463C2C982132D02C0C9821A8163 -:10D82000032D0F94FB2C90918C159B8710928C15D7 -:10D8300082E00F94858360933D1070933E10809337 -:10D840003F1090934010A981A1110F94682A8091F4 -:10D850007E0290917F02A0918002B091810280931C -:10D86000721390937313A0937413B09375138091F4 -:10D870004302909144029D878C8784E690E09093C8 -:10D880004402809343020F9425886093FF0E7093A7 -:10D89000000F8093010F9093020F81E0809321028B -:10D8A00080E1E5E3F0E1A9ECBFE001900D928A95FB -:10D8B000E1F710927E0210927F0210928002109285 -:10D8C00081020023C1F09BA191110FC040E050E004 -:10D8D00061E080E090E071DA1123A9F040E050E0CF -:10D8E00061E081E090E069DA0EC080E00E94D3C47C -:10D8F000111106C008C0112331F0ABA1AA2371F3A6 -:10D9000081E00E94D3C43320E9F041145104610442 -:10D910007104C1F0C301B2010F948EAE9B01AC0142 -:10D920006091D1107091D2108091D3109091D41049 -:10D930000F94EFB3609335107093361080933710C7 -:10D9400090933810BA81BB2301F18B819C81AD810A -:10D95000BE810097A105B105C1F0BC01CD010F94B6 -:10D960008EAE9B01AC016091D5107091D610809164 -:10D97000D7109091D8100F94EFB360933910709333 -:10D980003A1080933B1090933C109981992309F4AD -:10D99000E6C08091FF0C882321F08091000D811159 -:10D9A0000CC040E050E061E080E090E006DA40E04A -:10D9B00050E061E081E090E000DA0F94EA2EEEEEB4 -:10D9C000FEE185919591A591B491EAEEFEE1459134 -:10D9D0005591659174914093C90F5093CA0F60930C -:10D9E000CB0F7093CC0F8093CD0F9093CE0FA0935D -:10D9F000CF0FB093D00F6DEC7FE089EC9FE00E94D9 -:10DA0000C3A70F94C32C20E030E040E850EC6091B5 -:10DA1000CD0F7091CE0F8091CF0F9091D00F0F94BA -:10DA200088AE87FF0CC080E090E0A0E8B0EC809367 -:10DA3000CD0F9093CE0FA093CF0FB093D00F80E077 -:10DA400090E0A0EAB0E48093D10F9093D20FA0931E -:10DA5000D30FB093D40F80E090E0A0EAB2E48093BB -:10DA60007E0290937F02A0938002B0938102109275 -:10DA70003D1010923E1010923F10109240101092E4 -:10DA800021022091391030913A1040913B10509171 -:10DA90003C10609135107091361080913710909144 -:10DAA0003810E12CF12C87010F94BA5980907E0236 -:10DAB00090907F02A0908002B0908102E090D10F00 -:10DAC000F090D20F0091D30F1091D40F2091CD0F71 -:10DAD0003091CE0F4091CF0F5091D00F6091C90F70 -:10DAE0007091CA0F8091CB0F9091CC0FEEEFFCE0BC -:10DAF000FF93EF93A5EDCA2EAFE0DA2E0E94518777 -:10DB00000F9498838091C90F9091CA0FA091CB0F69 -:10DB1000B091CC0F8093351090933610A0933710AE -:10DB2000B09338108091CD0F9091CE0FA091CF0F70 -:10DB3000B091D00F8093391090933A10A0933B107E -:10DB4000B0933C1081E0809321020E94D2BC40E05F -:10DB500050E061E082E090E030D90F900F902220F9 -:10DB600001F18F819885A985BA850097A105B10536 -:10DB7000C1F0BC01CD010F948EAE9B01AC01609150 -:10DB8000D9107091DA108091DB109091DC100F9415 -:10DB9000EFB360933D1070933E1080933F109093CD -:10DBA0004010E0903D10F0903E1000913F10109119 -:10DBB00040102091391030913A1040913B10509113 -:10DBC0003C10609135107091361080913710909113 -:10DBD00038100F94BA5910922102809172139091CB -:10DBE0007313A0917413B091751380937E02909378 -:10DBF0007F02A0938002B0938102AC85BD85B09373 -:10DC00004402A09343020F9425886093FF0E709303 -:10DC1000000F8093010F9093020F0E94D2BC0F94CB -:10DC2000EA2E0F94FD2A311008C0BA81B11105C047 -:10DC30008CA1811102C0222049F1898181112AC061 -:10DC40009B85992339F181E080938C150F9485830E -:10DC50002B013C0180E00F948583A30192010F9476 -:10DC60008E779B01AC0160913D1070913E108091C8 -:10DC70003F10909140100F94EEB360933D1070935D -:10DC80003E1080933F109093401004C00F949883EF -:10DC90001092580E8091C80F882329F060E084E12B -:10DCA00090E00F94BE021092580E2D960FB6F89485 -:10DCB000DEBF0FBECDBFDF91CF911F910F91FF90BF -:10DCC000EF90DF90CF90BF90AF909F908F907F901C -:10DCD0006F905F904F903F902F90089520E030E03C -:10DCE00040EA50E460913D1070913E1080913F10E9 -:10DCF000909140100F94EFB37B018C0160933D1025 -:10DD000070933E1080933F109093401080E090E01D -:10DD1000A8E4B4E480937E0290937F02A0938002F3 -:10DD2000B09381022091391030913A1040913B100C -:10DD300050913C10609135107091361080913710E1 -:10DD400090913810EEEFFCE0FF93EF93E5E58E2E17 -:10DD5000982CA82CE1E4BE2EF1E4CF2EF0E1DF2ECA -:10DD60000E9451870F9498830F900F90A1E0A98390 -:10DD700011E001E056CD8F929F92AF92BF92CF9269 -:10DD8000EF92FF920F931F93262F91E09F931F9284 -:10DD9000812C912C5401C42EE12CF12C870140E000 -:10DDA00050E0BA0106DD0F900F901F910F91FF9088 -:10DDB000EF90CF90BF90AF909F908F9008958F92EB -:10DDC0009F92AF92BF92CF92DF92EF92FF920F930A -:10DDD0001F93CF93DF9324E0829FC0011124EC01B5 -:10DDE000CB5CDF4E20E030E040E251E46881798195 -:10DDF0008A819B810F94EFB3688379838A839B83A5 -:10DE0000E0903D10F0903E1000913F1010914010B6 -:10DE10002091391030913A1040913B1050913C10B4 -:10DE200060913510709136108091371090913810B4 -:10DE3000EEEFFCE0FF93EF93812C912CE4E3AE2E08 -:10DE4000E2E4BE2EF1E4CF2EF0E1DF2E0E945187F6 -:10DE50000F94988389E69FE00F9463B30F900F901F -:10DE6000882319F081E080930C02DF91CF911F91FC -:10DE70000F91FF90EF90DF90CF90BF90AF909F9069 -:10DE80008F9008953F924F925F926F927F928F9200 -:10DE90009F92AF92BF92CF92DF92EF92FF920F9339 -:10DEA0001F93CF93DF93CDB7DEB76A970FB6F89481 -:10DEB000DEBF0FBECDBF382E882369F081E0381257 -:10DEC00005C080E090E8ACE5B3E409C080E090E0F4 -:10DED000A2E5B3E404C080E090E0AFE7B3E4898B4F -:10DEE0009A8BAB8BBC8B10920C020F94643781E041 -:10DEF00080932102311041C020E030E048E851E435 -:10DF000060913D1070913E1080913F1090914010B3 -:10DF10000F94EFB37B018C0160933D1070933E1022 -:10DF200080933F10909340102091391030913A1017 -:10DF300040913B1050913C1060913510709136101B -:10DF40008091371090913810EEEFFCE0FF93EF9343 -:10DF5000812C912CB4E3AB2EB2E4BB2EE1E4CE2EA7 -:10DF6000E0E1DE2E0E94518784E00F94FF370F948A -:10DF700098830F9464370F900F90032D10E020E0EA -:10DF800030E040E752E469897A898B899C890F9453 -:10DF9000EFB36F8B788F898F9A8F1A870987D80193 -:10DFA000AA0FBB1FAA0FBB1FBE8BAD8BAB5CBF4EB6 -:10DFB0003D019B01AC016D917D918D919C910F94E0 -:10DFC000EEB3F3016083718382839383E0903D100D -:10DFD000F0903E1000913F101091401020913910A8 -:10DFE00030913A1040913B1050913C1060913510A7 -:10DFF000709136108091371090913810EEEF4E2EC0 -:10E00000ECE05E2E5F924F92812C912CF4E3AF2EC8 -:10E01000F2E4BF2EA1E4CA2EA0E1DA2E0E945187BD -:10E020000F9498833092850210927C1310927D1386 -:10E0300010927E1310927F1310928013109281130E -:10E040001092821310928313832D0F9485836D8712 -:10E050007E878F87988B20E030E040EF52E4D30139 -:10E060006D917D918D919C910F94EFB3F30160833D -:10E07000718382839383E0903D10F0903E10009175 -:10E080003F10109140102091391030913A1040917A -:10E090003B1050913C10609135107091361080917A -:10E0A0003710909138105F924F920E9451870F94D1 -:10E0B000988329893A894B895C89D3016D917D9137 -:10E0C0008D919C910F94EFB3F301608371838283F0 -:10E0D0009383E0903D10F0903E1000913F1010911E -:10E0E00040102091391030913A1040913B105091DE -:10E0F0003C106091351070913610809137109091DE -:10E1000038105F924F920E9451870F9498838FEF3F -:10E1100080938502609180137091811380918213A6 -:10E120009091831320917C1330917D1340917E1345 -:10E1300050917F130F94B3B389011F932F93898557 -:10E140009A85885A9F4F9F938F9388EE9DE59F9362 -:10E150008F930F9493AD0FB6F894DEBF0FBECDBF73 -:10E16000332019F08BE59FE002C08DE59FE0B801F8 -:10E170000F94A1B3832D0F9485832B013C012D8532 -:10E180003E854F8558890F94EEB369877A878B87D0 -:10E190009C8720E030E0A9010F943AB618164CF0A5 -:10E1A00089859A85AB85BC85B05889879A87AB8766 -:10E1B000BC8789859A85AB85BC8589839A83AB8327 -:10E1C000BC83AD89BE89AB5CBF4EBE87AD8720E006 -:10E1D00030E040E752E46D917D918D919C910F94D8 -:10E1E000EEB3ED85FE856083718382839383E09037 -:10E1F0003D10F0903E1000913F1010914010209182 -:10E20000391030913A1040913B1050913C10609180 -:10E210003510709136108091371090913810AEEF14 -:10E22000BCE0BF93AF93812C912CE4E3AE2EE2E4EB -:10E23000BE2EF1E4CF2EF0E1DF2E0E9451870F9425 -:10E2400098832F89388D498D5A8DAD85BE856D9106 -:10E250007D918D919C910F94EEB3ED85FE85608349 -:10E26000718382839383E0903D10F0903E10009183 -:10E270003F10109140102091391030913A10409188 -:10E280003B1050913C106091351070913610809188 -:10E29000371090913810AEEFBCE0BF93AF930E945F -:10E2A00051870F949883832D0F9485839B01AC0134 -:10E2B000C301B2010F94EEB32B013C010F900F90FC -:10E2C0000F900F9020E030E0A9010F943AB6181695 -:10E2D00024F077FA709477F870944D825E826F82A2 -:10E2E00078868E010F5F1F4F4E01F9E08F0E911C53 -:10E2F00085E1A82E8EE5B82ED801CC901196DC9041 -:10E3000011971296EC9012971396FC900C5F1F4F8A -:10E31000FF92EF92DF92CF92BF92AF920F9493ADA4 -:10E3200029893A894B895C896C2D7D2D8E2D9F2DF5 -:10E330000F94EEB36B017C010F900F900F900F9034 -:10E340000F900F9020E030E0A9010F943AB6181614 -:10E3500024F0F7FAF094F7F8F09420E030E040EA87 -:10E3600050E4C701B6010F943AB61816ACF41092F7 -:10E370002102B1E03B1631F0E2E03E1631F06AEAEC -:10E3800076E005C06EE476E002C06CEA76E040E03C -:10E3900050E089E090E05BC08016910609F0ACCFB8 -:10E3A000A301920169857A858B859C850F94EEB3D4 -:10E3B0006B017C0120E030E0A9010F943AB61816F9 -:10E3C00024F0D701C601B05802C0D701C601BF93DF -:10E3D000AF939F938F9388EF9DE59F938F930F94B7 -:10E3E00093AD0F900F900F900F900F900F9020E033 -:10E3F00030E0A901C701B6010F943AB618165CF4D3 -:10E4000020E030E040E85FE3C701B6010F943AB680 -:10E4100018165CF044C020E030E040E85FEBC70134 -:10E42000B6010F9488AE87FF3AC0F1E03F1631F095 -:10E4300082E0381631F06AEA76E005C06EE476E0F4 -:10E4400002C06CEA76E040E050E088E090E00F9493 -:10E45000D154ED89FE89EB5CFF4E1082118212824D -:10E460001382E0903D10F0903E1000913F1010910B -:10E4700040102091391030913A1040913B1050914A -:10E480003C1060913510709136108091371090914A -:10E4900038100F94BA59832D92DC80E025C0ED89A5 -:10E4A000FE89EB5CFF4E1082118212821382E09093 -:10E4B0003D10F0903E1000913F10109140102091BF -:10E4C000391030913A1040913B1050913C106091BE -:10E4D00035107091361080913710909138100F944C -:10E4E000BA59832D6CDC81E06A960FB6F894DEBFD2 -:10E4F0000FBECDBFDF91CF911F910F91FF90EF9095 -:10E50000DF90CF90BF90AF909F908F907F906F9053 -:10E510005F904F903F9008952F923F924F925F925D -:10E520006F927F928F929F92AF92BF92CF92DF9223 -:10E53000EF92FF920F931F93CF93DF93CDB7DEB788 -:10E540002B970FB6F894DEBF0FBECDBF0F944232AB -:10E5500019821A821B821C82CE010196D0D310929E -:10E56000030D1092020D20E030E048E452E4609187 -:10E57000DC0F7091DD0F8091DE0F9091DF0F0F9413 -:10E580003AB618168CF020E030E048E452E460918E -:10E5900008077091090780910A0790910B070F9463 -:10E5A0003AB618160CF04FC084E79DE50F94930718 -:10E5B00064E080E00F946E3282E00E949D9A809128 -:10E5C000DC0F9091DD0FA091DE0FB091DF0F8983FA -:10E5D0009A83AB83BC83CE0101960E9446A00F9420 -:10E5E000103182EB96E00F94103187E094E00F94A5 -:10E5F000103164E089E00F946E3280E00E949D9AB1 -:10E600008091080790910907A0910A07B0910B0724 -:10E6100089839A83AB83BC83CE0101960E9446A076 -:10E620000F94103182EB96E00F94103187E094E064 -:10E630000F9410310F944E3288EE93E00F94BD1278 -:10E640000E94C7F290CF6BE47BE581E00F94233208 -:10E6500081E00F9427370F941D3760E080E00F941E -:10E660006E3284EA9DE50F94953181E00F949C66AB -:10E6700060ED77E080E090E00F940D8782E090E01D -:10E68000909323028093220200ED17E021E043E003 -:10E6900050E060E070E08FEF9FEF0F946D533C010E -:10E6A0001092BC191092BB190F94BC7D61E088E0F8 -:10E6B0000F940A866FEF88E00F94DC856FEF70E0AF -:10E6C00088E00F94468660ED77E080E090E00F945C -:10E6D0000D870F94BC7D8091761390917713892BD1 -:10E6E00039F440E050E060E070E087E090E090C2F4 -:10E6F00000ED17E021E043E050E0B30180E090E05E -:10E700000F946D533C0186E990E09093BC1980937F -:10E71000BB1915E088EE93E00F94BD1263E082E12F -:10E720000F946E328FE996E00F94103188EE93E0EB -:10E730000F94BD1263E082E10F946E3281EA96E09D -:10E740000F941031115031F71092BC191092BB196F -:10E750000F94BC7D81E00F94680E809178139091A6 -:10E760007913009709F44EC2829764F481E00F9404 -:10E770004587882309F48FC280E00F94458788235A -:10E7800009F440C200ED17E021E043E050E0B3019E -:10E7900081E090E00F946D5308EE13E021E043E038 -:10E7A00050E0BC0183E090E00F946D533C0180E0A9 -:10E7B0000F94C855882309F42DC200ED17E021E01D -:10E7C00043E050E0B30184E090E00F946D533C01CE -:10E7D00080E058DB882309F41DC200E010E021E04E -:10E7E00043E050E0B30184E090E00F946D530CEDF2 -:10E7F00015E021E043E050E0BC0185E090E00F949B -:10E800006D533C0181E03EDB882309F403C200E044 -:10E8100010E021E043E050E0B30185E090E00F9488 -:10E820006D531C010F9464371092210220E030E0F8 -:10E8300040E651E4609135107091361080913710A8 -:10E84000909138100F94EFB32B013C016093351079 -:10E8500070933610809337109093381020E030E09A -:10E8600040E451E46091391070913A1080913B106E -:10E8700090913C100F94EFB36D837E838F839887C4 -:10E880006093391070933A1080933B1090933C1032 -:10E8900020E030E040E251E460913D1070913E1084 -:10E8A00080913F10909140100F94EFB360933D1012 -:10E8B00070933E1080933F10909340102EEF3CE0F9 -:10E8C0003F932F93812C912C14E3A12E12E4B12EAF -:10E8D00001E4C02E00E1D02E7B018C012D813E8110 -:10E8E0004F815885C301B2010E9451870F949883CC -:10E8F0000CED15E021E043E050E0B10186E090E04E -:10E900000F946D533C010F900F90412C512C1E829F -:10E910001D82212C312C1B861A86198620E030E0BE -:10E9200040E85FE360913D1070913E1080913F1090 -:10E93000909140100F94EEB37B018C0160933D10D9 -:10E9400070933E1080933F109093401020913910A7 -:10E9500030913A1040913B1050913C10609135102D -:10E96000709136108091371090913810AEEFBCE066 -:10E97000BF93AF93812C912CA4E3AA2EA2E4BA2ECC -:10E98000B1E4CB2EB0E1DB2E0E9451870F94988327 -:10E990000F900F901C9B24C083B182958170898752 -:10E9A00083B18295869586958370F1E08F2781707B -:10E9B0008D831E8220E02F938D818F931F929985E6 -:10E9C0009F93A6EBBDE5BF93AF930F9493AD0F90CC -:10E9D0000F900F900F900F900F90FF24F39401C0B1 -:10E9E000F12CF6E04F16510424F42FEF421A520A8C -:10E9F0000FC000E010E020E043E050E06A857B8536 -:10EA000086E090E00F946D539B878A87412C512CB0 -:10EA10000F94BC7D81E00F94680E88EE28163104B7 -:10EA200031F09FEF291A390AFF2009F477CFA98521 -:10EA3000A11116C0ED81FE81319719F44EE456E024 -:10EA400002C04AEA56E06CEA76E0F7EE2F1631048F -:10EA50001CF085E090E002C084E090E00F94D15477 -:10EA60008FE59FE00F9463B3813051F061E082EE57 -:10EA70009DE50E9465DB61E085ED9DE50E9465DB1B -:10EA80002985222309F4C6C020E030E040E251E4A9 -:10EA900060913D1070913E1080913F109091401018 -:10EAA0000F94EFB37B018C0160933D1070933E1087 -:10EAB00080933F10909340102091391030913A107C -:10EAC00040913B1050913C10609135107091361080 -:10EAD0008091371090913810EEEFFCE0FF93EF93A8 -:10EAE000812C912CE4E3AE2EE2E4BE2EF1E4CF2E95 -:10EAF000F0E1DF2E0E9451870F94988300E010E030 -:10EB000021E042E050E060E070E08DE090E00F94A2 -:10EB10006D5380E00E94D3C4582E21E042E050E0C3 -:10EB200061E070E08DE090E00F946D5381E00E9411 -:10EB3000D3C4582221E042E050E062E070E08DE072 -:10EB400090E00F946D533C010F900F90552009F405 -:10EB500061C061E088EF9EE00F9475B300ED17E0AF -:10EB600021E043E050E0B30187E090E00F946D5363 -:10EB70003C0181E00F94C855582E882309F44AC0FF -:10EB800021E043E050E0B30188E090E00F946D5342 -:10EB90003C0180917B1381111BC021E043E050E0D8 -:10EBA000B30189E090E00F946D533C010E94A99E4F -:10EBB00080917A13882341F040E050E060E070E0FB -:10EBC0008BE090E00F94D15480917A13811122C090 -:10EBD00080917B1381110BC000ED17E021E043E031 -:10EBE00050E0B3018AE090E00F946D533C0108E8D7 -:10EBF00013E121E043E050E0B3018BE090E00F949B -:10EC00006D5313C086E090E040E050E060E070E0BB -:10EC10000F94D15408E813E121E043E050E0B30140 -:10EC20008CE090E00F946D53512C1092F50F61E041 -:10EC300081ED9DE50E9465DB81E00F94273755202B -:10EC400019F087E99DE502C08DE39AE50F945A53C8 -:10EC500080E00F949C6681E090E090932302809383 -:10EC60002202852D2B960FB6F894DEBF0FBECDBFC6 -:10EC7000DF91CF911F910F91FF90EF90DF90CF9098 -:10EC8000BF90AF909F908F907F906F905F904F90CC -:10EC90003F902F9008958AE090E0B6CF22E0209335 -:10ECA000C0001092C50090E19093C4008091C10013 -:10ECB00080618093C1008091C10088608093C10011 -:10ECC0008091C10080688093C10080918B15813054 -:10ECD000A9F42093C8001092CD009093CC008091AD -:10ECE000C90080618093C9008091C90088608093C9 -:10ECF000C9008091C90080688093C900089510926E -:10ED00008A151092891508950F931F93CF93DF935F -:10ED1000D82F8B010F94CA828AEE0F947C820F94B5 -:10ED20009A82C82F811103C00F94C18214C08D2F05 -:10ED30000F947C820F949A82811102C0C0E00BC0B4 -:10ED4000F80180810F947C820F949A828823B1F31A -:10ED50000F94C182C1E08C2FDF91CF911F910F9151 -:10ED600008950F931F93CF93DF93EC010F9445AC5D -:10ED70008C018036910508F054C080919713811161 -:10ED800005C00E943CDC81E0809397134091871579 -:10ED900050918815809195139091961348175907B3 -:10EDA00039F4209198133091991312161306CCF16F -:10EDB00020919313309194131216130624F49C019E -:10EDC0002F593F4F01C09C018417950740F44450D0 -:10EDD0005109401B510B421753071CF109C0C801D0 -:10EDE00004964817590748F044505109401B510BED -:10EDF000509388154093871549C089EE91E0BC0176 -:10EE0000601B710B8B01621773075CF060E070E0B0 -:10EE10008AE993E10F940EB9109388150093871532 -:10EE200035C0E4E7FEE584918F01882339F00E9424 -:10EE30006EAD0F5F1F4FF8018491F7CFEBE5FEE554 -:10EE400084918F01882339F00E946EAD0F5F1F4FB0 -:10EE5000F8018491F7CFFE018491882321F00E946C -:10EE60006EAD2196F8CFE4E4FEE58491EF018111C7 -:10EE700007C08AE0DF91CF911F910F910C946EAD86 -:10EE80000E946EAD2196FE018491F1CF809187158D -:10EE900090918815FC01E656FC4E23E02083BE01CC -:10EEA00083569C4E0F943EAC809198139091991389 -:10EEB00001969093991380939813E6E9FEE5849167 -:10EEC000EF01882331F00E946EAD2196FE018491FE -:10EED000F8CFEDE7FEE58491EF01882331F00E9441 -:10EEE0006EAD2196FE018491F8CFC0918715D09127 -:10EEF0008815C356DC4E8991882319F00E946EADA7 -:10EF0000FACFEBE7FEE58491EF01882309F4B1CF56 -:10EF10000E946EAD2196FE018491F7CF2F923F9211 -:10EF20004F925F926F927F928F929F92AF92BF9219 -:10EF3000CF92DF92EF92FF920F931F93CF93DF93C5 -:10EF4000CDB7DEB72A970FB6F894DEBF0FBECDBFA0 -:10EF50002B013C0149015A0120E030E04CE052E431 -:10EF60000F94EEB325E535E547E052E40F94DDB4A8 -:10EF70006B017C010F9483B50F944EB58B0177FF25 -:10EF800012C020E030E040E85FE3C701B6010F9413 -:10EF90003AB618160CF05DC0C12CD12CE0E8EE2E6C -:10EFA000EFE3FE2E56C066307105DCF02AEA3AE245 -:10EFB0004CE453E4C301B2010F94EEB325E535E50B -:10EFC00047E052E40F94DDB46B017C0120E030E0B7 -:10EFD000A9010F9488AE87FF3FC0C12CD12C7601C8 -:10EFE0003BC0072E000C880B990B0F948EAE25E5C5 -:10EFF00035E547E052E40F94F5A720E030E04CE01F -:10F0000052E40F94EFB39B01AC01C301B2010F9422 -:10F01000EEB325E535E547E052E40F94DDB46B012E -:10F020007C0120E030E0A9010F9488AE87FD17C075 -:10F0300020E030E040E85FE3C701B6010F943AB644 -:10F04000181684F4C12CD12C70E8E72E7FE3F72E3C -:10F0500009C000E010E006C005E010E003C0C12CCC -:10F06000D12C760120E030E040EC50E4C501B40141 -:10F070000F94EEB32BEA3AEA42E052E40F94DDB487 -:10F080002B013C010F9483B50F944EB57A876987A5 -:10F0900077FF12C020E030E040E85FE3C301B20137 -:10F0A0000F943AB618160CF062C0412C512C60E84F -:10F0B000662E6FE3762E5BC0E985FA853697FCF005 -:10F0C00026E535E549E253E4C501B4010F94EEB3FA -:10F0D0002BEA3AEA42E052E40F94DDB42B013C0102 -:10F0E00020E030E0A9010F9488AE87FF43C0412C97 -:10F0F000512C320125E030E03A87298743C0072EA2 -:10F10000000C880B990B0F948EAE2BEA3AEA42E082 -:10F1100052E40F94F5A720E030E040EC50E40F9467 -:10F12000EFB39B01AC01C501B4010F94EEB32BEA20 -:10F130003AEA42E052E40F94DDB42B013C0120E0B6 -:10F1400030E0A9010F9488AE87FD19C020E030E0BF -:10F1500040E85FE3C301B2010F943AB6181694F485 -:10F16000412C512C50E8652E5FE3752E0BC01A869A -:10F17000198608C085E090E09A87898703C0412CF2 -:10F18000512C3201A701960160E070E080E89FE316 -:10F190000F94EEB369837A838B839C8318019FEF6E -:10F1A000291A390AE985FA853196F887EF83E7E06D -:10F1B00089859A85E89F9001E99F300D11243E834F -:10F1C0002D83F901E00FF11FEE0FFF1FEE0FFF1F60 -:10F1D000E457FA4E218132814381548169817A81D9 -:10F1E0008B819C810F94F5A74B015C01ED81FE8121 -:10F1F000E20DF31DEE0FFF1FEE0FFF1FE457FA4E57 -:10F200002181328143815481C701B6010F94F5A752 -:10F210009B01AC01C501B4010F94EFB34B015C013C -:10F22000A301920160E070E080E89FE30F94EEB3E9 -:10F230009B01AC01C501B4010F94F5A74B015C0122 -:10F24000E7E08F819885E89F9001E99F300D1124B8 -:10F250003E832D83F901E00FF11FEE0FFF1FEE0F2C -:10F26000FF1FE457FA4E2181328143815481698125 -:10F270007A818B819C810F94F5A769837A838B8334 -:10F280009C832D813E81220D331D220F331F220FBF -:10F29000331F24573A4EF901218132814381548131 -:10F2A000C701B6010F94F5A79B01AC0169817A8172 -:10F2B0008B819C810F94EFB3A30192010F94F5A76A -:10F2C0009B01AC01C501B4010F94EFB32A960FB6B0 -:10F2D000F894DEBF0FBECDBFDF91CF911F910F918C -:10F2E000FF90EF90DF90CF90BF90AF909F908F9066 -:10F2F0007F906F905F904F903F902F900895CF93A5 -:10F30000C82F8091921388608093921384E0809339 -:10F310009113109290132FEF80E792E021508040DC -:10F320009040E1F700C0000060E080918F130F94DF -:10F33000DC8560E080918E130F94DC8580918D13C5 -:10F340008F3F19F060E00F94DC858091921384FD6B -:10F350001FC083E00E94199A8FE496E40197F1F7A9 -:10F3600000C0000083E00E94199A8FE496E40197A0 -:10F37000F1F700C0000083E00E94199A87E592E04F -:10F380000197F1F700C0000082E00E94199A19C0AD -:10F3900080620E949B9A8FE496E40197F1F700C087 -:10F3A00000008091921380620E949B9A87E592E010 -:10F3B0000197F1F700C000008091921380620E94D3 -:10F3C0009B9A8091921380620E949B9A8FEE90E0AC -:10F3D0000197F1F700C0000084E080938C138CE06B -:10F3E0000E949B9A8FEE90E00197F1F700C0000019 -:10F3F000C1110F941D378FED9EE20197F1F700C008 -:10F40000000086E00E949B9A8FEE90E00197F1F752 -:10F4100000C0000010928413CF9108956F927F92E4 -:10F420008F929F92AF92BF92CF92DF92EF92FF9214 -:10F430000F931F93CF93DF93CDB7DEB7CC55D10990 -:10F440000FB6F894DEBF0FBECDBF8091D3168F9359 -:10F450008091D2168F938BE39EE59F938F938E01BD -:10F46000015C1F4F1F930F930F94ECAD0F900F9003 -:10F470000F900F900F900F90F12CF8010190002049 -:10F48000E9F73197E01BF10BFE1684F46801CF0C0D -:10F49000D11CF7FCDA94F6018081082E000C990B40 -:10F4A0000F94F0B8F6018083F394E7CF84ED96E1F2 -:10F4B0000E94A4E0612CCE0101967C0184E3A82E79 -:10F4C0008EE5B82E6E0191E2C90ED11C8091D7163F -:10F4D000823080F08091DC169091DD16A091DE16CE -:10F4E000B091DF168F719927AA27BB27892B8A2B0A -:10F4F0008B2B21F1611003C08FEF9FEF05C080912E -:10F50000D2169091D31601969093D3168093D2166B -:10F51000C45ADF4F0FB6F894DEBF0FBECDBFDF91E8 -:10F52000CF911F910F91FF90EF90DF90CF90BF9000 -:10F53000AF909F908F907F906F90089540E050E043 -:10F54000B70184ED96E10E94CBE218169CF6712C6F -:10F55000F70101900020E9F73197EE19FF097E16B7 -:10F5600074F44701870C911C77FC9A94F401808114 -:10F5700090E00F94F0B8F40180837394E9CF8A850A -:10F580008E3709F4A3CF45E050E0B801C7010F94CE -:10F590004EB9892B09F09ACF1F930F93BF92AF9268 -:10F5A000DF92CF920F94ECAD60E0C6010E9465DB64 -:10F5B00061E080E39EE50E9465DB0F900F900F9065 -:10F5C0000F900F900F906624639480CF8F929F923C -:10F5D000AF92BF92CF92DF92EF92FF920F931F9361 -:10F5E000CF93DF9300D01F92CDB7DEB7FC018381AC -:10F5F000813011F080E06BC0818181FFFBCF818978 -:10F600009289A389B489892B8A2B8B2B09F45EC03C -:10F610007F0140E050E0BA01CF010E940EE0882354 -:10F6200049F3F70185889688A788B08CC18CD28C65 -:10F6300082E090E0A0E0B0E0F60180839183A283B5 -:10F64000B3839E012F5F3F4FB501A401C6010E9405 -:10F65000D5DE882379F200E010E09801B501A4011D -:10F66000C6010E9444DE882329F289809A80AB80FB -:10F67000BC80F6018789803141F4F8EF8F16FFEFE7 -:10F680009F06A104B10448F4DCCF88EF88168FEF01 -:10F690009806A8068FE0B806A0F2F701158A168A28 -:10F6A000178A108E118A128A138A148A81818068BF -:10F6B0008183C7010E9499E3882309F49BCF40E02E -:10F6C00050E0BA01C7010E940EE001C081E00F9036 -:10F6D0000F900F900F90DF91CF911F910F91FF909E -:10F6E000EF90DF90CF90BF90AF909F908F90089554 -:10F6F0002F923F925F926F927F928F929F92AF92E2 -:10F70000BF92CF92DF92EF92FF920F931F93CF930E -:10F71000DF93CDB7DEB7C356D1090FB6F894DEBF7D -:10F720000FBECDBF7C018B014A012DB63EB6512CD8 -:10F730006E0127E5C20ED11CF8018381823008F4E6 -:10F7400032C180859185A285B3858F719927AA27BB -:10F75000BB27892B8A2B8B2B09F025C110929C1675 -:10F760004CE956E1BE016F5F7F4FC8010E94CBE2BA -:10F7700018160CF018C18C85982F9871903109F0EB -:10F780006FC02091601930916119215031092230E8 -:10F79000310508F465C06DB67EB6BE016F5F7F4F60 -:10F7A000C6010E948DDCF7018081882341F0F701BA -:10F7B00001900020E9F73197EE19FF0902C0E1E05E -:10F7C000F0E0D6010D900020E9F7EC19FD09EA0FF1 -:10F7D000FB1F31962DB73EB72E1B3F0B0FB6F8948B -:10F7E0003EBF0FBE2DBFEDB7FEB731965F01882338 -:10F7F00011F0B70102C065E074E0C5010F9447B98C -:10F80000B601C5010F9428B965E074E0C5010F94F5 -:10F8100028B91CAE1FAE21E0A601B801CE01CC96DE -:10F820000E9491E58BE1FE01FC96DE01919601902C -:10F830000D928A95E1F740E050E0BE016F5D7F4F89 -:10F84000C50156DFCE0181960E94BDA7CE01CC96A0 -:10F850000E94BDA70FB6F8947EBE0FBE6DBE6CCFE2 -:10F860002981222309F49FC0253E09F465CF2E3259 -:10F8700009F462CF20919C162E3209F45DCF8A7074 -:10F8800009F05ACF81E0903109F080E08093D116E1 -:10F89000903141F08985873409F04ECF8A858E37C3 -:10F8A00009F44ACF809160199091611981309105D6 -:10F8B00021F068F00297A9F13FCF809162199091F1 -:10F8C00063190196909363198093621935CFBE0135 -:10F8D0006F5F7F4F83E896E10E948DDC5701F50151 -:10F8E00081915F01882319F00E946EADF8CF83E803 -:10F8F000A82E86E1B82EF50181915F01882319F0C9 -:10F900000E946EADF8CF80E20E946EAD6D8D7E8D4F -:10F910008F8D98A14AE00E9486AD8AE00E946EAD6C -:10F920000BCFBE016F5F7F4F83E896E10E948DDCB5 -:10F93000F80184819581A681B78180939416909374 -:10F940009516A0939616B093971680859185A285FB -:10F95000B3858093981690939916A0939A16B093B6 -:10F960009B1689899A8990939316809392168F8516 -:10F97000988990939116809390168114910441F088 -:10F9800063E876E1C4010F9415B9892B51F40BC0DB -:10F99000852D90E0209162193091631982179307A9 -:10F9A00011F05394C9CE0FB6F8943EBE0FBE2DBED3 -:10F9B000CD59DF4F0FB6F894DEBF0FBECDBFDF913C -:10F9C000CF911F910F91FF90EF90DF90CF90BF905C -:10F9D000AF909F908F907F906F905F903F902F900F -:10F9E00008950F931F93CF93DF939091F50F992371 -:10F9F00021F090913A07911198C0C82F80918016FC -:10FA0000882361F08091330E9091340E892B19F088 -:10FA10000E94BECE17C00F94348B14C010928A156A -:10FA200010928915E7E1FFE584918F01882339F071 -:10FA30000E946EAD0F5F1F4FF8018491F7CF8AE0EF -:10FA40000E946EADCC2341F0C13009F06EC0E1EBF5 -:10FA5000FEE58491EF0134C0EDEEFEE58491EF0107 -:10FA6000882331F00E946EAD2196FE018491F8CF7B -:10FA70008AE00E946EAD8091F50F811156C0809191 -:10FA8000010790910207039740F49FB7F894809183 -:10FA900002018460809302019FBF8BE193E0019794 -:10FAA000F1F79FB7F894809102018B7F8093020158 -:10FAB0009FBF8BE891E00197F1F788ED9EE52FC09D -:10FAC000882331F00E946EAD2196FE018491F8CF1B -:10FAD0008AE00E946EAD8091F50F811126C0809161 -:10FAE000010790910207039740F49FB7F894809123 -:10FAF00002018460809302019FBF8BE193E0019734 -:10FB0000F1F79FB7F894809102018B7F80930201F7 -:10FB10009FBF8BE891E00197F1F78CE99EE5DF91BB -:10FB2000CF911F910F910D945A53DF91CF911F9157 -:10FB30000F910895CF93C1E020E030E048E452E413 -:10FB40006091DC0F7091DD0F8091DE0F9091DF0FDF -:10FB50000F943AB618160CF0C0E0C19561E088E049 -:10FB60000F940A866C2F88E00F94DC856C2F70E070 -:10FB700088E0CF910D9446862F923F924F925F92EC -:10FB80006F927F928F929F92AF92BF92CF92DF92AD -:10FB9000EF92FF920F931F93CF93DF93CDB7DEB712 -:10FBA0002A970FB6F894DEBF0FBECDBFA8958091FF -:10FBB0005D0F882309F45AC40F94CA4110915B0F5A -:10FBC000409008075090090760900A0770900B0753 -:10FBD0002091020D3091030D3A8329830F942588DB -:10FBE0000F948CAE20915F0F3091600F4091610FA8 -:10FBF0005091620F0F94EEB320E030E04AEF54E4EE -:10FC00000F943AB61816D4F4612F70E080E090E0BB -:10FC10000F948EAE6B017C0129813A81B901330FBB -:10FC2000880B990B0F948EAEAB01BC01AA24A39450 -:10FC30009301820180E090E00F94AE3E10915C0F42 -:10FC40004090DC0F5090DD0F6090DE0F7090DF0F62 -:10FC50008091891590918A159A8389830F942588BC -:10FC60000F948CAE2091630F3091640F4091650F1B -:10FC70005091660F0F94EEB320E030E04AEF54E469 -:10FC80000F943AB61816CCF4612F70E080E090E043 -:10FC90000F948EAE6B017C0129813A81B901330F3B -:10FCA000880B990B0F948EAEAB01BC01A12C930174 -:10FCB000820181E090E00F94AE3E8090DC0F909046 -:10FCC000DD0FA090DE0FB090DF0F8091891590912D -:10FCD0008A159A838983BC01990F880B990B0F941D -:10FCE0008EAEA50194010F94EEB36B017C0120E070 -:10FCF00030E040E251E40F943AB618160CF419C102 -:10FD000020E030E040E251ECC701B6010F9488AE2C -:10FD100087FF04C081E0809386190FC129813A8151 -:10FD2000232BC1F3809186198111F8C02091E11035 -:10FD30003091E2104091E3105091E410C701B601F8 -:10FD40000F94F5A769837A838B839C832091821912 -:10FD5000309183194091841950918519C701B601DA -:10FD60000F94EFB32B013C013091FB063A87809151 -:10FD7000FC0689871091FD060091FE06232F382F7F -:10FD8000412F502FB201C3010F9488AE87FFACC042 -:10FD90008A859985A12FB02F80938219909383191A -:10FDA000A0938419B09385192091E5103091E61045 -:10FDB0004091E7105091E810BC01812F902F0F94D3 -:10FDC000F5A76D837E838F83988720917E1930916C -:10FDD0007F194091801950918119C501B4010F9488 -:10FDE000EEB32091E9103091EA104091EB10509160 -:10FDF000EC100F94F5A720ED3CEC4CE45DE30F9480 -:10FE0000F5A72B013C0123E333E343E75FE3609174 -:10FE10007A1970917B1980917C1990917D190F94BA -:10FE2000F5A79B01AC01C301B2010F94EFB32B0105 -:10FE30003C0160937A1970937B1980937C1990939D -:10FE40007D192D813E814F81588569817A818B8111 -:10FE50009C810F94EFB3A30192010F94EEB32B0199 -:10FE60003C0120E030E04FE753E40F943AB620E045 -:10FE700030E0A901181604F1C301B2010F9488AE55 -:10FE800087FF65C020E030E0A901C701B6010F94EB -:10FE900088AE87FF52C0A70196016A857985812FB8 -:10FEA000902F0F94EEB3609382197093831980930F -:10FEB00084199093851941C0C701B6010F943AB6D1 -:10FEC00018160CF03EC0A70196016A857985812F2E -:10FED000902F0F94EEB360938219709383198093DF -:10FEE0008419909385192DC09091F7069A872091D7 -:10FEF000F80629871091F9060091FA06292F39850D -:10FF0000412F502FB201C3010F943AB618160CF4CA -:10FF10003FCF4A865986162D072D3ACF1092821967 -:10FF200010928319109284191092851910928619D3 -:10FF3000FDCE81E08093861904C0412C512C320102 -:10FF400006C0412C512C3FE7632E33E4732E809280 -:10FF50007E1990927F19A0928019B092811920E0A9 -:10FF600030E048EC51E460919D0E70919E0E8091BE -:10FF70009F0E9091A00E0F9488AE87FD12C06091E5 -:10FF8000ED067091EE06072E000C880B990B0F946E -:10FF90008EAE9B01AC01C501B4010F943AB61816A0 -:10FFA00094F46091090270910A02072E000C880BEC -:10FFB000990B0F948EAE9B01AC01C501B4010F9457 -:10FFC00088AE87FD03C010925C0F08C0C301B20168 -:10FFD0000F944EB57595679560935C0F0F942588C7 -:10FFE0008090761990907719A0907819B09079192F -:10FFF000DC01CB0188199909AA09BB09893E934004 -:020000023000CC -:10000000A105B10508F4C8C06091570F7091580F51 -:10001000072E000C880B990B0F948EAE6B017C01A0 -:100020000F942588681979098A099B090F948CAE69 -:100030009B01AC0160E070E08AE793E40F94DDB4CB -:10004000A70196010F94F5A70F944EB570937713FF -:10005000609376136091590F70915A0F072E000C20 -:10006000880B990B0F948EAE6B017C01EED768194B -:1000700079098A099B090F948CAE9B01AC0160E061 -:1000800070E08AE793E40F94DDB4A70196010F9422 -:10009000F5A70F944EB58B01709379136093781385 -:1000A0001092580F1092570F10925A0F1092590F2A -:1000B00087E89FE00F9463B3898381E09981911170 -:1000C00001C080E08093460280917613909177136F -:1000D000892BB1F420E030E048E452E46091DC0F79 -:1000E0007091DD0F8091DE0F9091DF0F0F943AB683 -:1000F000181634F4809168198F5F8093681902C0D4 -:1001000010926819012B09F0AEC1909100078091FF -:10011000FF06981769F0E091FF0627E5E29FF001DE -:100120001124E353F84F80819181A281B38108C0EB -:100130008091BB199091BC19092E000CAA0BBB0B26 -:100140008C349105A105B10508F48DC18091691920 -:100150008F5F8093691980916819863038F03981F2 -:10016000332321F01092681980E03BDC80916919FB -:10017000803140F080914602882321F01092691965 -:1001800081E02FDCD7DC61D7609376197093771903 -:1001900080937819909379198090080790900907B7 -:1001A000A0900A07B0900B076091020D7091030DAB -:1001B000072E000C880B990B0F948EAEA5019401AD -:1001C0000F94EEB36B017C012091ED103091EE1095 -:1001D0004091EF105091F0100F94F5A769837A8346 -:1001E0008B839C83209172193091731940917419FB -:1001F00050917519C701B6010F94EFB33B018C0103 -:100200008091F3068A879091F40699873090F506DD -:100210002090F6069C01432D522DB301C8010F9486 -:1002200088AE87FD16C02091EF062A873091F00630 -:1002300039873090F1062090F206432D522DB301FC -:10024000C8010F943AB6181624F06A867986302EC3 -:10025000212E8A859985A32DB22D809372199093B2 -:100260007319A0937419B09375192091F1103091FE -:10027000F2104091F3105091F410BC01832D922D97 -:100280000F94F5A76D837E838F83988720916E19D5 -:1002900030916F194091701950917119C501B401D5 -:1002A0000F94EEB32091F5103091F6104091F710B5 -:1002B0005091F8100F94F5A720ED3CEC4CE45DE371 -:1002C0000F94F5A72B013C0123E333E343E75FE3FE -:1002D00060916A1970916B1980916C1990916D19E8 -:1002E0000F94F5A79B01AC01C301B2010F94EFB3CA -:1002F0002B013C0160936A1970936B1980936C1900 -:1003000090936D1980926E1990926F19A092701946 -:10031000B09271192D813E814F81588569817A8112 -:100320008B819C810F94EFB3A30192010F94EEB3E4 -:100330002B013C0120E030E04FE753E40F943AB644 -:1003400020E030E0A9011816BCF4C701B6010F94F3 -:100350003AB618168CF5A70196016A857985832D22 -:10036000922D0F94EEB3609372197093731980936A -:1003700074199093751920C0C301B2010F9488AE0F -:1003800087FF24C020E030E0A901C701B6010F9427 -:1003900088AE87FF18C0A70196016A857985832DED -:1003A000922D0F94EEB3609372197093731980932A -:1003B00074199093751907C0412C512C9FE7692E31 -:1003C00093E4792E03C0412C512C320120E030E01F -:1003D00040E751E4C501B4010F943AB6181684F011 -:1003E00020E030E048EC51E460919D0E70919E0E4B -:1003F00080919F0E9091A00E0F9488AE87FF13C03E -:1004000020E030E04AEF52E4C501B4010F9488AE19 -:1004100087FF09C0C301B2010F944EB5759567956A -:1004200060935B0F02C010925B0F8091C80F811127 -:100430001DC02A960FB6F894DEBF0FBECDBFDF9168 -:10044000CF911F910F91FF90EF90DF90CF90BF90D1 -:10045000AF909F908F907F906F905F904F903F9064 -:100460002F900C94CDE91092691975CE2A960FB68B -:10047000F894DEBF0FBECDBFDF91CF911F910F91DA -:10048000FF90EF90DF90CF90BF90AF909F908F90B4 -:100490007F906F905F904F903F902F9008952091A4 -:1004A000E5103091E6104091E7105091E81060E0BF -:1004B00070E08FE793E40F94DDB46093F7067093D8 -:1004C000F8068093F9069093FA062091F110309186 -:1004D000F2104091F3105091F41060E070E08FE75B -:1004E00093E40F94DDB46093EF067093F00680936D -:1004F000F1069093F206089527E030E090E0AC0119 -:10050000022E02C0559547950A94E2F740FF02C0BB -:10051000599A01C0599848E04A95F1F7589A48E02D -:100520004A95F1F7589848E04A95F1F7215031097A -:1005300030F70895519828E02A95F1F788E08A95D8 -:10054000F1F7589A81E098E029B1322F327021FDFD -:1005500011C0589888E08A95F1F7519A28E02A95B9 -:10056000F1F7599888E08A95F1F781E0332341F05B -:1005700080E00895019769F328E02A95F1F7E4CF28 -:100580000895589A88E08A95F1F7599A88E08A95F3 -:10059000F1F70895599888E08A95F1F7589888E01E -:1005A0008A95F1F708958FEF9FE00F9463B38093DE -:1005B000420E0895813039F120F0823009F445C0AF -:1005C000089517988091090181702FB7611105C0B6 -:1005D000F89490910B01916004C0F89490910B01F4 -:1005E0009E7F90930B012FBF409A40989FB788231E -:1005F00029F0F89480910B01816048C0F8948091B3 -:100600000B018E7F43C016988091090182702FB72D -:10061000662329F0F89490910B01926004C0F8943D -:1006200090910B019D7F90930B012FBF419A4198B0 -:100630009FB7882329F0F89480910B01826026C02F -:10064000F89480910B018D7F21C01598809109014C -:1006500084702FB7611105C0F89490910B019460DC -:1006600004C0F89490910B019B7F90930B012FBFD6 -:10067000429A42989FB7882329F0F89480910B0101 -:10068000846004C0F89480910B018B7F80930B01F0 -:100690009FBF089580916F008D7F80936F00909130 -:1006A00000078091FF06981769F0909100078091EC -:1006B000FF069817A1F38091FF068F5F8F708093DC -:1006C000FF06EDCF1092671910926619B19A109239 -:1006D00085001092840080ED97E0909389008093CC -:1006E000880080916F00826080936F0008952FB71B -:1006F000F89494E0899FF0011124EB5DFF4E608136 -:100700007181828193812FBF0895CF93C82FEFDF2E -:100710000F948EAE24E0C29FF0011124E358FF4EE7 -:1007200020813181428153810F94DDB4CF910895AE -:10073000CF93DF9300D01F92CDB7DEB79091000723 -:100740008091FF06981709F445C016DA809185025A -:100750008430C8F519821A821B821C82AE014F5F59 -:100760005F4F6FE60E9438C689819A81AB81BC8158 -:100770009370AA27BB2740918013509181136091F9 -:10078000821370918313840F951FA61FB71F809348 -:10079000801390938113A0938213B093831380915D -:1007A0007C1390917D13A0917E13B0917F130196DD -:1007B000A11DB11D80937C1390937D13A0937E1394 -:1007C000B0937F13BBCF81E00F94680E80E00F944D -:1007D000932FB4CF0F900F900F900F90DF91CF9188 -:1007E0000895A6DF179AEFEFFCE01082169A1182A7 -:1007F000149A089590E0FC013197E231F10508F078 -:100800004EC08827E355FF4F8F4F0D94D0B880918D -:1008100080008F7703C0809180008F7D809380005F -:10082000089580918000877FF9CF84B58F7702C0CB -:1008300084B58F7D84BD08958091B0008F7703C00B -:100840008091B0008F7D8093B000089580919000DA -:100850008F7707C0809190008F7D03C080919000BA -:10086000877F8093900008958091A0008F7707C0C4 -:100870008091A0008F7D03C08091A000877F80932E -:10088000A0000895809120018F7707C080912001FA -:100890008F7D03C080912001877F80932001089580 -:1008A0003FB7F8948091C0199091C119A091C219D5 -:1008B000B091C31926B5A89B05C02F3F19F001962A -:1008C000A11DB11D3FBFBA2FA92F982F8827820FD6 -:1008D000911DA11DB11DBC01CD0142E0660F771F26 -:1008E000881F991F4A95D1F708958F929F92AF92D2 -:1008F000BF92CF92DF92EF92FF92CF9320E030E051 -:100900004AE754E4FC0160817181828193810F94F4 -:10091000F5A70F944EB54B015C0197FD12C028EE70 -:1009200033E040E050E00F94B4B8CA01B9012AE0C6 -:1009300030E040E050E00F94B4B8605D6093B319CC -:1009400003C08DE28093B319640197FE04C0CC24E8 -:10095000DD24C818D9080D2C000CEE08FF088EE223 -:100960008093B419C701B60124E630E040E050E0BE -:100970000F94B4B88AE0882E912CA12CB12CCA0116 -:10098000B901A50194010F94B4B8605D6093B519E5 -:10099000C701B601A50194010F94B4B8C62FCA01CE -:1009A000B901A50194010F94B4B8605D6093B619C4 -:1009B000C05DC093B7191092B81983EB99E1CF913C -:1009C000FF90EF90DF90CF90BF90AF909F908F906F -:1009D00008958F929F92AF92BF92CF92DF92EF9243 -:1009E000FF920F931F93CF93DF93CDB7DEB7659739 -:1009F0000FB6F894DEBF0FBECDBFF82EE92ED42E71 -:100A0000C52EB62EA72E0F9445AC4C0163EC7FE5A6 -:100A10008E010F5F1F4FC8010F943EACC4018D3093 -:100A2000910514F08CE090E0F801E81BF90B1486B6 -:100A3000AF92BF92CF92DF921F930F93EF92FF92EC -:100A40001F9280E28F9381EB9FE59F938F930F948A -:100A50002A310FB6F894DEBF0FBECDBF65960FB634 -:100A6000F894DEBF0FBECDBFDF91CF911F910F91E4 -:100A7000FF90EF90DF90CF90BF90AF909F908F90BE -:100A80000895CF92DF92EF92FF920F931F93CF932F -:100A9000DF93F090B2192091B119F21275C0EB01F9 -:100AA0008C01809186028823F1F06091B01980E07A -:100AB0000F946E32488150E08F2D90E0A0E0B0E0BE -:100AC000C090AC19D090AD19E090AE19F090AF196C -:100AD0008C159D05AE05BF0511F080E201C08EE3C7 -:100AE000B8010F9499318091AB19882309F44CC057 -:100AF0008091B21990E0A0E0B0E04091AC19509123 -:100B0000AD196091AE197091AF1984179507A607BA -:100B1000B707D1F580E092E00F94E92F10938C197C -:100B200000938B19D0938E19C0938D198DE190E0AD -:100B3000A0E0B0E080938F1990939019A093911941 -:100B4000B093921988EC90E0A0E0B0E08093931904 -:100B500090939419A0939519B0939619888190E079 -:100B6000A0E0B0E08093AC199093AD19A093AE19BA -:100B7000B093AF19DF91CF911F910F91FF90EF903C -:100B8000DF90CF900D94B52F8091B2198F5F809335 -:100B9000B21980E0DF91CF911F910F91FF90EF90FC -:100BA000DF90CF900895CF93DF93EB010F9463B361 -:100BB0008883DF91CF9108951F93CF93DF93282FE0 -:100BC00030E0F901E55AF04A8491F901E95EF34A0F -:100BD000D491F901E957F34AC491CC23B9F0162F07 -:100BE000811108DEEC2FF0E0EE0FFF1FE359F34A0E -:100BF000A591B4919FB7F894111104C08C91D09530 -:100C0000D82302C0EC91DE2BDC939FBFDF91CF9104 -:100C10001F910895CF93DF9390E0FC01E95EF34AC2 -:100C20002491FC01E957F34A8491882361F190E013 -:100C3000880F991FFC01E95DF04AC591D491FC0130 -:100C4000E359F34AA591B491611109C09FB7F89493 -:100C50008881209582238883EC912E230BC06230FB -:100C600061F49FB7F8948881322F3095832388836D -:100C7000EC912E2B2C939FBF06C08FB7F894E88180 -:100C80002E2B28838FBFDF91CF9108951F93CF9391 -:100C9000DF93182FEB0161E0BDDF209711F460E0D6 -:100CA00004C0CF3FD10531F461E0812FDF91CF91B6 -:100CB0001F9182CFE12FF0E0E55AF04AE4918E2FA8 -:100CC00090E0FC013197E231F10508F09DC08827E2 -:100CD000E154FF4F8F4F0D94D0B884B5806884BD28 -:100CE000C7BD97C084B5806284BDC8BD92C08091E5 -:100CF0008000806880938000D0938900C093880032 -:100D000088C080918000806280938000D0938B00A7 -:100D1000C0938A007EC080918000886080938000AC -:100D2000D0938D00C0938C0074C08091B000806817 -:100D30008093B000C093B3006CC08091B00080621B -:100D40008093B000C093B40064C08091900080682C -:100D500080939000D0939900C09398005AC08091DE -:100D60009000806280939000D0939B00C0939A0083 -:100D700050C080919000886080939000D0939D0037 -:100D8000C0939C0046C08091A00080688093A00022 -:100D90008091A0008F7B8093A000D093A900C09386 -:100DA000A80037C08091A00080628093A000D093FB -:100DB000AB00C093AA002DC08091A00088608093F2 -:100DC000A000D093AD00C093AC0023C0809120015F -:100DD000806880932001D0932901C093280119C015 -:100DE00080912001806280932001D0932B01C093D9 -:100DF0002A010FC080912001886080932001D09348 -:100E00002D01C0932C0105C0C038D1050CF04CCF8A -:100E100046CFDF91CF911F9108958F929F92AF920D -:100E2000BF92CF92DF92EF92FF926B017C0138DD8F -:100E30004B015C01C114D104E104F104E9F030DD9F -:100E4000DC01CB0188199909AA09BB09883E9340A6 -:100E5000A105B10578F321E0C21AD108E108F10833 -:100E600088EE880E83E0981EA11CB11CC114D10429 -:100E7000E104F10421F7DECFFF90EF90DF90CF90F7 -:100E8000BF90AF909F908F9008951F93CF93DF9363 -:100E9000C82F0F941D3760E080E00F946E328CE114 -:100EA00090E60F94953161E080E00F946E32CC2390 -:100EB00019F08AEF9FE502C08BE090E60F94953120 -:100EC000809101018860809301016FEF70E086E0FE -:100ED000DDDE64EF71E080E090E09FDF62E081E0C2 -:100EE0000F946E3281EF9FE50F94953163E080E0BF -:100EF0000F946E3288E694E00F94103163E081E045 -:100F00000F946E3284EE9FE50F94953184E090E06B -:100F100090932302809322021092BE19DC2F11E0DD -:100F20001C27809101018860809301016FEF70E0C0 -:100F300086E0ACDE2091BD19822F022E000C990BA9 -:100F400097FF03C091958195910903970CF44AC0CE -:100F500027FF21C0D12F62E080E00F946E3288E637 -:100F600094E00F94103162E081E00F946E3281EFD3 -:100F70009FE50F94953163E080E00F946E3289E530 -:100F800096E00F94103163E081E00F946E3284EEAE -:100F90009FE50F9495318091BD1918160CF562E00C -:100FA00080E00F946E3289E596E00F94103162E094 -:100FB00081E00F946E3281EF9FE50F94953163E0ED -:100FC00080E00F946E3288E694E00F94103163E075 -:100FD00081E00F946E3284EE9FE50F949531DC2F03 -:100FE0001092BD190F94BC7D64E670E080E090E043 -:100FF00014DF0F946B30882309F493CF82E090E0E4 -:101000009093230280932202809101018062809359 -:1010100001019FB7F894809102018F7D80930201B6 -:101020009FBF8091010188608093010160E070E0C2 -:1010300086E02CDE1092BC191092BB190F94BC7D77 -:101040008D2FDF91CF911F9108952FB7F894609164 -:101050008719709188198091891990918A192FBFE9 -:1010600008956F927F928F929F92AF92BF92CF928C -:10107000DF92EF92FF920F931F93CF93DF93782E1F -:10108000692E162F6A0159010F9493077C01DDDF49 -:101090000091BD19E70184E6982E82E390E00F9459 -:1010A000BD120F94BC7D81E00F94680E8090BD1935 -:1010B000802F002E000C990B8819910987FC9395BD -:1010C00097FF03C0919581959109059764F1209749 -:1010D00009F064C063E080E00F946E32081584F478 -:1010E0001123F9F082EE9FE50F94953163E087E0DC -:1010F0000F946E3280EE9FE50F94953110E011C091 -:1011000080167CF411110DC08EED9FE50F94953182 -:1011100063E087E00F946E328CED9FE50F9495317C -:1011200011E00091BD190F946B30882319F02097BE -:10113000A9F538C09A949110B0CFE114F10441F0B0 -:10114000209711F4C72DD62DCE010F949307EC01F3 -:10115000209709F0A0CF63E080E00F946E32112356 -:1011600021F08AED9FE50F94953163E081E00F94C3 -:101170006E32C6010F94953163E087E00F946E32B2 -:10118000111104C088ED9FE50F94953163E088E06C -:101190000F946E32C5010F9495317DCFE114F104A7 -:1011A00099F679CF0F944E32812FDF91CF911F9115 -:1011B0000F91FF90EF90DF90CF90BF90AF909F90F6 -:1011C0008F907F906F9008951F920F920FB60F929D -:1011D00011242F933F938F939F93AF93BF9380914D -:1011E000871990918819A0918919B0918A19309125 -:1011F000BF1923E0230F2D3720F40196A11DB11D47 -:1012000005C026E8230F0296A11DB11D2093BF192A -:101210008093871990938819A0938919B0938A199C -:101220008091C0199091C119A091C219B091C319B0 -:101230000196A11DB11D8093C0199093C119A0936F -:10124000C219B093C319BF91AF919F918F913F91F4 -:101250002F910F900FBE0F901F9018950F944E2F47 -:101260001092B0198091B019843028F51092B219FB -:1012700083EF9FE20F94B23681111DC060EE71E0E2 -:101280008BE691E60F94DE36811115C064E771E0BC -:1012900085E691E60F94DE3681110DC00F940F2F75 -:1012A0008091B0198F5F8093B0198091B1198F5FD1 -:1012B0008093B119D7CF08951F93CF93DF931092E6 -:1012C000511684E69FE00F9463B3C82F85E69FE034 -:1012D0000F9463B3D82F86E69FE00F9463B3182F63 -:1012E00088E69FE00F9463B31F928F931F921F9322 -:1012F0001F92DF931F92CF938CEF90E69F938F9373 -:101300000F942A318DB79EB70A960FB6F8949EBFF8 -:101310000FBE8DBFDF91CF911F910D947830EF926A -:10132000FF920F931F93CF93DF93109251168FEF7D -:101330009EE00F9470B3EC0181E09FE00F9470B3D6 -:10134000182F092F85E09FE00F9470B3F82EE92E37 -:1013500083E09FE00F9470B39F938F93EF92FF927F -:101360000F931F93DF93CF9388E990E69F938F931A -:101370000F942A318DB79EB70A960FB6F8949EBF88 -:101380000FBE8DBFDF91CF911F910F91FF90EF9016 -:101390000D94783020917613309177134CE3429F6F -:1013A000C001439F900D11246091781370917913BF -:1013B000469F9001479F300D1124109251163F9384 -:1013C0002F939F938F9389E690E69F938F930F942B -:1013D0002A310F900F900F900F900F900F908091E7 -:1013E0007B13811140C080914002811105C08CE4C3 -:1013F00090E60F94953137C0809100079091FF06D9 -:10140000891B8F7071F48091801681110AC08091C0 -:101410003C07811106C0809101109091021008973D -:1014200021F58091CA191F928F938091C9191F923B -:101430008F938091C8198F938091C7198F93809152 -:10144000C6198F938091C5198F9385E290E69F937B -:101450008F930F942A318DB79EB70A960FB6F894E2 -:101460009EBF0FBE8DBF0D947E300E943B97D9CF9B -:101470000F930E94149A01E020E040E050E0BA018E -:1014800081EC9EEB0F94C32F1092C4190F91089515 -:10149000CF93DF9300D01F92CDB7DEB719821A82A7 -:1014A0001B821C82CE0101960F947F761092030D51 -:1014B0001092020D1092BC191092BB19D9DF0F9037 -:1014C0000F900F900F90DF91CF91089580EF90E0F3 -:1014D00090938A158093891580917B0E811106C0A7 -:1014E00082E390E09093030D8093020D1092BC195B -:1014F0001092BB19BDDF80917B0E882319F088E024 -:101500000C944CD908958CED90E090938A158093BB -:10151000891580917B0E811106C084E690E090933E -:10152000030D8093020D1092BC191092BB19A0DF1D -:1015300080917B0E882319F088E00C944CD9089593 -:1015400086EE90E090938A158093891580917B0EAA -:10155000811106C085E590E09093030D8093020D04 -:101560001092BC191092BB1983DF80917B0E8823E7 -:1015700019F088E00C944CD908958EEF90E0909388 -:101580008A158093891580917B0E811106C084E6AF -:1015900090E09093030D8093020D1092BC1910926D -:1015A000BB1966DF80917B0E882319F088E00C94CC -:1015B0004CD908958FEF90E090938A158093891508 -:1015C00080917B0E811106C084E690E09093030D1C -:1015D0008093020D1092BC191092BB1949DF8091C3 -:1015E0007B0E882319F088E00C944CD9089587ED80 -:1015F00090E090938A158093891580917B0E8111DC -:1016000006C08CE390E09093030D8093020D10923E -:10161000BC191092BB192CDF80917B0E882319F026 -:1016200088E00C944CD908958AEF90E090938A1545 -:10163000809389151092030D1092020D1092BC191F -:101640001092BB1915CF8AEF90E090938A15809382 -:1016500089158CE390E09093030D8093020D109216 -:10166000BC191092BB1904CFCF93DF9300D01F9207 -:10167000CDB7DEB7FDDE80913F0E811107C020E0BF -:1016800030E0A901CA01B9010E945CE819821A82FE -:101690001B821C82CE0101960F947F7681E080939D -:1016A0003A078091011090910210892B31F485E066 -:1016B00090E090930210809301100F900F900F9084 -:1016C0000F90DF91CF9108952F923F924F925F92AA -:1016D0006F927F928F929F92AF92BF92CF92DF9242 -:1016E000EF92FF920F931F93CF93DF93CDB7DEB7A7 -:1016F00060970FB6F894DEBF0FBECDBF7C011B0113 -:101700006A01FC0117821682838181FF44C39E0116 -:101710002F5F3F4F3901F7019381F10193FD8591CF -:1017200093FF81911F01882309F431C3853239F475 -:1017300093FD859193FF81911F01853239F4B701A3 -:1017400090E00F940EAD56016501E5CF10E0512CED -:10175000912CFFE1F915D8F08B3279F038F4803212 -:1017600079F08332A1F4F92DF0612EC08D3261F051 -:10177000803369F4292D21602DC0392D3260932EDC -:10178000892D8460982E2AC0E92DE86015C097FC49 -:101790002DC020ED280F2A3088F496FE06C03AE0CE -:1017A000139F200D1124122F19C08AE0589E200D7E -:1017B0001124522EE92DE0629E2E10C08E3231F49B -:1017C00096FCE5C2F92DF0649F2E08C08C3621F4FA -:1017D000292D2068922E02C0883641F4F10193FD34 -:1017E000859193FF81911F018111B3CF9BEB980FDE -:1017F000933020F4992D9061805E07C09BE9980F8B -:10180000933008F066C1992D9F7E96FF16E09F7376 -:10181000992E853619F49064992E08C0863621F4E5 -:10182000392F3068932E02C01111115097FE07C056 -:101830001C3350F444244394410E27E00BC018306D -:1018400038F027E017E005C027E09CE3492E02C0EE -:10185000212F412C560184E0A80EB11CF6016081B5 -:10186000718182819381042DA3010F944AAB6C0195 -:10187000F981FC87F0FF02C0F3FF06C091FC06C0AF -:1018800092FE06C000E205C00DE203C00BE201C0FB -:1018900000E08C858C7019F001115AC29BC297FE32 -:1018A00010C04C0CFC85F4FF04C08A81813309F41C -:1018B0004A94141474F528E0241578F588E0482E2D -:1018C0002CC096FC2AC0812F90E08C159D059CF0C1 -:1018D0003CEFC3163FEFD30674F0892D8068982E35 -:1018E0000AC0E2E0F0E0EC0FFD1FE10FF11D808186 -:1018F000803319F411501111F4CF97FE0EC0442417 -:101900004394410E812F90E0C816D9062CF41C197F -:1019100004C04424439401C010E097FE06C01C1488 -:101920001D0434F4C601019605C085E090E002C0B4 -:1019300081E090E001110196112331F0212F30E078 -:101940002F5F3F4F820F931F252D30E082179307A3 -:1019500014F4581A01C0512C892D897049F455206E -:1019600039F0B70180E290E00F940EAD5A94F7CFB2 -:10197000002329F0B701802F90E00F940EAD93FC67 -:1019800009C0552039F0B70180E390E00F940EAD07 -:101990005A94F7CF97FE4CC04601D7FE02C0812C67 -:1019A000912CC60188199909F301E80FF91FFE87E8 -:1019B000ED87960124193109388B2F87012F10E00C -:1019C0001195019511093FEF8316930629F4B7018C -:1019D0008EE290E00F940EADC814D9044CF08F85C0 -:1019E00098898815990524F4ED85FE85818101C0CB -:1019F00080E3F1E08F1A91082D853E852F5F3F4FE0 -:101A00003E872D87801691062CF0B70190E00F9449 -:101A10000EADD9CFC814D90441F49A81963320F47D -:101A2000953319F43C8534FF81E3B70190E04EC053 -:101A30008A81813319F09C859F7E9C87B70190E055 -:101A40000F940EAD111105C094FC18C085E690E00E -:101A500017C0B7018EE290E00F940EAD1E5F82E0DA -:101A600001E0080FF301E80FF11D8081B70190E05C -:101A70000F940EAD802F0113F3CFE6CF85E490E0F5 -:101A8000B7010F940EADD7FC06C0C114D10441F4C8 -:101A9000EC85E4FF05C0D194C194D1088DE201C06A -:101AA0008BE2B70190E00F940EAD80E32AE0C216FE -:101AB000D1042CF08F5FFAE0CF1AD108F7CFB7012D -:101AC00090E00F940EADB701C601C0960F940EAD15 -:101AD00054C1833631F0833779F0833509F056C02D -:101AE00020C0560132E0A30EB11CF601808189832B -:101AF00001E010E0630112C05601F2E0AF0EB11C2C -:101B0000F601C080D18096FE03C0612F70E002C054 -:101B10006FEF7FEFC6010F94A8AC8C01F92DFF7712 -:101B200014C0560122E0A20EB11CF601C080D18083 -:101B300096FE03C0612F70E002C06FEF7FEFC60119 -:101B40000F9483AC8C01F92DF0689F2EF3FD1AC021 -:101B5000852D90E008171907A8F4B70180E290E0FE -:101B60000F940EAD5A94F4CFF60197FC859197FE31 -:101B700081916F01B70190E00F940EAD51105A940E -:101B8000015011090115110579F7F7C0843611F0DC -:101B9000893661F5560197FE09C024E0A20EB11CFA -:101BA000F60160817181828193810AC0F2E0AF0EFB -:101BB000B11CF60160817181072E000C880B990B16 -:101BC000F92DFF769F2E97FF09C09095809570950F -:101BD00061957F4F8F4F9F4FF0689F2E2AE030E036 -:101BE000A3010F942AAEC82EC6183FC0092D853711 -:101BF00021F40F7E2AE030E01DC0097F8F3691F07E -:101C000018F4883559F0C3C0803719F0883711F0BF -:101C1000BEC0006104FF09C0046007C094FE08C094 -:101C2000066006C028E030E005C020E130E002C0D8 -:101C300020E132E0560107FF09C084E0A80EB11C84 -:101C4000F601608171818281938108C0F2E0AF0E5C -:101C5000B11CF6016081718180E090E0A3010F94D6 -:101C60002AAEC82EC6180F77902E96FE0BC0092DEF -:101C70000E7FC11650F494FE0AC092FC08C0092DD4 -:101C80000E7E05C0DC2C092D03C0DC2C01C0D12E3A -:101C900004FF0DC0FE01EC0DF11D8081803311F4B5 -:101CA000097E09C002FF06C0D394D39404C0802FDC -:101CB000867809F0D39403FD11C000FF06C01C2DE7 -:101CC000D51480F4150D1D190DC0D51458F4B701A5 -:101CD00080E290E00F940EADD394F7CFD51410F4BA -:101CE0005D1801C0512C04FF10C0B70180E390E0E3 -:101CF0000F940EAD02FF17C001FD03C088E790E00E -:101D000002C088E590E0B7010CC0802F867859F0BA -:101D100001FF02C08BE201C080E207FD8DE2B70146 -:101D200090E00F940EADC11638F4B70180E390E057 -:101D30000F940EAD1150F7CFCA94F301EC0DF11DC5 -:101D40008081B70190E00F940EADC110F5CF15C0A2 -:101D5000F4E0F51560F584E0581A93FE1FC00111F8 -:101D600027C02C8523FF2AC008E214E0392D3071EA -:101D7000932EF8018491811124C0552009F4E4CCFC -:101D8000B70180E290E00F940EAD5A94F6CFF701C0 -:101D90008681978126C08FEF9FEF23C0B70180E235 -:101DA00090E00F940EAD5A945110F8CFD8CF512C2B -:101DB000B701802F90E00F940EADD3CF0CE214E06A -:101DC000D5CF91108052B70190E00F940EAD0F5F08 -:101DD0001F4FCFCF23E0251510F483E0BDCF512C4A -:101DE000C0CF60960FB6F894DEBF0FBECDBFDF91B7 -:101DF000CF911F910F91FF90EF90DF90CF90BF9008 -:101E0000AF909F908F907F906F905F904F903F909A -:101E10002F900895CF93DF93CDB7DEB760970FB6BD -:101E2000F894DEBF0FBECDBF789484B5826084BDC8 -:101E300084B5816084BD85B5826085BD85B58160CE -:101E400085BD80916E00816080936E00109281004C -:101E50008091810082608093810080918100816007 -:101E600080938100809180008160809380008091C8 -:101E7000B10084608093B1008091B0008160809354 -:101E8000B0008091910082608093910080919100D8 -:101E90008160809391008091900081608093900098 -:101EA0008091A10082608093A1008091A100816057 -:101EB0008093A1008091A00081608093A000809118 -:101EC00021018260809321018091210181608093B2 -:101ED00021018091200181608093200180917A000E -:101EE000846080937A0080917A00826080937A0087 -:101EF00080917A00816080937A0080917A00806876 -:101F000080937A001092C10061E08CE40F94DC852C -:101F100061E08CE40F940A86809101018E7F8093AA -:101F20000101809102018160809302018AE0809327 -:101F3000B8061092B9061092BA068091D00082605D -:101F40008093D00080E18093D40088E18093D10019 -:101F50008091D10080688093D10081E29EEB9093C4 -:101F600019108093181088E09EEB90931B108093BB -:101F70001A1083E08093131010921D1010921C1001 -:101F80008FE39CE90197F1F700C000000F946026F1 -:101F90008FEF8093C60686ED9EE00F9463B38F3F6C -:101FA00019F41092E60606C091E0811101C090E09C -:101FB0009093E60682E580938F138FEF80938D13C5 -:101FC0008DE380938E138BE38093D50686E4809314 -:101FD000D60685E58093D70687E48093D8061092CD -:101FE000D9061092DA061092DB061092DC0661E048 -:101FF00082E50F940A8680918D138F3F19F061E07E -:102000000F940A8661E080918E130F940A861092D5 -:10201000921381E00F947F7980ED9BE99093D00635 -:102020008093CF061092D2061092D10682E0809360 -:10203000CA061092D4061092D3060E94149A88E41D -:1020400091E09093E5068093E40686E092E0909319 -:10205000E3068093E2068EE691E09093E10680939A -:10206000E00681EC9EEB9093DF068093DE060F94F2 -:10207000D14C809104018B7F8093040180910401F5 -:102080008D7F809304019FB7F8948091050184604F -:10209000809305019FBF9FB7F894809105018260EE -:1020A000809305019FBF809101018F7B8093010187 -:1020B0009FB7F894809102018064809302019FBFD2 -:1020C00060E08FE00F940A869FB7F8948091050135 -:1020D0008160809305019FBF80910301809581708D -:1020E0008093DD061092BD190F94292088ED93E1AD -:1020F0000F9495318091010184608093010187EDF7 -:102100009EE00F9463B390E09093020780930107E1 -:102110008F3F910549F4109202071092010760E089 -:1021200087ED9EE00F9475B30F946351811105C044 -:1021300060E08CE097E10F940A0E8091FB1F87FD11 -:1021400029C00F940E208091C00082608093C0004F -:1021500080E18093C40088E18093C1008091C00039 -:1021600087FF05C00F940E208091C600F7CF6DEC5D -:10217000E62E63E1F62E07EC13E1F80184910F944B -:1021800007200F5F1F4FE016F106B9F70F940E20DE -:102190000E94119884EC9FE00F9463B38093C80F62 -:1021A00069E277E081EC9FE00E949EFD2091C80FDC -:1021B0008091290790912A072F3F11F4009721F071 -:1021C0008F3FFFEF9F0711F41092C80F019621F483 -:1021D00010922A071092290788E09FE00F9463B3BA -:1021E00080938B158F3F11F410928B158091C80F3F -:1021F0008823A9F011E01093280788E0809327072F -:1022000060E088E090E00F94BE0210938B1584E2AA -:102210008093200280931C0280E00E942A9C0F94ED -:102220004E7682E89DEA90932207809321071092D0 -:1022300024071092230782E080931C071092260740 -:102240001092250789E197E09093D2198093D119D4 -:1022500006E91EE5F80184917801882341F00E9487 -:102260006EADFFEFEF1AFF0AF7018491F6CF89E513 -:1022700094E19F938F930F9493ADF4B60F900F90CA -:10228000F0FE04C084E097E10F94BBADF1FE04C002 -:1022900087EC97E10F94BBADF2FE04C086EB97E1AB -:1022A0000F94BBADF3FE04C086EA97E10F94BBAD7B -:1022B000F5FE04C086E997E10F94BBAD14BEF801AA -:1022C000849156E9E52E5EE5F52E882341F00E94C3 -:1022D0006EADFFEFEF1AFF0AF7018491F6CFE4EF3E -:1022E000F6E184917F01882341F00E946EADFFEFFB -:1022F000EF1AFF0AF7018491F6CFE4E4F4E1849148 -:102300007F01882341F00E946EADFFEFEF1AFF0AB4 -:10231000F7018491F6CFEAE8F7E184917F01882301 -:1023200041F00E946EADFFEFEF1AFF0AF7018491B2 -:10233000F6CFEDE2F4E184917F01882341F00E9421 -:102340006EADFFEFEF1AFF0AF7018491F6CF8AE036 -:102350000E946EADE2E2F4E184917F01882341F0B6 -:102360000E946EADFFEFEF1AFF0AF7018491F6CFDE -:10237000E6E1F4E184917F01882341F00E946EAD93 -:10238000FFEFEF1AFF0AF7018491F6CF8AE00E946F -:102390006EADF801849106E91EE5882339F00E94AC -:1023A0006EAD0F5F1F4FF8018491F7CFE5EEF6E1B8 -:1023B00084918F01882339F00E946EAD0F5F1F4F0B -:1023C000F8018491F7CF8091CB199091CC199E019F -:1023D0002F5F3F4F5901B901009719F0681B790B26 -:1023E00002C0675D7941072E000C880B990B0E9493 -:1023F000F7ADEEECF6E184918F01882339F00E946D -:102400006EAD0F5F1F4FF8018491F7CF60E775E065 -:1024100080E090E00E94F7AD8AE00E946EAD8EEE03 -:102420009EE00F9470B38C018CEE9EE00F9470B31D -:102430007C010C32F1E01F0709F48EC50F3F1F4FDE -:1024400039F46CE271E08EEE9EE00F94A1B384C586 -:1024500002E08633914089F0EF20E09439F466E39E -:1024600071E08CEE9EE00F94A1B301C0016001FD0C -:1024700004C00E9420AF782E03C00E94EAAE712CE7 -:1024800082EA92EAA0E0B0E08093D7199093D8193D -:10249000A093D919B093DA191092FB061092FC069A -:1024A0001092FD061092FE062091E5103091E61084 -:1024B0004091E7105091E81060E070E08FE793E4FE -:1024C0000F94DDB46093F7067093F8068093F906D5 -:1024D0009093FA061092F3061092F4061092F50605 -:1024E0001092F6062091F1103091F2104091F31005 -:1024F0005091F41060E070E08FE793E40F94DDB446 -:102500006093EF067093F0068093F1069093F206C5 -:102510006D9A9D9A809101018860809301018EECF3 -:1025200093E19F938F930F9493AD1092E8061092CE -:10253000E70680917A00876080937A0080917C0022 -:10254000806480937C0080917A00806880937A0018 -:102550008FE580937E0082E080937D000E94A3DC63 -:1025600080E888BD80916E00846080936E006AEF81 -:1025700070E080E090E00F940D878FE090E0909302 -:10258000EE068093ED060F900F90E0900702F0901A -:10259000080260E0C7010F940C3A20E030E040E709 -:1025A00051E40F9488AE87FF08C080E1E81AF10873 -:1025B000F0920802E0920702E8CF81E391E0909365 -:1025C0000A0280930902E090EB06F090EC0660E0CE -:1025D000C7010F940C3A20E030E848E953E40F9427 -:1025E0003AB6181644F490E1E90EF11CF092EC06AC -:1025F000E092EB06E8CFE0900502F0900602C701FA -:102600000F94C14020E030E040E751E40F9488AEE1 -:1026100087FF08C0A0E1EA1AF108F0920602E092F2 -:102620000502E9CFE090E906F090EA06C7010F94B1 -:10263000C14020E030E04AEF52E40F943AB6181659 -:1026400044F4B0E1EB0EF11CF092EA06E092E906E8 -:10265000E9CF88ED93E10F94953110920007109225 -:10266000FF0680E1E9E6F0E1DF01282F1D922A95BF -:10267000E9F7E9E5F0E1DF011D928A95E9F71092AB -:102680004510109246101092471010924810109268 -:10269000491010924A1010924B1010924C10109248 -:1026A0004D1010924E1010924F1010925010109228 -:1026B0005110109252101092531010925410109208 -:1026C000551010925610109257101092581084E026 -:1026D00090E090932302809322028091000186FD76 -:1026E000FAC0BFEFE3EDF0E3B150E040F040E1F7B6 -:1026F00000C000008091000186FDEDC00F941D37E1 -:1027000088E094E10F949531809101018460809379 -:1027100001018091010790910207029740F49FB751 -:10272000F894809102018460809302019FBF8091A0 -:10273000000186FFFCCF9FB7F894809102018B7F48 -:10274000809302019FBF2FEF37EA81E6215030408E -:102750008040E1F700C0000087EC94E09A83898311 -:1027600080ED94E09C838B838BED94E09E838D833E -:1027700089EE94E098878F83E090BD190E2C000CB1 -:10278000FF080F941D3760E080E00F946E3288E6FA -:1027900094E00F94103110E0C12CD12C6C2D81E00D -:1027A0000F946E32E0913F07F0914007EC0DFD1D54 -:1027B000EE0FFF1FEA0DFB1D808191810F941031F8 -:1027C0009FEFC91AD90AA4E0CA16D10439F70F94A9 -:1027D000BC7D81E00F94680E8091BD19082E000C1D -:1027E000990B9701281B390B37FF03C031952195B1 -:1027F0003109253031050CF45FC08E159F050CF4AE -:102800001150E816F90624F41F5F14301CF421C09F -:10281000143074F080913F079091400797FFA4C354 -:1028200001969093400780933F070F941D379CC3F8 -:102830001F3F79F480913F079091400718161906C1 -:102840003CF401979093400780933F070F941D3706 -:1028500010E060E080E00F946E3289E596E00F941E -:10286000103161E080E00F946E3289E596E00F94BC -:10287000103162E080E00F946E3289E596E00F94AB -:10288000103163E080E00F946E3289E596E00F949A -:102890001031612F80E00F946E3288E694E00F943F -:1028A0001031E090BD190E2C000CFF0864E670E0BA -:1028B00080E090E00F940D870F946B30882309F42B -:1028C0006BCF80913F070FB6F894DEBF0FBECDBF30 -:1028D000810F0E949FA982E090E090932302809351 -:1028E00022021092BD198FEF9FE00F9463B3182F4F -:1028F0008F3F09F410E01092180789E69FE00F94CB -:1029000063B3882391F08091C80F81110EC0FF241A -:10291000F394F0920C026FEF89E69FE00F9475B389 -:10292000F0920B0285E797E104C00E949DA780E624 -:1029300097E10F94BBAD87EF9EE00F9463B3D82E61 -:102940008093140786EF9EE00F9463B3E82E809384 -:10295000150785EF9EE00F9463B3F82E809316075A -:1029600084EF9EE00F9463B380931707BFEFDB12F1 -:1029700002C010921407EFEFEE1202C0109215077A -:10298000FFEFFF1202C0109216078F3F11F4109252 -:10299000170780E190E00E94BEC6809310078093E5 -:1029A00011078093120780E290E00E94BEC68093D8 -:1029B00013070F948B380F94D38280910A018160A2 -:1029C00080930A0180910A01826080930A018091BC -:1029D0000A01846080930A0180910A0180648093D7 -:1029E0000A010F9A179A0E9A169A0D9A159A0C9A2E -:1029F000149A809107018B7F809307019FB7F89409 -:102A0000809108018460809308019FBF8091070135 -:102A10008F77809307019FB7F894809108018068B1 -:102A2000809308019FBF809107018F7B80930701EE -:102A30009FB7F894809108018064809308019FBF3C -:102A400080910701877F809307019FB7F894809159 -:102A500008018860809308019FBF26982E9A2598C8 -:102A60002D9A24982C9A809107018B7F80930701DF -:102A70009FB7F894809108018460809308019FBFFC -:102A8000809107018F77809307019FB7F894809119 -:102A900008018068809308019FBF0998119A6E9879 -:102AA000389A4098179A1092FF0C399A4198169AC2 -:102AB0001092000D3A9A42983B9A4398149A80914A -:102AC00081008F7E80938100809181008860809357 -:102AD0008100809180008D7F8093800080918000B4 -:102AE0008E7F80938000809180008F738093800020 -:102AF000809180008F7C8093800080918100887F0E -:102B000082608093810080E090E4909389008093BC -:102B10008800109285001092840080916F0082607E -:102B200080936F0010920607109205071092040719 -:102B30001092030781E0809321027894111101C063 -:102B400080E0809318070E94B9BD0F948B380F94D2 -:102B5000C32C0E94A99E9FB7F89480910B018460BA -:102B600080930B019FBF82E00E94C8C608967C013B -:102B700034E0F694E7943A95E1F7E114F10491F02A -:102B8000429A62E070E080E090E00F940D874298F6 -:102B900062E070E080E090E00F940D8721E0E21A9F -:102BA000F108EBCF159884EC9FE00F9463B380930A -:102BB000C80F69E277E081EC9FE00E949EFD2091C2 -:102BC000C80F8091290790912A072F3F11F4009791 -:102BD00021F08F3F3FEF930711F41092C80F019639 -:102BE00021F410922A07109229078091C80F882398 -:102BF00029F060E088E090E00F94BE028BEB9FE04C -:102C00000F9463B391E0813009F090E090938718BE -:102C10008CEF9FE00F946BB36F3F7F4F8F4F9F4FB1 -:102C2000A9F488EF9FE00F946BB36F3F7F4F8F4FF6 -:102C30009F4F61F460E08FEF9FE00F9493B3109289 -:102C4000180761E08FE59FE00F9493B30F94BB48A2 -:102C500084E69FE00F9463B38F3F29F460E084E63D -:102C60009FE00F9493B386E69FE00F9463B38F3F8A -:102C700029F460E086E69FE00F9493B388E69FE036 -:102C80000F9463B38F3F29F460E088E69FE00F94D0 -:102C900093B385E69FE00F9463B38F3F29F460E020 -:102CA00085E69FE00F9493B38FEF9EE00F9470B38F -:102CB000019631F460E070E08FEF9EE00F94A1B3D5 -:102CC00085E09FE00F9470B3019631F460E070E00E -:102CD00085E09FE00F94A1B383E09FE00F9470B371 -:102CE000019631F460E070E083E09FE00F94A1B3BF -:102CF00081E09FE00F9470B3019631F460E070E0E2 -:102D000081E09FE00F94A1B38FEA9FE00F9463B33B -:102D10008F3F41F460E08FEA9FE00F9493B31092ED -:102D20000F0706C091E0811101C090E090930F075A -:102D300086EA9FE00F9463B38F3F01F561E086EA76 -:102D40009FE00F9493B31A82198220EBE22E2FE0BA -:102D5000F22EBE016F5F7F4FC7010E94B8FDB2E047 -:102D6000EB0EF11CEAEBEE16EFE0FE0691F760E0E9 -:102D70008FEA9FE00F9493B310920F0785EA9FE0CC -:102D80000F9463B38F3F29F460E085EA9FE00F94CE -:102D900093B389E09FE00F9463B38F3F29F460E021 -:102DA00089E09FE00F9493B30F949E0C6C987498F5 -:102DB00080916A00816080936A0080916A008D7FB3 -:102DC00080936A00EC9A6F98779880916A008F7B65 -:102DD00080936A0080916A00806880936A00EF9A0D -:102DE00061E08BE40F940A8660E08BE40F94DC854D -:102DF0001092070780916C00806280936C00D99AD2 -:102E00008091680082608093680061E172E087EAE7 -:102E10009FE00E949EFD63E172E089EA9FE00E94CC -:102E20009EFD65E172E08BEA9FE00E949EFD67E1F6 -:102E300072E08DEA9FE00E949EFD84E090E0909316 -:102E400023028093220281E00F942737023049F059 -:102E5000033081F00130F1F48BEA96E10F944108E0 -:102E600013C08CE896E10F9441086CE271E08EEE9D -:102E70009EE00EC083E596E10F9441086CE271E09C -:102E80008EEE9EE00F94A1B366E371E08CEE9EE0BF -:102E90000F94A1B3711006C089E196E10F94410827 -:102EA0000E9491B08FE59FE00F9463B3813019F4D5 -:102EB00080E00E944CD98FE59FE00F9463B38111AD -:102EC00013C00E94C6AC8F3F09F450C0882309F498 -:102ED0004DC08A3F09F055C049C0813009F05EC03D -:102EE00080910F07811155C088E0E3ECF2E0DE012C -:102EF000119601900D928A95E1F78AE090E00F9487 -:102F000070B36C019A8789878CE090E00F9470B35E -:102F10007C019C878B878EE090E00F9470B38C01CE -:102F20009E878D8780E190E00F9470B3988B8F8798 -:102F3000FE013196DE011996BD01419151912D910D -:102F40003D9124173507A0F14217530708F47BC3BE -:102F5000E617F70791F777C300E026E3E21621E0D2 -:102F6000F20609F079CA85CA13E073CC60E070E01C -:102F700088EF9FE00F948FB38BEA95E10F9441089F -:102F8000B3CF863E09F0A9CF87E59AE10F944108B7 -:102F90000BC00E9490A98111A7CF06C0803F09F005 -:102FA000A3CF85E395E1EACF81E00F9427379CCF4B -:102FB000F3E0CF16D10409F44CC30E94C6AC8F3F96 -:102FC00009F01DC383E090E09093230280932202D6 -:102FD00081E00F9427370F941D3782E00F94932FD1 -:102FE0000F9481518EEF9EE00F9463B3082F80936E -:102FF0000D078DEF9EE00F9463B3182F80930F029F -:103000008CEF9EE00F9463B380930D020F3F11F499 -:1030100010920D071F3F19F490E390930F028F3F1A -:1030200019F480E380930D028BEF9EE00F9463B35D -:10303000082F80930E078AEF9EE00F9463B3182F3A -:103040008093100289EF9EE00F9463B380930E0289 -:103050000F3F11F410920E071F3F19F490E3909365 -:1030600010028F3F19F480E380930E0288EF9EE0F8 -:103070000F9463B380930C078F3F11F410920C07E9 -:1030800085EA9FE00F9463B3882309F43FC00F944F -:10309000BC7DC0900807D0900907E0900A07F09027 -:1030A0000B078BE89FE00F9463B3682F70E080E01C -:1030B00090E00F948CAE20E030E040EA50E40F94B2 -:1030C000EEB39B01AC01C701B6010F943AB61816D6 -:1030D00014F481E009C040E060E083ED94E10F94D6 -:1030E000A007882321F080E00E94B6EA0FC060E0CC -:1030F00085EA9FE00F9475B381E00F94273782E053 -:103100000F94932F8FEB94E10F94EE5198E288E1A6 -:103110000FB6F894A895809360000FBE909360005E -:103120001E01F5E02F0E311C44244394512C80E005 -:10313000682E80E0782E5092230240922202009165 -:103140003D0710913E070115110551F10F94258897 -:10315000C0908207D0908307E0908407F0908507A5 -:10316000DC01CB018C199D09AE09BF09893E934052 -:10317000A105B105B8F031E030933C0701501109C9 -:1031800010933E0700933D070F94258860938207B4 -:10319000709383078093840790938507012B11F424 -:1031A00010923C0780913B07882309F499C019824B -:1031B0001A821B821C82CE0101960F947F76109298 -:1031C000030D1092020D0F941D378AE694E10F94BF -:1031D00095318E010F5F1F4F0E94CAAC8F3F3FEFAA -:1031E0009307D1F3D8018D938D01A215B305A1F7F3 -:1031F00089809A80AB80BC808BE20E946EADC12C2E -:10320000D12C760180913B07882309F456C101E453 -:1032100017E08C149D04AE04BF0499F00E94CAAC60 -:103220008F3FBFEF9B07D1F3EFEFCE1ADE0AEE0A16 -:10323000FE0AD8018D938D01B7E001381B0749F7CD -:1032400002C07501640160E470E081E497E00F94CE -:10325000164A8091A618882309F1E4E7FEE58491D7 -:103260008F01882339F00E946EAD0F5F1F4FF80168 -:103270008491F7CFE8E3F7E184918F01882339F057 -:103280000E946EAD0F5F1F4FF8018491F7CF8AE067 -:103290000E946EAD82EF94E00E94A7AE8BE20E9486 -:1032A0006EAD0F94BC7DC814D904EA04FB0409F088 -:1032B000A9CF0F94BF660F94375710923B07E7EDE5 -:1032C000F7E184918F01882339F00E946EAD0F5F82 -:1032D0001F4FF8018491F7CF8AE00E946EAD92CF24 -:1032E0000E94F4A080915F198823F1F0C0905719D3 -:1032F000D0905819E0905919F0905A190F942588D8 -:10330000C616D706E806F90678F010925F19809184 -:103310008116882319F00F940E7A06C00F94BB48CB -:10332000809181168111F7CF809198139091991314 -:10333000892B09F4C2C01092971380917E168823BE -:1033400009F469C0009187151091881503561C4E29 -:103350006BEB74E1C8010F948EAC892B09F06FC040 -:10336000F80101900020E9F79F012250310979010D -:103370001092A6186EE470E0C8010F9433B96C0186 -:10338000009771F060E270E00F9433B98C010F5F29 -:103390001F4F6AE270E0C6010F9433B901977C01B8 -:1033A0008DE0D70111968C9311978AE012968C9339 -:1033B000129713961C92F80101900020E9F73197BB -:1033C000BF01601B710BC8010F94164A8091A618AB -:1033D0008823E9F0E4E7FEE584918F01882339F042 -:1033E0000E946EAD0F5F1F4FF8018491F7CFE8E3A5 -:1033F000F7E184918F01882339F00E946EAD0F5F51 -:103400001F4FF8018491F7CF8AE00E946EAD809142 -:103410007F16882319F00E94F03020C0EDE5F7E117 -:1034200084918F01882339F00E946EAD0F5F1F4F8A -:10343000F8018491F7CF8AE00E946EAD0FC00F941F -:103440003757E7EDF7E184918F018823A1F30E94BC -:103450006EAD0F5F1F4FF8018491F7CF80919713E6 -:10346000811125C08091981390919913892BF9F0BF -:10347000E0918715F0918815E656FC4E80818230E8 -:1034800031F4F89485E08083818192810BC086308D -:1034900061F480918016811108C0F89485E08083E2 -:1034A00081E090E00E945EBD78940E943CDC8091B7 -:1034B000C80F811102C00E94CDE90F94BC7D80919C -:1034C0003A07882311F081E001C080E00F94680E74 -:1034D0008091380781119CC080913707811198C075 -:1034E0008091DA0F811194C063C0809138078823DE -:1034F000D1F060912B0770912C0780912D0790914E -:103500002E070F948EAE20917D1030917E10409149 -:103510007F10509180100F94DDB4AB01BC0186E8A0 -:1035200094E10E9489AE809137078823D1F06091A1 -:103530002F077091300780913107909132070F94D7 -:103540008EAE209181103091821040918310509165 -:1035500084100F94DDB4AB01BC0182E894E10E94B9 -:1035600089AE8091DA0F8823D1F060913307709192 -:10357000340780913507909136070F948EAE2091D5 -:1035800085103091861040918710509188100F94CB -:10359000DDB4AB01BC018EE794E10E9489AE8AE004 -:1035A0000E946EAD10923807109237071092DA0F12 -:1035B00080E00F94932F0E94AEC780913907882333 -:1035C000A9F010923907823041F0833051F08130F8 -:1035D00069F461E08BEA94E107C061E08BE994E172 -:1035E00003C061E08AE894E10E9465DB0F947A26CB -:1035F0006114710409F49FCD0E94000098CD85EFFD -:1036000094E10F9441080F9481510F948C72DACC9D -:10361000E6E9FEE584918F01882339F00E946EADC2 -:103620000F5F1F4FF8018491F7CFEEE4F7E184912B -:103630008F01882309F459CF0E946EAD0F5F1F4F91 -:10364000F8018491F6CF23E0C216D10409F0BACC78 -:1036500006C032E0E316F10409F0AFCC0AC0A2E0E4 -:10366000EA16F10409F0AECC012B09F0ABCC20E056 -:1036700004C0012B09F0A1CC21E0039709F49DCCF3 -:10368000222309F49FCC99CC6091D1197091D21961 -:1036900090E08A3018F0895A9F4F01C0C0960D946F -:1036A0000EAD0F931F93CF93DF9300912B0D1091CD -:1036B0002C0D65E470E0C8010F9433B9EC01892B3F -:1036C00051F460E070E0C8010196DF91CF911F9145 -:1036D0000F910D94C9A8188280912B0D90912C0DFB -:1036E00060E070E001960F94C9A825E42883DF917B -:1036F000CF911F910F91089580912B0D90912C0DDA -:103700004AE050E060E070E001960D941DAA8091BF -:103710002B0D90912C0D60E070E001960D94C9A8DE -:10372000682F880F770B80918715909188158356A5 -:103730009C4E0F9433B99C0190932C0D80932B0DCC -:1037400081E0232B09F480E00895CF93C82F829560 -:103750008F709ADF8C2F8F70CF9196CF262F482FA6 -:1037600050E0FA01E75EFD4F6083DA01A35EBD4FD2 -:10377000FA01E05FF84F4C9160810C94E1C6462F4E -:10378000282F30E0F901E35EFD4F6083D901A75E89 -:10379000BD4FF901E05FF84F2C9160810C94E1C6B8 -:1037A000CF93DF9386EA98E10E94BDA78CE097E172 -:1037B000892B51F481EF96E10E94BDA784ED96E13B -:1037C000DF91CF910C94BDA7CFEFD7E1CE010E943E -:1037D000BDA76B9786E1C13FD807C1F7EBCF8F92AA -:1037E0009F92AF92BF92CF92DF92EF92FF920F9390 -:1037F0001F93CF93DF93C5E3D0E120E030E04CE8A6 -:1038000052E46C857D858E859F850F94EFB36C8720 -:103810007D878E879F87E884F9840A851B852C81A4 -:103820003D814E815F81688179818A819B81EEEF44 -:10383000FCE0FF93EF93812C912CE0EAAE2EE1E4C3 -:10384000BE2EF1E4CF2EF0E1DF2E0E9451870E94C0 -:103850006EEA0F941D3760E080E00F946E3282ECC8 -:1038600091E30F94953162E080E00F946E3286E729 -:1038700099E40F94953183E49BE210D00F900F9060 -:10388000DF91CF911F910F91FF90EF90DF90CF903C -:10389000BF90AF909F908F900D949883EF92FF927E -:1038A0000F931F93CF9364E670E00F948DB87B0164 -:1038B000C0E063E08C2F0F946E3287E195E00F94A7 -:1038C000103105E010E0C7010F94BD12015011093D -:1038D000D1F7CF5FC43169F7CF911F910F91FF905E -:1038E000EF9008954F925F926F927F928F929F9286 -:1038F000AF92BF92CF92DF92EF92FF920F931F93FE -:10390000CF938C010F94258828EE33E040E050E0FF -:103910000F94B3B369017A0184E090E0909323029D -:103920008093220288EE882E83E0982EA12CB12C61 -:103930002801612C712C0F94BC7D81E00F94680EDE -:103940000F942588A50194010F94B3B3DA01C9013E -:103950008C199D09AE09BF09481659066A067B06EF -:1039600020F4C1E00115110509F4C0E00F946B309B -:103970008823C1F082E090E090932302809322029A -:1039800081E08C27CF911F910F91FF90EF90DF90F6 -:10399000CF90BF90AF909F908F907F906F905F90EF -:1039A0004F900895CC2339F2E5CFCF93DF93109257 -:1039B000410E1092400E179A1092FF0C169A109218 -:1039C000000D149A1092030D1092020D8823E9F055 -:1039D00061E086EA9FE00F9475B3EAECF4E4849129 -:1039E000EF01882331F00E946EAD2196FE01849193 -:1039F000F8CF8AE00E946EAD83E595E40F9441080C -:103A000081E080930F0761E01BC060E086EA9FE0E1 -:103A10000F9475B3E9E8F4E48491EF01882331F061 -:103A20000E946EAD2196FE018491F8CF8AE00E943B -:103A30006EAD84E395E40F94410810920F0760E0A7 -:103A40008FEA9FE00F9475B381E00F94273782E0EF -:103A5000DF91CF910D94932FCF92DF92EF92FF924F -:103A6000CF93DF93EC01BC016C5F7F4F0E946BA88A -:103A700020E030E0A90160916E0270916F028091A8 -:103A80007002909171020F94EFB36B017C019B0166 -:103A9000AC01688579858A859B850F9488AE87FF00 -:103AA00004C0C886D986EA86FB86C0906202D090A0 -:103AB0006302E0906402F0906502A70196016885B8 -:103AC00079858A859B850F943AB6181624F4C886A2 -:103AD000D986EA86FB86DF91CF91FF90EF90DF9049 -:103AE000CF9008952F923F924F925F926F927F9264 -:103AF0008F929F92AF92BF92CF92DF92EF92FF92FE -:103B00000F931F93CF93DF93CDB7DEB7C354D10983 -:103B10000FB6F894DEBF0FBECDBF382EC0900C0F8D -:103B2000D0900D0FE0900E0FF0900F0F8090080FC7 -:103B30009090090FA0900A0FB0900B0FA70196016B -:103B4000C501B4010F944BB668AB79AB8AAB9BABA4 -:103B5000009143021091440280917E0290917F0275 -:103B6000A0918002B091810224968CAF9DAFAEAF40 -:103B7000BFAF24978091FE0C898B80913510909176 -:103B80003610A0913710B0913810888F998FAA8F76 -:103B9000BB8F9C01AD01C501B4010F94EFB36CABB9 -:103BA0007DAB8EAB9FAB8091391090913A10A09174 -:103BB0003B10B0913C1088A399A3AAA3BBA39C017E -:103BC000AD01C701B6010F94EFB368AF79AF8AAF0B -:103BD0009BAF80913D1090913E10A0913F10B0910D -:103BE00040108CAF9DAFAEAFBFAF9C01AD016091F7 -:103BF000D10F7091D20F8091D30F9091D40F0F9469 -:103C0000EEB368A779A78AA79BA7D501C401B058CE -:103C10008C8F9D8FAE8FBF8FD701C601B0588C8B14 -:103C20009D8BAE8BBF8B8091C90F9091CA0FA091D5 -:103C3000CB0FB091CC0F8CA39DA3AEA3BFA32CA997 -:103C40003DA94EA95FA9BC01CD010F94EEB36B0154 -:103C50007C018091CD0F9091CE0FA091CF0FB091AC -:103C6000D00F8CA79DA7AEA7BFA728AD39AD4AAD91 -:103C70005BADBC01CD010F94EEB34B015C01A7011C -:103C800096016C8D7D8D8E8D9F8D0F94F5A72B01E8 -:103C90003C01A50194016C897D898E899F890F94CF -:103CA000F5A79B01AC01C301B2010F94EFB32B0147 -:103CB0003C01A50194016C8D7D8D8E8D9F8D0F949F -:103CC000F5A74B015C01A70196016C897D898E895E -:103CD0009F890F94F5A79B01AC01C501B4010F9416 -:103CE000EEB3A30192010F946DB46B017C0120E04F -:103CF00030E0A9010F9488AE87FF0AC02BED3FE0AA -:103D000049EC50E4C701B6010F94EFB36B017C019D -:103D1000332051F02BED3FE049EC50E4C701B601F0 -:103D20000F94EEB36B017C012CA13DA14EA15FA1CC -:103D3000688D798D8A8D9B8D0F9488AE81111FC0FF -:103D40002CA53DA54EA55FA568A179A18AA19BA13F -:103D50000F9488AE811113C020E030E0A901C701A3 -:103D6000B6010F9488AE81110AC02BED3FE049ECFB -:103D700050E4C701B6010F94EFB36B017C01A701BA -:103D8000960168A979A98AA99BA90F94F5A728A5E6 -:103D900039A54AA55BA55F770F944BB64B015C0133 -:103DA0002FE632E143E85AE30F9488AE87FDCDC198 -:103DB000C501B4010F9483B50F9454B579A368A3DA -:103DC000DB01AB2B21F4E1E0F0E0F9A3E8A3B801BB -:103DD000110F880B990B0F948EAE24962CAD3DAD30 -:103DE0004EAD5FAD24970F94F5A720E030E040E79B -:103DF00052E40F94DDB420E030E048EC52E40F943C -:103E0000DDB46CA37DA38EA39FA34090411050907E -:103E10004210609043107090441028A139A1B9015C -:103E200080E090E00F948CAE4B015C019B01AC01F3 -:103E3000C701B6010F94DDB4688F798F8A8F9B8F8D -:103E4000A501940168A579A58AA59BA50F94DDB469 -:103E50006CA77DA78EA79FA7A30192016091D50FA4 -:103E60007091D60F8091D70F9091D80F0F94EEB329 -:103E7000A50194010F94DDB468AB79AB8AAB9BAB21 -:103E800020E030E040E05FE3688D798D8A8D9B8D86 -:103E90000F94F5A7288D398D4A8D5B8D0F94F5A76A -:103EA0009B01AC0160E070E080E89FE30F94EEB30B -:103EB00068A779A78AA79BA78CAD9DADAEADBFAD16 -:103EC00089879A87AB87BC874D865E866F86788A9E -:103ED000712C22242394312CDE015196BB8BAA8BAA -:103EE000E8A1F9A1E215F30509F407C1F8E1F71516 -:103EF0000CF444C02C893D894E895F8968A579A559 -:103F00008AA59BA50F94F5A76B017C012C8D3D8D97 -:103F10004E8D5F8D688D798D8A8D9B8D0F94F5A761 -:103F2000A70196010F94EFB35B018C012C8D3D8DA1 -:103F30004E8D5F8D68A579A58AA59BA50F94F5A7E1 -:103F40006B017C012C893D894E895F89688D798D53 -:103F50008A8D9B8D0F94F5A79B01AC01C701B6011B -:103F60000F94EEB36C8F7D8F8E8F9F8F739465014E -:103F70007801CC8ADD8AEE8AFF8A65C0B10180E0D3 -:103F800090E00F948CAE288D398D4A8D5B8D0F9407 -:103F9000F5A76B017C010F94DAB42B013C01C7013A -:103FA000B6010F9468B74B015C01C090080FD09028 -:103FB000090FE0900A0FF0900B0FF7FAF094F7F862 -:103FC000F09480910C0F90910D0FA0910E0FB09175 -:103FD0000F0F8C8B9D8BAE8BBF8BA7019601C301FE -:103FE000B2010F94F5A76C8F7D8F8E8F9F8F2C89D8 -:103FF0003D894E895F89C501B401F7D79B01AC01AA -:104000006C8D7D8D8E8D9F8D0F94EFB36C8F7D8F1A -:104010008E8F9F8FA7019601C501B401E6D76B0172 -:104020007C012C893D894E895F89C301B201DDD7AE -:104030009B01AC01C701B6010F94EEB36C8B7D8B75 -:104040008E8B9F8B712C2C8D3D8D4E8D5F8D6CA931 -:104050007DA98EA99FA90F94EFB369837A838B837F -:104060009C832C893D894E895F8968AD79AD8AAD85 -:104070009BAD0F94EFB36D837E838F8398872CA5C0 -:104080003DA54EA55FA569857A858B859C850F9496 -:10409000EFB369877A878B879C8728A939A94AA9B2 -:1040A0005BA96D857E858F8598890F94EFB36D87A9 -:1040B0007E878F87988BCE010196CEDCE984FA84C7 -:1040C0000B851C852D813E814F81588569817A81C0 -:1040D0008B819C81AB89AF93BA89BF938CA09DA043 -:1040E000AEA0BFA0FE013D966F010E945187FFEF79 -:1040F0002F1A3F0A0F900F90F3CEE090D10FF0905F -:10410000D20F0091D30F1091D40F2091CD0F309189 -:10411000CE0F4091CF0F5091D00F6091C90F709189 -:10412000CA0F8091CB0F9091CC0FFE017196FF9337 -:10413000EF938CA09DA0AEA0BFA0E5EDCE2EEFE04A -:10414000DE2E0E9451870F900F90E9ECFFE0A5E36F -:10415000B0E189ED9FE041915191619171914D9351 -:104160005D936D937D938E179F07A9F70F94258814 -:104170006093FF0E7093000F8093010F9093020FD6 -:10418000CD5BDF4F0FB6F894DEBF0FBECDBFDF9122 -:10419000CF911F910F91FF90EF90DF90CF90BF9044 -:1041A000AF909F908F907F906F905F904F903F90D7 -:1041B0002F9008952F923F924F925F926F927F922D -:1041C0008F929F92AF92BF92CF92DF92EF92FF9227 -:1041D0000F931F93CF93DF93CDB7DEB7A5970FB69D -:1041E000F894DEBF0FBECDBF89EC9FE035DC0F94A5 -:1041F00025886093FF0E7093000F8093010F9093BA -:10420000020FC0903510D0903610E0903710F0902B -:1042100038104090C90F5090CA0F6090CB0F70902B -:10422000CC0FA3019201C701B6010F9488AE811192 -:1042300043C08091CD0F9091CE0FA091CF0FB09140 -:10424000D00F88879987AA87BB879C01AD016091B1 -:10425000391070913A1080913B1090913C100F945E -:1042600088AE811129C020E030E040E752E460913F -:104270007E0270917F0280918002909181020F9462 -:10428000DDB44B015C01E090D10FF090D20F0091B2 -:10429000D30F1091D40F8EEF9CE09F938F93F5ED89 -:1042A000CF2EFFE0DF2E288539854A855B85C30147 -:1042B000B2010E9451879FC06091430270914402F5 -:1042C000072E000C880B990B0F948EAE20917E0266 -:1042D00030917F02409180025091810286D62EE378 -:1042E00033EC4EE259E381D66E877F87888B998BBA -:1042F0008091FE0C8D8320913D1030913E104091B5 -:104300003F10509140106091D10F7091D20F809169 -:10431000D30F9091D40F0F94EEB36A8B7B8B8C8B61 -:104320009D8B80918C15811169C0E090D10FF09028 -:10433000D20F0091D30F1091D40F2091CD0F309157 -:10434000CE0F4091CF0F5091D00F6091C90F709157 -:10435000CA0F8091CB0F9091CC0FFE013596FF9341 -:10436000EF938E849F84A888B988E5EDCE2EEFE088 -:10437000DE2E0E9451878091C90F9091CA0FA091A3 -:10438000CB0FB091CC0F8093351090933610A09343 -:104390003710B09338108091CD0F9091CE0FA0912F -:1043A000CF0FB091D00F8093391090933A10A09313 -:1043B0003B10B0933C108091D10F9091D20FA091FF -:1043C000D30FB091D40F80933D1090933E10A093E3 -:1043D0003F10B09340108091D50F9091D60FA091CF -:1043E000D70FB091D80F8093411090934210A093B3 -:1043F0004310B09344100F900F900FC1A701960186 -:10440000C301B2010F94EEB32B013C0120E030E078 -:10441000A9010F943AB673016201181624F0F7FA55 -:10442000F094F7F8F0942091391030913A104091BF -:104430003B1050913C106091CD0F7091CE0F809148 -:10444000CF0F9091D00F0F94EEB3688779878A874A -:104450009B8720E030E0A9010F943AB62885398582 -:104460004A855B8518160CF05058C701B6010F94A9 -:10447000EFB36B017C0120E030E0A9010F943AB664 -:1044800018160CF052CF20E030E040EF51E4C701A5 -:10449000B6010F94DDB40F94C6B40F944EB57D876A -:1044A0006C87623071050CF440CF2091411030913F -:1044B000421040914310509144106091D50F70917B -:1044C000D60F8091D70F9091D80F0F94EEB36E8BCB -:1044D0007F8B888F998F22242394312C8C859D8506 -:1044E000092E000CAA0BBB0B8AA39BA3ACA3BDA3F4 -:1044F000DE011596BF83AE83B101032C000C880B3F -:10450000990B0F948EAE6B017C016AA17BA18CA1EB -:104510009DA10F948EAE9B01AC01C701B6010F9413 -:10452000DDB46B017C0180913F0E811176C08091DA -:104530008C15882309F471C0A70196016E897F89C3 -:10454000888D998D52D59B01AC016091411070917D -:10455000421080914310909144100F94EFB36983FF -:104560007A838B839C83A70196016A897B898C89D6 -:104570009D893BD520913D1030913E1040913F10D8 -:10458000509140100F94EFB36A8F7B8F8C8F9D8F6B -:10459000A7019601688579858A859B8526D5209116 -:1045A000391030913A1040913B1050913C100F94CB -:1045B000EFB36E8F7F8F88A399A3A7019601C301E4 -:1045C000B20113D52091351030913610409137103B -:1045D000509138100F94EFB3BF81BF932E812F936A -:1045E0008E849F84A888B988DE0111966D01EA8CBB -:1045F000FB8C0C8D1D8D2E8D3F8D48A159A10E94E5 -:104600005187BFEF2B1A3B0A0F900F902C853D85E9 -:104610002215330509F070CF88CEE9ECFFE0A5E361 -:10462000B0E141915191619171914D935D936D9381 -:104630007D933FE0E93DF307A1F7A5960FB6F89407 -:10464000DEBF0FBECDBFDF91CF911F910F91FF90C5 -:10465000EF90DF90CF90BF90AF909F908F907F9022 -:104660006F905F904F903F902F900895CF92DF9280 -:10467000EF92FF921F93CF93DF93EC017B01809128 -:10468000FE0CFB01808384E54BD8182F811102C0FA -:1046900010E05DC03CD80F9454B5F70160836623E9 -:1046A000B9F3E6E9FEE584916F01882341F00E94A9 -:1046B0006EADFFEFCF1ADF0AF6018491F6CFCD364B -:1046C000D10529F14CF4C836D10579F0C936D105A8 -:1046D000A1F5CCE5D7E415C0CA3DD10501F1CD3D2A -:1046E000D10559F5C1EAD7E422C0E5E4F7E48491A5 -:1046F000EF01882311F10E946EAD2196FE01849195 -:10470000F8CF89918823C9F00E946EADFACFC3E734 -:10471000D7E48991882389F00E946EADFACFCAE868 -:10472000D7E48991882349F00E946EADFACF899130 -:10473000882319F00E946EADFACFF701608170E016 -:1047400080E090E00E94F7AD8AE00E946EAD812F7C -:10475000DF91CF911F91FF90EF90DF90CF90089560 -:104760002F923F924F925F926F927F928F929F9281 -:10477000AF92BF92CF92DF92EF92FF920F931F936F -:10478000CF93DF9389EFC82E82E0D82EC9ECDFE00B -:1047900005E310E19FE2E92E9FE0F92E212CF601BE -:1047A00081916F010F94909B882309F458C0F70101 -:1047B0008081811103C03090FA0E02C033243394FB -:1047C0000F94879B2B013C01688379838A839B83A9 -:1047D000F3E02F1232C0E091FE0C84E0E89FF0017C -:1047E0001124E95BFD4F80809180A280B38020E09E -:1047F00030E040E85FE3C501B4010F9488AE882340 -:1048000009F459C031100DC0F80120813181428175 -:104810005381C301B2010F94EEB3688379838A8315 -:104820009B83A5019401688179818A819B81DDD375 -:10483000688379838A839B8302C03320C9F0F8019F -:104840002081318142815381688179818A819B8174 -:104850000F94EFB3688379838A839B8309C0F8013F -:1048600080819181A281B38188839983AA83BB834C -:10487000239424960C5F1F4FFFEFEF1AFF0A84E08A -:1048800028128DCF86E40F94909B8823B9F00F9463 -:10489000879B6B017C0120E030E0A9010F943AB6C0 -:1048A000181664F4C0927E02D0927F02E0928002D9 -:1048B000F092810203C03110C2CFE4CFDF91CF91DB -:1048C0001F910F91FF90EF90DF90CF90BF90AF902E -:1048D0009F908F907F906F905F904F903F902F9020 -:1048E00008953EDF89E40F94909B882359F00F943C -:1048F000879B6093080F7093090F80930A0F909322 -:104900000B0F08C01092080F1092090F10920A0F97 -:1049100010920B0F8AE40F94909B882359F00F9408 -:10492000879B60930C0F70930D0F80930E0F9093E5 -:104930000F0F089510920C0F10920D0F10920E0F82 -:1049400010920F0F089590912D0E90932C0E26EF3C -:104950003FEF30937C0220937B02882349F0892F1C -:1049600090E0019665E070E00F94A1B880932C0E62 -:1049700080E00F9427370F941D3761E080E00F949B -:104980006E3282EC91E30F94953189E596E00F94B5 -:10499000103160912C0E70E06F5F7F4F072E000C7E -:1049A000880B990B0F94F53080912C0E21E030E0AC -:1049B000082E01C0220F0A94EAF79091330F292B99 -:1049C0002093330F805F0F946A2461E080E00F949E -:1049D0005B216CED75E080E090E00F940D8780E343 -:1049E0000F946A2480912C0E80932D0E0F94372003 -:1049F0000E946EEA0D9498834F925F926F927F921D -:104A00008F929F92AF92BF92EF92FF920F931F935C -:104A1000E091FE0CF0E0E752F04F882309F4BFC0AC -:104A20008081811186C18091351090913610A091BE -:104A30003710B09138108093C90F9093CA0FA0938C -:104A4000CB0FB093CC0F8091391090913A10A09178 -:104A50003B10B0913C108093CD0F9093CE0FA0935C -:104A6000CF0FB093D00F80913D1090913E10A09148 -:104A70003F10B09140108093D10F9093D20FA0932C -:104A8000D30FB093D40F8090411090904210A0901B -:104A90004310B09044108092D50F9092D60FA09200 -:104AA000D70FB092D80F6091820270918302072EC7 -:104AB000000C880B990B0F948EAE2091FC10309156 -:104AC000FD104091FE105091FF108FD22AE037ED7B -:104AD00043E25CE38AD2A50194010F94EFB36093A3 -:104AE000411070934210809343109093441081E4DE -:104AF00090E10E94D5BD80907E0290907F02A090B0 -:104B00008002B090810220E030E040E752E4609102 -:104B1000001170910111809102119091031165D2E1 -:104B200060937E0270937F02809380029093810253 -:104B3000E091FE0CF0E0E752F04F81E080833ADB39 -:104B400020910411309105114091061150910711E7 -:104B500060913D1070913E1080913F1090914010F7 -:104B60000F94EEB37B018C0160933D1070933E1067 -:104B700080933F10909340102091391030913A105B -:104B800040913B1050913C1060913510709136105F -:104B900080913710909138100F94BA59C1C080811C -:104BA000882309F4C6C08090351090903610A090EC -:104BB0003710B09038108092C90F9092CA0FA0920F -:104BC000CB0FB092CC0F4090391050903A106090BB -:104BD0003B1070903C104092CD0F5092CE0F6092DF -:104BE000CF0F7092D00F60913D1070913E10809168 -:104BF0003F10909140106093D10F7093D20F80932B -:104C0000D30F9093D40F0091411010914210209136 -:104C10004310309144100093D50F1093D60F20937A -:104C2000D70F3093D80F2091041130910511409186 -:104C30000611509107110F94EFB360933D107093DC -:104C40003E1080933F10909340107B018C01A30194 -:104C50009201C501B4010F94BA5920910811309105 -:104C6000091140910A1150910B116091FC10709143 -:104C7000FD108091FE109091FF100F94EFB34B0147 -:104C80005C016091820270918302072E000C880BF8 -:104C9000990B0F948EAE9B01AC01C501B401A5D157 -:104CA0002AE037ED43E25CE3A0D19B01AC016091C7 -:104CB00041107091421080914310909144100F94D4 -:104CC000EEB3609341107093421080934310909321 -:104CD000441081E490E10E94D5BD80907E029090C6 -:104CE0007F02A0908002B090810220E030E040E797 -:104CF00052E460910C1170910D1180910E11909100 -:104D00000F1173D160937E0270937F0280938002B3 -:104D100090938102E091FE0CF0E0E752F04F108298 -:104D200049DA80927E0290927F02A0928002B09235 -:104D300081021F910F91FF90EF90BF90AF909F90D5 -:104D40008F907F906F905F904F900895442359F01B -:104D5000FC012491213418F024912D3530F0FC0110 -:104D6000249121111BC080E00895FC012491FB01D6 -:104D7000549130E0205E3F4FE52FF0E02E173F07C3 -:104D8000F4F0FC012491FB01549130E0215E3F4F8F -:104D9000E52FF0E02E173F076CF011C0FC012491C5 -:104DA000FB013491231758F0FC012491FB0134914D -:104DB000321728F0415001966F5F7F4FC7CF81E0D7 -:104DC00008950F931F93CF93DF93CDB7DEB780E1A4 -:104DD00090E1C9D597FFFBCFAE01465F5F4F6BEB0C -:104DE0007BE580E190E127D78C010F9425886093C3 -:104DF0000C1070930D1080930E1090930F10C8013B -:104E0000DF91CF911F910F9108950F94F56010924B -:104E1000591610925B1610925A161092561610924E -:104E20005816109257161092511610925216109250 -:104E3000531610925416109255160F9425886093AD -:104E400060167093611680936216909363160F94A8 -:104E500025881092D4161092D7161092F11610923F -:104E6000F416ECE0F7E1108213827B9628E1EA3138 -:104E7000F207C9F789E1809383181092861810927F -:104E8000871810929F181092A6181092A9181092C5 -:104E90001D1810921C181092531910925419109248 -:104EA00055191092561910925B1910925C191092B4 -:104EB0005D1910925E191092801610928116109250 -:104EC000821610927E1610927F1610925719109229 -:104ED00058191092591910925A1910921B181092C1 -:104EE0001A181092C1188EE091E0ECE0F7E1DF01B2 -:104EF0009C011D9221503040E1F781E080935F19C1 -:104F00001092D3161092D2160F942588DC01CB0193 -:104F100088579C4EAF4FBF4F8093571990935819A5 -:104F2000A0935919B0935A190F94258860937A1653 -:104F300070937B1680937C1690937D160F94258832 -:104F40000F9425886093721670937316809374166D -:104F5000909375160F94258860936E1670936F1654 -:104F600080937016909371161092691610926A16BB -:104F700010926B1610926C1610926D1610926416A9 -:104F800010926516109266161092671610926816A7 -:104F90000895CF93DF93282F30E0F901E55AF04AC6 -:104FA0008491F901E95EF34AD491F901E957F34A92 -:104FB000C491CC2391F081110F94FA83EC2FF0E08F -:104FC000EE0FFF1FEF5BF04AA591B491EC91ED233A -:104FD00081E090E021F480E002C080E090E0DF9189 -:104FE000CF9108959B01AC0100C00BD078C069D06F -:104FF00028F06ED018F0952309F05AC05FC0112434 -:10500000A2C07ED0A0F3959FD1F3950F50E0551F1D -:10501000629FF001729FBB27F00DB11D639FAA270D -:10502000F00DB11DAA1F649F6627B00DA11D661F5C -:10503000829F2227B00DA11D621F739FB00DA11D7D -:10504000621F839FA00D611D221F749F3327A00D37 -:10505000611D231F849F600D211D822F762F6A2FD3 -:1050600011249F5750408AF0E1F088234AF0EE0F58 -:10507000FF1FBB1F661F771F881F91505040A9F765 -:105080009E3F510570F014C05EC05F3FECF3983E48 -:10509000DCF3869577956795B795F795E7959F5FCC -:1050A000C1F7FE2B880F911D9695879597F9089566 -:1050B00097F99F6780E870E060E008959FEF80ECCB -:1050C000089500240A94161617061806090608956E -:1050D00000240A9412161306140605060895092ED4 -:1050E0000394000C11F4882352F0BB0F40F4BF2B43 -:1050F00011F460FF04C06F5F7F4F8F4F9F4F089583 -:1051000057FD9058440F551F59F05F3F71F0479578 -:10511000880F97FB991F61F09F3F79F0879508955D -:10512000121613061406551FF2CF4695F1DF08C07C -:10513000161617061806991FF1CF86957105610599 -:1051400008940895E894BB2766277727CB0197F941 -:105150000895EF920F931F93CF93DF93E80147FDDC -:1051600002C034E001C034E1042E000C550B57FF9F -:1051700003C0519541955109E32E022F242FAE0112 -:105180000F94B6B1CE01DF91CF911F910F91EF90A7 -:1051900008958F929F92AF92BF92CF92DF92EF923B -:1051A000FF920F931F93CF93DF93EC016B01611577 -:1051B000710519F0FB01918380837E01FFEFEF1AE7 -:1051C000FF0A0881802F90E03DD3892B11F0E70181 -:1051D000F4CF0D3239F47E0182E0E80EF11C098132 -:1051E00011E008C00B3229F47E0192E0E90EF11CB7 -:1051F000098110E0E701219743E050E068E374E0A3 -:10520000CE014CD3892BB9F4239645E050E063E3FB -:1052100074E0CE0143D3892B09F42596C114D1043F -:1052200019F0F601D183C0831111F1C060E070E084 -:1052300080E89FE7F5C043E050E060E374E0CE0112 -:105240002DD3892B59F4C114D10409F4E5C0F2E03F -:10525000EF0EF11CF601F182E082DEC020E030E0CA -:10526000A901C0E0D0E0F70160EDA62EA00E89E014 -:105270008A1530F1912F9260B92E812F887012FF1C -:1052800004C0811124C0219622C081112197A5E07C -:10529000B0E00F94D5B3DC01CB01880F991FAA1F92 -:1052A000BB1F9C01AD012A0D311D411D511D283927 -:1052B00089E93807480789E1580748F0166006C0B1 -:1052C0009EEFA9120AC013FD40C01860B12E8FEFE7 -:1052D000E81AF80A00811B2DC6CF802F8F7D8534F8 -:1052E000A1F580818D3211F4106106C08B3221F05E -:1052F000319661E070E004C08181329662E070E036 -:1053000080538A3018F0E61BF70B1FC060E070E096 -:1053100060389CE079075CF4DB01AA0FBB1FAA0F81 -:10532000BB1F6A0F7B1F660F771F680F711D3196B9 -:10533000DF0111978C9180538A3050F314FF03C022 -:10534000719561957109C60FD71F11FF08C0C1146F -:10535000D10429F0CF010197F60191838083CA011E -:10536000B901DAD4212F2370233019F04B015C01ED -:1053700006C04B015C01B7FAB094B7F8B09420E0D6 -:1053800030E0A901C501B401C3D4882309F43CC0AD -:10539000D7FF06C0D195C195D1090FE414E002C032 -:1053A00007E614E06801F8E1CF1AD10890E2E92E8F -:1053B000F12CCE15DF056CF0F80125913591459162 -:1053C0005491C501B40111DE4B015C01CE19DF0916 -:1053D000F0CF04501109F594E7940C151D0549F719 -:1053E0008A2D880F8B2D881F8F3F41F020E030E001 -:1053F000A901C501B4018CD4811106C082E290E0FC -:105400009093D6198093D519C501B40109C060E005 -:1054100070E080E89FEF04C060E070E080EC9FE700 -:10542000DF91CF911F910F91FF90EF90DF90CF9080 -:10543000BF90AF909F908F9008953F924F925F9250 -:105440006F927F928F929F92AF92BF92CF92DF9294 -:10545000EF92FF920F931F93CF93DF935C016B0149 -:105460007A016115710519F0FB0191838083E114C4 -:10547000F10429F0C7010297839708F0E4C0E50121 -:105480002196F5011081812F90E0DCD1892B11F05C -:105490005E01F5CF1D3229F42196F501118101E05D -:1054A00007C01B3221F4E5012296F501118100E0CD -:1054B000E114F10409F1F0E1EF16F10429F43FC021 -:1054C00010E3E114F10421F128E0E216F10401F106 -:1054D00054F4E2E0EE16F10421F5812C912CA12C7C -:1054E000B0E4BB2E3EC0FAE0EF16F10439F020E143 -:1054F000E216F104B1F430C0103319F1FAE0EF2EE6 -:10550000F12CACEC8A2E982CA82CACE0BA2E29C039 -:1055100078E0E72EF12C812C912CA12CE0E1BE2E1D -:1055200020C060E070E080E090E897010F2C000C54 -:10553000440B550B0F94B3B349015A0112C01033F9 -:1055400059F488818F7D883509F0BACF1981229668 -:10555000026080E1E82EF12C812C912CA12C68E0D6 -:10556000B62E40E060E070E0CB0127010F2C000C6C -:1055700066087708FE0150ED352E310E29E023151F -:1055800070F42FEB210F2A3118F439EC332E06C0BA -:105590002FE9210F2A3118F529EA322E310E232D59 -:1055A00030E02E153F05DCF447FD16C08616970641 -:1055B000A806B90670F0A30192010F94A4B3630D7D -:1055C000711D811D911D61307105810520E89207D3 -:1055D00010F04FEF01C041E021961081CBCF202F7A -:1055E0002170C114D10471F0442329F02197F601F0 -:1055F000D183C08307C001FF19C02297F601D18370 -:10560000C08314C047FF12C0222329F060E070E07D -:1056100080E090E804C06FEF7FEF8FEF9FE722E21A -:1056200030E03093D6192093D51909C0222381F098 -:1056300090958095709561957F4F8F4F9F4F462F26 -:10564000372F282F12C040E030E020E090E00DC05E -:1056500097FFF5CF82E290E09093D6198093D51909 -:105660006FEF7FEF8FEF9FE7EACF642F732F822FCB -:10567000DF91CF911F910F91FF90EF90DF90CF902E -:10568000BF90AF909F908F907F906F905F904F9062 -:105690003F900895283008F027E03327DA01990F6A -:1056A000311D87FD916000966105710539F4326006 -:1056B0002E5F3D9330E32A95E1F708959F3F30F048 -:1056C00080387105610509F03C5F3C5F3D93913086 -:1056D00008F08068911DDF93CF931F930F93FF9283 -:1056E000EF92192F987F9695E92F96959695E90F49 -:1056F000FF27EB53FB4F99273327EE24FF24A70105 -:10570000E70105900894079428F4360FE71EF81E69 -:10571000491F511D660F771F881F991F0694A1F717 -:105720000590079428F4E70EF81E491F561FC11D67 -:10573000770F881F991F661F0694A1F7059007949D -:1057400028F4F80E491F561FC71FD11D880F991F37 -:10575000661F771F0694A1F70590079420F4490F60 -:10576000561FC71FD81F990F661F771F881F0694E3 -:10577000A9F784911095177041F0D695C795579564 -:105780004795F794E7941A95C1F7EBE6F4E068942F -:105790001590159135916591959105907FE27395DE -:1057A000E118F10A430B560BC90BD009C0F7E10C05 -:1057B000F11E431F561FC91FD01D7EF4703311F414 -:1057C0008A95E6CFE894015030F0080F0AF40027DC -:1057D000021708F4202F2395022F7A3328F079E35B -:1057E0007D932A95E9F710C07D932A9589F6069452 -:1057F00097956795379517951794E118F10A430B1C -:10580000560BC90BD00998F023957E9173957A3386 -:1058100008F070E37C932013B8F77E9170617D935C -:1058200030F0839571E37D9370E32A95E1F71124BD -:10583000EF90FF900F911F91CF91DF91992787FDF6 -:1058400090950895911108C7803219F089508550BC -:10585000D0F70895FB01DC0102C005900D92415084 -:105860005040D8F70895FB01DC010D900020E9F7C6 -:10587000119705900D920020E1F70895FB01DC01DE -:1058800005900D920020E1F70895FC01059000209D -:10589000E9F7809590958E0F9F1F0895FB01DC011D -:1058A0004150504088F08D9181341CF08B350CF4C0 -:1058B000805E659161341CF06B350CF4605E861B74 -:1058C000611171F3990B0895881BFCCFFB01DC017A -:1058D0004150504030F08D910590801919F400200E -:1058E000B9F7881B990B0895FB01DC01415050402A -:1058F00048F005900D920020C9F701C01D9241505B -:105900005040E0F70895FC0105906150704001108F -:10591000D8F7809590958E0F9F1F0895FB015591A4 -:105920005523A9F0BF01DC014D9145174111E1F765 -:1059300059F4CD010590002049F04D9140154111D9 -:10594000C9F3FB014111EFCF81E090E00197089589 -:10595000FC016150704001900110D8F7809590953E -:105960008E0F9F1F0895CF93DF93EC012B8120FFB3 -:1059700033C026FF0AC02F7B2B838E819F81019627 -:105980009F838E838A8190E029C022FF0FC0E88127 -:10599000F9818081082E000C990B009719F4206280 -:1059A0002B831AC03196F983E8830EC0EA85FB8504 -:1059B000199597FF09C02B81019611F080E201C073 -:1059C00080E1822B8B8308C02E813F812F5F3F4F68 -:1059D0003F832E83992702C08FEF9FEFDF91CF91F6 -:1059E00008950F931F93CF93DF93CDB7DEB708854C -:1059F0001985F801838188608383AE01445F5F4F1E -:105A00006A857B85C8010F94648BF8012381277F09 -:105A10002383DF91CF911F910F9108950F931F93CF -:105A2000CF93DF93FB01238121FD03C08FEF9FEF15 -:105A30002CC022FF16C04681578124813581421730 -:105A4000530744F4A081B1819D012F5F3F4F318303 -:105A500020838C93268137812F5F3F4F37832683A6 -:105A600014C08B01EC01FB010084F185E02D199538 -:105A7000892BE1F6D80116968D919C911797019686 -:105A800017969C938E931697CE01DF91CF911F911D -:105A90000F910895EF92FF920F931F93CF93DF938F -:105AA0008C017B01DB0113968C9181FF17C0D0E044 -:105AB000C0E0F8018491882371F0D7011896ED9128 -:105AC000FC911997B7011995892B11F0DFEFCFEFF2 -:105AD0000F5F1F4FEECF8D2F9C2F02C08FEF9FEFD8 -:105AE000DF91CF911F910F91FF90EF9008950F9349 -:105AF0001F93CF93DF93CDB7DEB708851985F801E3 -:105B0000838188608383AE01445F5F4F6A857B85B4 -:105B1000C80115D3F8012381277F2383DF91CF911B -:105B20001F910F9108950F931F93CF93DF93CDB7DC -:105B3000DEB7AE01485F5F4FDA016D917D91AD0137 -:105B40000FEC19E1F80182819381DC0113962C910D -:105B50001397286013962C930F94648BD801129698 -:105B6000ED91FC9113972381277F2383DF91CF91C0 -:105B70001F910F9108950F931F93CF93DF938C0183 -:105B8000E091D119F091D219838181FF1BC0D0E03F -:105B9000C0E0F80184916091D1197091D219DB01B4 -:105BA0001896ED91FC911997882341F01995892B4E -:105BB00011F0DFEFCFEF0F5F1F4FEBCF8AE01995AA -:105BC000892B19F08FEF9FEF02C08D2F9C2FDF9153 -:105BD000CF911F910F9108950F931F93CF93DF9350 -:105BE000CDB7DEB72E970FB6F894DEBF0FBECDBF90 -:105BF0000E891F898EE08C831A8309838FEF9FE7BC -:105C00009E838D83AE01465E5F4F688D798DCE0198 -:105C100001960F94648BEF81F885E00FF11F1082DD -:105C20002E960FB6F894DEBF0FBECDBFDF91CF9199 -:105C30001F910F910895CF93DF93EC018B818860C2 -:105C40008B83CE010F94648B2B81277F2B83DF9175 -:105C5000CF910895FA01AA27283051F1203181F11E -:105C6000E8946F936E7F6E5F7F4F8F4F9F4FAF4F64 -:105C7000B1E03ED0B4E03CD0670F781F891F9A1F77 -:105C8000A11D680F791F8A1F911DA11D6A0F711D2B -:105C9000811D911DA11D20D009F468943F912AE037 -:105CA000269F11243019305D3193DEF6CF0108951F -:105CB000462F4770405D4193B3E00FD0C9F7F6CF50 -:105CC000462F4F70405D4A3318F0495D31FD405218 -:105CD000419302D0A9F7EACFB4E0A69597958795AE -:105CE00077956795BA95C9F700976105710508958D -:105CF0009B01AC010A2E0694579547953795279539 -:105D0000BA95C9F7620F731F841F951FA01D0895D0 -:105D100040D008F481E00895E89409C097FB3EF470 -:105D200090958095709561957F4F8F4F9F4F9923E8 -:105D3000A9F0F92F96E9BB279395F6958795779566 -:105D40006795B795F111F8CFFAF4BB0F11F460FF26 -:105D50001BC06F5F7F4F8F4F9F4F16C0882311F07E -:105D600096E911C0772321F09EE8872F762F05C092 -:105D7000662371F096E8862F70E060E02AF09A952D -:105D8000660F771F881FDAF7880F9695879597F922 -:105D90000895990F0008550FAA0BE0E8FEEF1616BC -:105DA0001706E807F907C0F012161306E407F5070F -:105DB00098F0621B730B840B950B39F40A2661F083 -:105DC000232B242B252B21F408950A2609F4A14026 -:105DD000A6958FEF811D811D089520FD09C0FC014E -:105DE00023FD05C022FF02C0738362835183408379 -:105DF000089544FD17C046FD17C0AB01BC01DA0190 -:105E0000FB01AA0FBB1FEE1FFF1F1094D1F74A0F13 -:105E10005B1F6E1F7F1FCB01BA01660F771F881FA4 -:105E2000991F09C033E001C034E0660F771F881F57 -:105E3000991F3150D1F7620F711D811D911D089579 -:105E40000F931F93CF93DF938C01C8018CDDEC017E -:105E500097FD06C0F7DC892BC1F7B801CE010AD443 -:105E6000CE01DF91CF911F910F9108958F929F9254 -:105E7000AF92BF92EF92FF920F931F93CF93DF9356 -:105E80008C01D62F7A01B22E6EDD9C0133272B3286 -:105E9000310531F02D32310559F48B2D8068B82E43 -:105EA000D15011F480E061C0C8015DDD97FDFACFEB -:105EB000CB2DCD7F2B2D2073F9F48033E9F4AA2468 -:105EC000AA94AD0E09F43EC0C8014DDD97FD3AC05D -:105ED0009C012F7D33272835310541F4C264D2500F -:105EE00089F1C80140DD97FF07C02CC0B6FE02C093 -:105EF000C26001C0C261DA2D812C912C540120EDC9 -:105F0000280F283078F0C4FF03C0B801B3D317C0FE -:105F10002A3040F0C6FFF9CF2F7D3FEE320F3630EA -:105F2000A0F727504C2FC501B40163DF4B015C0182 -:105F3000C260D15051F0C80116DD97FFE0CFC1FD1E -:105F400004C0B0CF812C912C5401C7FF08C0B0947D -:105F5000A09490948094811C911CA11CB11C2C2FA6 -:105F6000B501A401C70139DF81E0DF91CF911F9115 -:105F70000F91FF90EF90BF90AF909F908F900895FA -:105F80005F926F927F928F929F92AF92BF92CF92C9 -:105F9000DF92EF92FF920F931F93CF93DF93CDB7D2 -:105FA000DEB7A0970FB6F894DEBF0FBECDBF5C0181 -:105FB000962E7A01F9018E010F5F1F4F680180E272 -:105FC000D8011D928A95E9F7D50113968C9080E04F -:105FD00090E0612C712C30E061E070E083FC259151 -:105FE00083FE21918F01522E211103C080E090E0A9 -:105FF00090C02E3511F4009751F1432F50E048170F -:1060000059073CF42D3559F12D3219F4772009F157 -:1060100003C0772009F468C0452D469546954695FE -:10602000D601A40FB11D452D47708B0102C0000F92 -:10603000111F4A95E2F7A8015C91452B4C9365141A -:1060400059F0561410F45394E7CF5A94E5CF31E049 -:1060500004C07724739401C0712C0196BFCF7720C0 -:1060600019F08E8180628E83311103C0882483945D -:1060700017C0F6019E012F5D3F4F8081809581936F -:106080002E173F07D1F7F2CFE114F10429F0D70121 -:106090008C93F70131967F019A94812C9920E9F035 -:1060A000C50161DC97FD17C0FC01FF2723E0F595D2 -:1060B000E7952A95E1F7EC0DFD1D208130E0AC015C -:1060C0004770552702C0359527954A95E2F720FD80 -:1060D000DBCFB501CFD2811089CFE114F10411F0EB -:1060E000D7011C92C80115C0422F4695469546958A -:1060F000D601A40FB11D422F47708B0102C0000FC3 -:10610000111F4A95E2F7A8015C91452B4C93622E32 -:10611000A4CFA0960FB6F894DEBF0FBECDBFDF911F -:10612000CF911F910F91FF90EF90DF90CF90BF9094 -:10613000AF909F908F907F906F905F9008955F9247 -:106140006F927F928F929F92AF92BF92CF92DF9287 -:10615000EF92FF920F931F93CF93DF936C01EB01AC -:106160005A01FC0117821682512CF601E380FE01D0 -:10617000E3FC8591E3FE8191182FEF01882309F458 -:10618000E0C090E05FDB892B19F0C60159DEEDCF4E -:10619000153241F4FE01E3FC1591E3FE1191EF018C -:1061A000153271F4C601DFDB97FDC9C0412F50E005 -:1061B0009C01332724173507C1F2B6015BD2C1C059 -:1061C0001A3239F4E3FC1591E3FE1191EF0101E07D -:1061D00001C000E0F12C20ED210F2A3078F402609C -:1061E0006F2D70E080E090E040E203DEF62EFE01CD -:1061F000E3FC1591E3FE1191EF01EDCF01FF03C028 -:10620000F11003C09EC0FF24FA94183619F01C3612 -:1062100051F010C0FE01E3FC1591E3FE1191EF0176 -:10622000183641F408600460FE01E3FC1591E3FEBA -:106230001191EF01112309F484C0612F70E085E60C -:1062400095E00DD2892B09F47CC000FD07C0F50153 -:1062500080809180C50102965C0102C0812C912C46 -:106260001E3649F4F6014681578160E070E0202F28 -:10627000C401B3DD7ACF1336A1F401FD02C0FF24BF -:10628000F394C60170DB97FD5AC08114910429F084 -:10629000F4018083C40101964C01FA94F110F1CF0E -:1062A0004AC01B3551F49E01A4016F2DC60168DE62 -:1062B000EC01892B09F03FC039C0C601C1DD97FD53 -:1062C0003EC01F3649F128F4143621F1193639F150 -:1062D00025C0133771F01537E9F020C081149104FF -:1062E00029F0F4016082C40101964C01FA94FF2068 -:1062F00059F0C60138DB3C0197FD06C0A3DA892BB3 -:1063000069F3B601C301B6D181149104A1F0F4017F -:10631000108211C0006203C0006101C00064202F20 -:10632000A4016F2DC601A2DD811105C0F601838194 -:10633000807329F406C000FD18CF539416CF552062 -:1063400019F0852D90E002C08FEF9FEFDF91CF9184 -:106350001F910F91FF90EF90DF90CF90BF90AF9083 -:106360009F908F907F906F905F9008958F929F92F3 -:10637000AF92BF92CF92DF92EF92FF920F931F9353 -:10638000CF93DF93CDB7DEB729970FB6F894DEBF72 -:106390000FBECDBF6A01122FB02E2BE3201720F0C5 -:1063A000FF24F394F00E02C02CE3F22E0F2D27E011 -:1063B000AE014F5F5F4F6ED9BC014981842F897058 -:1063C000813031F0E1FC06C0E0FE06C090E205C07D -:1063D0009DE203C09BE201C090E05E2D507143FF3F -:1063E0003CC0911102C083E001C084E0811718F421 -:1063F000212F281B01C020E051110BC0F601822F74 -:1064000030E2882319F031938150FBCFC20ED11CAA -:1064100020E0992329F0D6019C93F60131966F0173 -:10642000C6010396E2FE0AC03EE4D6013C9341E475 -:1064300011964C93119712963C9306C03EE6F601D6 -:10644000308341E641833283FC01322F40E2332323 -:1064500009F442C041933150FACF42FF44C0911138 -:1064600002C083E001C084E0811718F4212F281BAB -:1064700001C020E051110BC0F601822F30E28823C9 -:1064800019F031938150FBCFC20ED11C20E099232B -:1064900029F0D6019C93F60131966F01C60103964F -:1064A000E2FE0BC039E4D6013C933EE411963C93E6 -:1064B000119736E412963C9307C039E6F601308313 -:1064C0003EE6318336E63283FC01322F40E233234D -:1064D00019F041933150FBCFFC01E20FF11D108206 -:1064E0008EEF9FEFA6C021E030E0911102C020E0C6 -:1064F00030E0161617061CF4FB01319602C0E1E0ED -:10650000F0E02E0F3F1FBB2021F0EB2DF0E0319685 -:1065100002C0E0E0F0E02E0F3F1FE12FF0E02E1769 -:106520003F071CF4121B212F01C020E08E2D887123 -:1065300059F4F601822F30E2882319F0319381500B -:10654000FBCFC20ED11C20E0992329F0D6019C93E9 -:10655000F60131966F0151110BC0F601822F90E3C5 -:10656000882319F091938150FBCFC20ED11C20E0FB -:106570000F2D060F9A81342F307144FF03C09133E1 -:1065800009F40150101624F4093018F008E001C095 -:1065900001E0AB0177FF02C040E050E0FB01E41BEB -:1065A000F50BA1E0B0E0AC0FBD1FEA0FFB1F8EE2C0 -:1065B000A82E4B01801A91080B2D10E01195019522 -:1065C00011094F3FBFEF5B0721F4D601AC92119642 -:1065D0006D01641775072CF08416950614F48181FB -:1065E00001C080E3415051093196D60111967D01D9 -:1065F0004017510724F0D6018C936701E2CF64174E -:10660000750739F4963320F4953319F4311101C02C -:1066100081E3F6018083F701822F90E2882319F04D -:1066200091938150FBCFF701E20FF11D108280E0C2 -:1066300090E029960FB6F894DEBF0FBECDBFDF9174 -:10664000CF911F910F91FF90EF90DF90CF90BF906F -:10665000AF909F908F900895992788270895FC0107 -:106660000590061621F00020D9F7C0010895319752 -:10667000CF010895FB01238120FF12C026FD10C029 -:106680008F3F3FEF930761F082832F7D2064238348 -:106690002681378121503109378326839927089530 -:1066A0008FEF9FEF0895DC01CB01FC01F999FECF3C -:1066B00006C0F2BDE1BDF89A319600B40D9241508A -:1066C0005040B8F70895F999FECF92BD81BDF89A70 -:1066D000992780B50895A6E1B0E044E050E0E5CF09 -:1066E000A8E1B0E042E050E0E0CF262FF999FECFDC -:1066F00092BD81BDF89A019700B4021639F01FBA15 -:1067000020BD0FB6F894FA9AF99A0FBE0895039631 -:10671000272FECDFEADF252FE9DF242FE7CF0196D3 -:10672000272FE4DFE2CF262FF999FECF1FBA92BDC3 -:1067300081BD20BD0FB6F894FA9AF99A0FBE019662 -:106740000895F1DF272FF0CFDB018F939F932DD09A -:10675000BF91AF91A29F800D911DA39F900DB29FFD -:10676000900D11240895A1E21A2EAA1BBB1BFD0156 -:106770000DC0AA1FBB1FEE1FFF1FA217B307E40720 -:10678000F50720F0A21BB30BE40BF50B661F771F78 -:10679000881F991F1A9469F7609570958095909558 -:1067A0009B01AC01BD01CF01089509D0A59F900DBB -:1067B000B49F900DA49F800D911D11240895A29F58 -:1067C000B001B39FC001A39F700D811D1124911DC5 -:1067D000B29F700D811D1124911D08955058BB2743 -:1067E000AA2713D00D946FA80F9461A838F00F94C6 -:1067F00068A820F039F49F3F19F426F40D945EA8A0 -:106800000EF4E095E7FB0D9458A8E92F0F9480A8AB -:1068100058F3BA17620773078407950720F079F4D5 -:10682000A6F50D94A2A80EF4E0950B2EBA2FA02D7C -:106830000B01B90190010C01CA01A0011124FF272D -:10684000591B99F0593F50F4503E68F11A16F04028 -:10685000A22F232F342F4427585FF3CF4695379527 -:106860002795A795F0405395C9F77EF41F16BA0BEC -:10687000620B730B840BBAF09150A1F0FF0FBB1F9A -:10688000661F771F881FC2F70EC0BA0F621F731FE3 -:10689000841F48F4879577956795B795F7959E3F40 -:1068A00008F0B0CF9395880F08F09927EE0F9795D1 -:1068B000879508950F9461A860F080E891E009F44D -:1068C0009EEF0F9468A828F040E851E071F45EEF65 -:1068D0000CC00D945EA80D94A2A8E92FE0780F9447 -:1068E00080A840F3092E052AB1F326173707480779 -:1068F000590738F00E2E07F8E02569F0E025E0642E -:106900000AC0EF6307F8009407FADB01B9019D01A3 -:10691000DC01CA01AD01EF9366D00F946FA80AD0D5 -:106920005F91552331F02BED3FE049E450FD49ECF8 -:1069300056CF0895DF93DD27B92FBF7740E85FE397 -:106940001616170648075B0710F4D92F00D29F933D -:106950008F937F936F930F94F2A7E2EAF1E010D147 -:106960000F946FA82F913F914F915F910F9401A8C1 -:10697000DD2349F09058A2EA2AED3FE049EC5FE3BD -:10698000D0785D2742DFDF910D946FA85BD188F04E -:106990009F3748F4911116F40D94A3A860E070E0BD -:1069A00080E89FE3089526F01B16611D711D811D6F -:1069B000BEC0D8C00DD1E39533C112D00D946FA8DD -:1069C0000F9468A858F00F9461A840F029F45F3F35 -:1069D00029F00D9458A851110D94A3A80D945EA808 -:1069E0000F9480A868F39923B1F3552391F3951B75 -:1069F000550BBB27AA2762177307840738F09F5FE0 -:106A00005F4F220F331F441FAA1FA9F335D00E2E4C -:106A10003AF0E0E832D091505040E695001CCAF7B9 -:106A20002BD0FE2F29D0660F771F881FBB1F26177C -:106A300037074807AB07B0E809F0BB0B802DBF0153 -:106A4000FF2793585F4F3AF09E3F510578F00D9421 -:106A500058A80D94A3A85F3FE4F3983ED4F386951D -:106A600077956795B795F7959F5FC9F7880F911D43 -:106A70009695879597F90895E1E0660F771F881F2F -:106A8000BB1F621773078407BA0720F0621B730BE2 -:106A9000840BBA0BEE1F88F7E095089505D0689433 -:106AA000B1110D94A3A808950F9488A888F09F575A -:106AB00098F0B92F9927B751B0F0E1F0660F771F22 -:106AC000881F991F1AF0BA95C9F714C0B13091F018 -:106AD0000F94A2A8B1E008950D94A2A8672F782F73 -:106AE0008827B85F39F0B93FCCF3869577956795DD -:106AF000B395D9F73EF490958095709561957F4F49 -:106B00008F4F9F4F08959ED088F09F3748F4911182 -:106B100016F00D94A3A860E070E080E89FEB089564 -:106B200026F41B16611D711D811D01C01BC0882329 -:106B300071F4772321F09850872B762F07C06623B6 -:106B400011F499270DC09051862B70E060E02AF077 -:106B50009A95660F771F881FDAF7880F96958795A5 -:106B600097F908959F3F31F0915020F487957795DC -:106B70006795B795880F911D9695879597F9089514 -:106B8000DF93CF931F930F93FF92EF92DF927B01DE -:106B90008C01689406C0DA2EEF010F9401A8FE0163 -:106BA000E894A5912591359145915591A6F3EF0172 -:106BB0002CDEFE019701A801DA9471F7DF90EF90C7 -:106BC000FF900F911F91CF91DF9108950D945EA8D2 -:106BD0000F9488A8D8F3E894E0E0BB279F57F0F023 -:106BE0002AED3FE049EC06C0EE0FBB0F661F771F92 -:106BF000881F28F0B23A62077307840728F0B25A58 -:106C0000620B730B840BE3959A9572F7803830F41E -:106C10009A95BB0F661F771F881FD2F79048A4CFA5 -:106C2000EF93E0FF06C0A2EA2AED3FE049EC5FEBFC -:106C3000ECDD0F946FA80F90039401FC9058EFECDB -:106C4000F1E0CDC10F9488A8A0F0BEE7B91788F491 -:106C5000BB279F3860F41616B11D672F782F882741 -:106C6000985FF7CF869577956795B11D939596397F -:106C7000C8F308958ED808F48FEF08950F9461A893 -:106C800029F00F9468A811F00D945EA80D9458A8EF -:106C9000B901CA0167CF9F775F770F9480A870F31F -:106CA0009923B1F35523B1F3FF27951758F4E52F36 -:106CB000E91BED3068F75E3B10F0F1E41CC0903446 -:106CC000E0F40AC0E92FE51BED3020F79E3B10F001 -:106CD000F1E411C0503488F4F9EA88232AF09A9537 -:106CE000660F771F881FDAF744232AF05A95220F80 -:106CF000331F441FDAF79F1B5F1BFF931F930F93F4 -:106D0000FF92EF9279018A01BB27AB2F9B01AC0167 -:106D10000F9403A89701A801BF937B018C01AA27B8 -:106D2000BA2FB901CA010F9403A8AF919701A80126 -:106D3000EF90FF900F911F9168DD0F946FA8D3D053 -:106D40004F9140FF0895552747FD50950AC09B017C -:106D5000AC0160E070E080E89FE32FCE0D9458A86E -:106D600001CF0F9488A8E0F39923D1F3940F511D1C -:106D7000ABF39150504094F059F0882332F0660FF5 -:106D8000771F881F91505040C1F79E3F510534F73F -:106D9000880F911D9695879597F908955F3FACF000 -:106DA000983E9CF0BB27869577956795B79508F434 -:106DB000B1609395C1F7BB0F58F711F460FFE8CFAE -:106DC0006F5F7F4F8F4F9F4FE3CF0D94A3A80F941A -:106DD00088A858F19E5760F19851A0F0E9F09830DA -:106DE00020F5092E9927660F771F881F991F0A948F -:106DF000D1F712C0062E672F782F8827985F11F4DD -:106E0000000C07C0993FB4F38695779567959395E5 -:106E1000D9F7611D711D811D3EF490958095709587 -:106E200061957F4F8F4F9F4F089568940D94A3A84D -:106E30000D94A2A8FA01EE0FFF1F3096210531052F -:106E4000A1F16115710561F48038BFE39B0749F139 -:106E500068949038810561F08038BFEF9B0741F05E -:106E600099234AF5FF3FE1053105210519F1E89421 -:106E70000894E795D901AA2329F4AB2FBE2FF85F18 -:106E8000D0F310C0FF5F70F4A695E0F7F73950F02B -:106E900019F0FF3A38F49F779F930DD00F9007FCBD -:106EA0009058089546F00D945EA860E070E080E888 -:106EB0009FE308954FE79F775F934F933F932F93FF -:106EC000A8D02F913F914F915F910F94F5A752C099 -:106ED0009F937EDE0F9007FCEE5FA2CE19F416F4AE -:106EE0000D945EA83FCE0F9488A8C0F39923D1F3E8 -:106EF000BEF39F57550B87FF6BD00024A0E640EAF6 -:106F0000900180585695979528F4805C660F771FFE -:106F1000881F20F026173707480730F4621B730BD1 -:106F2000840B202931294A2BA695179407942025F4 -:106F300031254A2758F7660F771F881F20F026173C -:106F40003707480730F4620B730B840B200D311D9B -:106F5000411DA09581F7B901842F9158880F96950E -:106F60008795089529F416F00D9458A80D94A2A8B9 -:106F70000D945EA80F9488A8A8F39638A0F707F898 -:106F80000F92E8942BE33AEA48EB5FE70F9403A8EB -:106F90000F920F920F924DB75EB70F927ED0EDEE2B -:106FA000F1E0EEDD4F915F91EF91FF91E595EE1FDE -:106FB000FF1F49F0FE57E0684427EE0F441FFA9583 -:106FC000E1F74195550BCDDE0F9007FEC0CE089539 -:106FD00091505040660F771F881FD2F708959F93F6 -:106FE0008F937F936F93FF93EF939B01AC010F946B -:106FF000F5A7EF91FF91C4DD2F913F914F915F91E4 -:107000000D94F5A70EF0AECD0D945EA868940D9486 -:1070100058A80F9488A8B0F39923C1F3AEF3DF9377 -:10702000CF931F930F93FF92C92FDD2788232AF058 -:107030002197660F771F881FDAF720E030E040E8DD -:107040005FEB9FE3883920F0803E30F021968F7708 -:10705000C6DBE5E1F2E003C0C2DBE2E4F2E090DD92 -:107060008B01BE01EC01FB2E6F5771097595771FDF -:10707000880B990B0F948EAE28E132E741E35FE372 -:107080000F9401A8AF2D9801AE01FF900F911F91B1 -:10709000CF91DF91BADB0D946FA8FA01DC01AA0F42 -:1070A000BB1F9B01AC01BF5728F42227332744277D -:1070B00050781FC0B75188F4AB2F00244695379500 -:1070C0002795011CA395D2F3002069F0220F331FEE -:1070D000441FB395DAF30DD081CB61307105A0E880 -:1070E0008A07B94630F49B01AC01662777278827C9 -:1070F0009078309621F02083318342835383089522 -:1071000087FB082E062687FD819567FD61955CD07B -:107110000EF4919507FC81950895AA1BBB1B51E1C4 -:1071200007C0AA1FBB1FA617B70710F0A61BB70BF7 -:10713000881F991F5A95A9F780959095BC01CD019C -:10714000089597FB072E16F4009406D077FD08D01B -:10715000E4DF07FC05D03EF4909581959F4F08959C -:10716000709561957F4F0895052E97FB16F4009456 -:107170000FD057FD05D0F7DA07FC02D046F408C05F -:1071800050954095309521953F4F4F4F5F4F089553 -:1071900090958095709561957F4F8F4F9F4F089583 -:1071A000EE0FFF1F881F8BBF0790F691E02D1994FB -:1071B00006DB332312F48A1B9B0B01C000DBB7FFF5 -:1071C0000895821B930B0895991B79E004C0991FC1 -:1071D000961708F0961B881F7A95C9F78095089531 -:1071E0009111089581548A5108F4805E855A08955A -:1071F000FB01DC0104C08D910190801921F4415004 -:107200005040C8F7881B990B0895FB01DC0102C0B0 -:1072100001900D9241505040D8F70895DC0101C013 -:107220006D9341505040E0F70895FB01DC018D91D2 -:1072300081341CF08B350CF4805E619161341CF05C -:107240006B350CF4605E861B611189F3990B089510 -:10725000FB01DC010D900020E9F7119701900D92E0 -:107260000020E1F70895FC018191861721F0882321 -:10727000D9F7992708953197CF010895FB01DC01D3 -:107280008D91019080190110D9F3990B0895FB019C -:10729000DC0101900D920020E1F70895FB01DC0173 -:1072A0004150504030F08D910190801919F4002028 -:1072B000B9F7881B990B0895FB01DC014150504040 -:1072C00048F001900D920020C9F701C01D92415075 -:1072D0005040E0F70895FB0151915523A9F0BF01FB -:1072E000DC014D9145174111E1F759F4CD010190B1 -:1072F000002049F04D9140154111C9F3FB014111A6 -:10730000EFCF81E090E0019708950F931F93CF9303 -:10731000DF93CDB7DEB72E970FB6F894DEBF0FBE62 -:10732000CDBF0E891F8986E08C831A8309838FEF76 -:107330009FE79E838D83AE01465E5F4F688D798D9A -:10734000CE0101960F94648BEF81F885E00FF11F59 -:1073500010822E960FB6F894DEBF0FBECDBFDF9120 -:10736000CF911F910F91089510E3CCEBD0E300E093 -:1073700005C0802FFE0114DF2196011DCD3BD107F2 -:0A73800080E00807B1F7F894FFCF92 -:10738A000000803F01FF3FFF3FFF3F0101303030E7 -:10739A003081018101810181011014231E101423FF -:1073AA001E01010000002F43019D108D10010101F3 -:1073BA0001D310D310D310D310FFFFFFFFFFFF013B -:1073CA00010101640001010000803FFFFFFFFF028D -:1073DA00FFFFFFFF00005243080000007F430080C8 -:1073EA0054430000524300000000000080C09A99F4 -:1073FA00193E40771B0060EA0000FFF6FF0100809B -:10740A00BB446400FFFF024C5246420000010025C3 -:10741A000031001D000C004000240030001C000B4D -:10742A0000450023002F001B000A001700FFFF047D -:10743A0000060022002B001A000300360037003530 -:10744A0000380003000100020004006D182A18E940 -:10745A001700803B4500803B45000048440000007F -:10746A000056320000537465707261746520746F3F -:10747A006F20686967683A200058595A45000040E9 -:10748A000014005400E6EBC8F002020404020202EF -:10749A000201010101080A14120303040301010194 -:1074AA0001FFFFFF0100010000C0284500C0284578 -:1074BA0000007A440000C8424D313137004352413E -:1074CA0053485F444554454354454400435241534D -:1074DA00485F5245434F5645520043524153485F15 -:1074EA0043414E43454C004653454E534F525F521B -:1074FA0045434F5645520050525553410050696E0C -:10750A00670050524E0046414E00666E007468781D -:10751A000075766C6F004D4D5552455300524553D8 -:10752A004554004E6F7420696E206661726D206D3D -:10753A006F64652E006676004D323800534E004661 -:10754A00697200352E302E322D545A422D32323382 -:10755A00340052657600315F37356D6D5F4D4B33C0 -:10756A002D45494E53795F3130612D453344763686 -:10757A0066756C6C004C616E67004C7A00426561FE -:10758A0074004652002F0001005072757361206921 -:10759A0033204D4B330020703A0020693A002064B2 -:1075AA003A0020633A00504944204175746F74755B -:1075BA006E65206661696C65642E2042616420658F -:1075CA0078747275646572206E756D6265722E00CC -:1075DA00504944204175746F74756E6520737461E7 -:1075EA007274004155544F003E0050494E444120A8 -:1075FA0063616C207374617475733A203100696E2B -:10760A006465782C2074656D702C207573746570B0 -:10761A002C20756D0050494E44412063616C2073E3 -:10762A0074617475733A203000666163746F72799D -:10763A0020726573746F726564007A65726F72691D -:10764A007A6564004F4B004C616E6775616765002F -:10765A0053746174697374696373005368697070F1 -:10766A00696E67207072657000416C6C20446174A9 -:10767A006100416E206572726F72207768696C656D -:10768A002077726974696E6720746F207468652048 -:10769A00534420436172642E004D313132004578E3 -:1076AA0074727564657220003A20003030300056DA -:1076BA00320025642F36004D3834004D203834000E -:1076CA002E67636F004F72616E676500426C61637B -:1076DA006B004661726D206E6F005E004C6F6164D4 -:1076EA00696E672066696C616D656E74005B5354E0 -:1076FA00303A005D5B5354423A005D5B4154303A84 -:10770A00005D5B4154423A005B50524E3A007B00A6 -:10771A005B5446553A005D5B5043443A005D5B4614 -:10772A00454D3A005D5B464E4D3A005D5B54494D0E -:10773A003A005D5B4657523A00352E302E322D54B0 -:10774A005A42007B5B5245533A315D5B46494C3A9B -:10775A00007B5B5245533A305D5B46494C3A007BAD -:10776A005B50524E3A385D007B5B50524E3A395D5F -:10777A00007B5B50524E3A305D5B50464E3A005D9C -:10778A007D007B5B50524E3A355D007B5B45525221 -:10779A003A315D007B5B4552523A325D007B5B4574 -:1077AA0052523A335D007B5B4552523A345D007B5C -:1077BA005B50524E3A39395D0047312058373020F4 -:1077CA005900473120590047312058353020590097 -:1077DA0020202020202020202020004D333031205E -:1077EA0050002049002044004731205835302059A4 -:1077FA0033352045005072696E74206F6B203F004C -:10780A004D33303320453020530053442D505249D4 -:10781A004E54494E47202020202020202020002D91 -:10782A00007C00486F74656E640058005A00426517 -:06783A0064002F30000085 -:00000001FF diff --git a/Firmware/Marlin.h b/Firmware/Marlin.h index 6d965a99e5..9cbdeef486 100755 --- a/Firmware/Marlin.h +++ b/Firmware/Marlin.h @@ -54,13 +54,13 @@ //#include "WString.h" #ifdef AT90USB - #ifdef BTENABLED - #define MYSERIAL bt - #else - #define MYSERIAL Serial - #endif // BTENABLED +#ifdef BTENABLED +#define MYSERIAL bt #else - #define MYSERIAL MSerial +#define MYSERIAL Serial +#endif // BTENABLED +#else +#define MYSERIAL MSerial #endif #include "lcd.h" @@ -113,12 +113,12 @@ void serial_echopair_P(const char *s_P, unsigned long v); //Things to write to serial from Program memory. Saves 400 to 2k of RAM. FORCE_INLINE void serialprintPGM(const char *str) { - char ch=pgm_read_byte(str); - while(ch) - { - MYSERIAL.write(ch); - ch=pgm_read_byte(++str); - } + char ch=pgm_read_byte(str); + while(ch) + { + MYSERIAL.write(ch); + ch=pgm_read_byte(++str); + } } bool is_buffer_empty(); @@ -129,47 +129,47 @@ void ramming(); void manage_inactivity(bool ignore_stepper_queue=false); #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); axis_known_position[X_AXIS] = false; } +#define enable_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() ; +#define enable_x() ; +#define disable_x() ; #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); 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); axis_known_position[Y_AXIS] = false; } - #endif +#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); 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); axis_known_position[Y_AXIS] = false; } +#endif #else - #define enable_y() ; - #define disable_y() ; +#define enable_y() ; +#define disable_y() ; #endif -#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 - #if defined(Z_AXIS_ALWAYS_ON) - #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); axis_known_position[Z_AXIS] = false; } - #else - #define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) - #define disable_z() {} - #endif - #else - #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); 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); axis_known_position[Z_AXIS] = false; } - #endif - #endif +#if defined(Z_ENABLE_PIN) && Z_ENABLE_PIN > -1 +#if defined(Z_AXIS_ALWAYS_ON) +#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); axis_known_position[Z_AXIS] = false; } +#else +#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON) +#define disable_z() {} +#endif #else - #define enable_z() {} - #define disable_z() {} +#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); 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); axis_known_position[Z_AXIS] = false; } +#endif +#endif +#else +#define enable_z() {} +#define disable_z() {} #endif @@ -190,27 +190,27 @@ void manage_inactivity(bool ignore_stepper_queue=false); #if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1) - #define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON) - #define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON) +#define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON) +#define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON) #else - #define enable_e0() /* nothing */ - #define disable_e0() /* nothing */ +#define enable_e0() /* nothing */ +#define disable_e0() /* nothing */ #endif #if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1) - #define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON) - #define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON) +#define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON) +#define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON) #else - #define enable_e1() /* nothing */ - #define disable_e1() /* nothing */ +#define enable_e1() /* nothing */ +#define disable_e1() /* nothing */ #endif #if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1) - #define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON) - #define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON) +#define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON) +#define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON) #else - #define enable_e2() /* nothing */ - #define disable_e2() /* nothing */ +#define enable_e2() /* nothing */ +#define disable_e2() /* nothing */ #endif @@ -262,15 +262,17 @@ void refresh_cmd_timeout(void); extern volatile unsigned long timer0_millis; // An unsynchronized equivalent to a standard Arduino millis() function. // To be used inside an interrupt routine. -FORCE_INLINE unsigned long millis_nc() { return timer0_millis; } +FORCE_INLINE unsigned long millis_nc() { + return timer0_millis; +} #ifdef FAST_PWM_FAN void setPwmFrequency(uint8_t pin, int val); #endif #ifndef CRITICAL_SECTION_START - #define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli(); - #define CRITICAL_SECTION_END SREG = _sreg; +#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli(); +#define CRITICAL_SECTION_END SREG = _sreg; #endif //CRITICAL_SECTION_START extern float homing_feedrate[]; @@ -375,7 +377,7 @@ extern LongTimer safetyTimer; extern void calculate_extruder_multipliers(); -// Similar to the default Arduino delay function, +// Similar to the default Arduino delay function, // but it keeps the background tasks running. extern void delay_keep_alive(unsigned int ms); @@ -406,7 +408,7 @@ bool check_commands(); void uvlo_(); void uvlo_tiny(); -void recover_print(uint8_t automatic); +void recover_print(uint8_t automatic); void setup_uvlo_interrupt(); #if defined(TACH_1) && TACH_1 >-1 diff --git a/Firmware/MarlinSerial.cpp b/Firmware/MarlinSerial.cpp index d3ffdfbeea..7b12bbeef7 100755 --- a/Firmware/MarlinSerial.cpp +++ b/Firmware/MarlinSerial.cpp @@ -15,7 +15,7 @@ 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 */ @@ -26,26 +26,26 @@ uint8_t selectedSerialPort = 0; #ifndef AT90USB -// this next line disables the entire HardwareSerial.cpp, +// 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) #if UART_PRESENT(SERIAL_PORT) - ring_buffer rx_buffer = { { 0 }, 0, 0 }; +ring_buffer rx_buffer = { { 0 }, 0, 0 }; #endif FORCE_INLINE void store_char(unsigned char c) { - int i = (unsigned int)(rx_buffer.head + 1) % RX_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 != rx_buffer.tail) { - rx_buffer.buffer[rx_buffer.head] = c; - rx_buffer.head = i; - } + int i = (unsigned int)(rx_buffer.head + 1) % RX_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 != rx_buffer.tail) { + rx_buffer.buffer[rx_buffer.head] = c; + rx_buffer.head = i; + } } @@ -57,44 +57,44 @@ FORCE_INLINE void store_char(unsigned char c) // As the serial line is not fully utilized, the CPU load is likely around 1%. ISR(M_USARTx_RX_vect) { - // Test for a framing error. - if (M_UCSRxA & (1<> 8; - M_UBRRxL = baud_setting; - - sbi(M_UCSRxB, M_RXENx); - sbi(M_UCSRxB, M_TXENx); - sbi(M_UCSRxB, M_RXCIEx); - + if (useU2X) { + M_UCSRxA = 1 << M_U2Xx; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + M_UCSRxA = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + M_UBRRxH = baud_setting >> 8; + M_UBRRxL = baud_setting; + + sbi(M_UCSRxB, M_RXENx); + sbi(M_UCSRxB, M_TXENx); + sbi(M_UCSRxB, M_RXCIEx); + #ifndef SNMM - if (selectedSerialPort == 1) { //set up also the second serial port - if (useU2X) { - UCSR1A = 1 << U2X1; - baud_setting = (F_CPU / 4 / baud - 1) / 2; - } else { - UCSR1A = 0; - baud_setting = (F_CPU / 8 / baud - 1) / 2; - } - - // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) - UBRR1H = baud_setting >> 8; - UBRR1L = baud_setting; - - sbi(UCSR1B, RXEN1); - sbi(UCSR1B, TXEN1); - sbi(UCSR1B, RXCIE1); - } + if (selectedSerialPort == 1) { //set up also the second serial port + if (useU2X) { + UCSR1A = 1 << U2X1; + baud_setting = (F_CPU / 4 / baud - 1) / 2; + } else { + UCSR1A = 0; + baud_setting = (F_CPU / 8 / baud - 1) / 2; + } + + // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) + UBRR1H = baud_setting >> 8; + UBRR1L = baud_setting; + + sbi(UCSR1B, RXEN1); + sbi(UCSR1B, TXEN1); + sbi(UCSR1B, RXCIE1); + } #endif } void MarlinSerial::end() { - cbi(M_UCSRxB, M_RXENx); - cbi(M_UCSRxB, M_TXENx); - cbi(M_UCSRxB, M_RXCIEx); + cbi(M_UCSRxB, M_RXENx); + cbi(M_UCSRxB, M_TXENx); + cbi(M_UCSRxB, M_RXCIEx); #ifndef SNMM - cbi(UCSR1B, RXEN1); - cbi(UCSR1B, TXEN1); - cbi(UCSR1B, RXCIE1); + cbi(UCSR1B, RXEN1); + cbi(UCSR1B, TXEN1); + cbi(UCSR1B, RXCIE1); #endif } @@ -170,33 +170,33 @@ void MarlinSerial::end() int MarlinSerial::peek(void) { - if (rx_buffer.head == rx_buffer.tail) { - return -1; - } else { - return rx_buffer.buffer[rx_buffer.tail]; - } + if (rx_buffer.head == rx_buffer.tail) { + return -1; + } else { + return rx_buffer.buffer[rx_buffer.tail]; + } } int MarlinSerial::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) % RX_BUFFER_SIZE; - return c; - } + // 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) % RX_BUFFER_SIZE; + return c; + } } void MarlinSerial::flush() { - // don't reverse this or there may be problems if the RX interrupt - // occurs after reading the value of rx_buffer_head but before writing - // the value to rx_buffer_tail; the previous value of rx_buffer_head - // may be written to rx_buffer_tail, making it appear as if the buffer - // were full, not empty. - rx_buffer.head = rx_buffer.tail; + // don't reverse this or there may be problems if the RX interrupt + // occurs after reading the value of rx_buffer_head but before writing + // the value to rx_buffer_tail; the previous value of rx_buffer_head + // may be written to rx_buffer_tail, making it appear as if the buffer + // were full, not empty. + rx_buffer.head = rx_buffer.tail; } @@ -209,54 +209,54 @@ void MarlinSerial::flush() void MarlinSerial::print(char c, int base) { - print((long) c, base); + print((long) c, base); } void MarlinSerial::print(unsigned char b, int base) { - print((unsigned long) b, base); + print((unsigned long) b, base); } void MarlinSerial::print(int n, int base) { - print((long) n, base); + print((long) n, base); } void MarlinSerial::print(unsigned int n, int base) { - print((unsigned long) n, base); + print((unsigned long) n, base); } void MarlinSerial::print(long n, int base) { - if (base == 0) { - write(n); - } else if (base == 10) { - if (n < 0) { - print('-'); - n = -n; + if (base == 0) { + write(n); + } else if (base == 10) { + if (n < 0) { + print('-'); + n = -n; + } + printNumber(n, 10); + } else { + printNumber(n, base); } - printNumber(n, 10); - } else { - printNumber(n, base); - } } void MarlinSerial::print(unsigned long n, int base) { - if (base == 0) write(n); - else printNumber(n, base); + if (base == 0) write(n); + else printNumber(n, base); } void MarlinSerial::print(double n, int digits) { - printFloat(n, digits); + printFloat(n, digits); } void MarlinSerial::println(void) { - print('\r'); - print('\n'); + print('\r'); + print('\n'); } /*void MarlinSerial::println(const String &s) @@ -267,108 +267,108 @@ void MarlinSerial::println(void) void MarlinSerial::println(const char c[]) { - print(c); - println(); + print(c); + println(); } void MarlinSerial::println(char c, int base) { - print(c, base); - println(); + print(c, base); + println(); } void MarlinSerial::println(unsigned char b, int base) { - print(b, base); - println(); + print(b, base); + println(); } void MarlinSerial::println(int n, int base) { - print(n, base); - println(); + print(n, base); + println(); } void MarlinSerial::println(unsigned int n, int base) { - print(n, base); - println(); + print(n, base); + println(); } void MarlinSerial::println(long n, int base) { - print(n, base); - println(); + print(n, base); + println(); } void MarlinSerial::println(unsigned long n, int base) { - print(n, base); - println(); + print(n, base); + println(); } void MarlinSerial::println(double n, int digits) { - print(n, digits); - println(); + print(n, digits); + println(); } // Private Methods ///////////////////////////////////////////////////////////// void MarlinSerial::printNumber(unsigned long n, uint8_t base) { - unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. - unsigned long i = 0; - - if (n == 0) { - print('0'); - return; - } - - while (n > 0) { - buf[i++] = n % base; - n /= base; - } - - for (; i > 0; i--) - print((char) (buf[i - 1] < 10 ? - '0' + buf[i - 1] : - 'A' + buf[i - 1] - 10)); + unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. + unsigned long i = 0; + + if (n == 0) { + print('0'); + return; + } + + while (n > 0) { + buf[i++] = n % base; + n /= base; + } + + for (; i > 0; i--) + print((char) (buf[i - 1] < 10 ? + '0' + buf[i - 1] : + 'A' + buf[i - 1] - 10)); } -void MarlinSerial::printFloat(double number, uint8_t digits) -{ - // Handle negative numbers - if (number < 0.0) - { - 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) - print("."); - - // Extract digits from the remainder one at a time - while (digits-- > 0) - { - remainder *= 10.0; - int toPrint = int(remainder); - print(toPrint); - remainder -= toPrint; - } +void MarlinSerial::printFloat(double number, uint8_t digits) +{ + // Handle negative numbers + if (number < 0.0) + { + 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) + print("."); + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + int toPrint = int(remainder); + print(toPrint); + remainder -= toPrint; + } } // Preinstantiate Objects ////////////////////////////////////////////////////// @@ -380,6 +380,6 @@ MarlinSerial MSerial; // For AT90USB targets use the UART for BT interfacing #if defined(AT90USB) && defined (BTENABLED) - HardwareSerial bt; +HardwareSerial bt; #endif diff --git a/Firmware/MarlinSerial.h b/Firmware/MarlinSerial.h index d596708e4e..6f9c2242f4 100755 --- a/Firmware/MarlinSerial.h +++ b/Firmware/MarlinSerial.h @@ -23,15 +23,15 @@ #define MarlinSerial_h #include "Marlin.h" -#if !defined(SERIAL_PORT) +#if !defined(SERIAL_PORT) #define SERIAL_PORT 0 #endif // The presence of the UBRRH register is used to detect a UART. #define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \ (port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \ - (port == 3 && defined(UBRR3H))) - + (port == 3 && defined(UBRR3H))) + // These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor // requires two levels of indirection to expand macro values properly) #define SERIAL_REGNAME(registerbase,number,suffix) SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) @@ -41,15 +41,15 @@ #define SERIAL_REGNAME_INTERNAL(registerbase,number,suffix) registerbase##number##suffix #endif -// Registers used by MarlinSerial class (these are expanded +// Registers used by MarlinSerial class (these are expanded // depending on selected serial port #define M_UCSRxA SERIAL_REGNAME(UCSR,SERIAL_PORT,A) // defines M_UCSRxA to be UCSRnA where n is the serial port number -#define M_UCSRxB SERIAL_REGNAME(UCSR,SERIAL_PORT,B) -#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,) -#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,) -#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,) -#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,) -#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,) +#define M_UCSRxB SERIAL_REGNAME(UCSR,SERIAL_PORT,B) +#define M_RXENx SERIAL_REGNAME(RXEN,SERIAL_PORT,) +#define M_TXENx SERIAL_REGNAME(TXEN,SERIAL_PORT,) +#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,) +#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,) +#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,) #define M_UBRRxH SERIAL_REGNAME(UBRR,SERIAL_PORT,H) #define M_UBRRxL SERIAL_REGNAME(UBRR,SERIAL_PORT,L) #define M_RXCx SERIAL_REGNAME(RXC,SERIAL_PORT,) @@ -77,28 +77,28 @@ extern uint8_t selectedSerialPort; struct ring_buffer { - unsigned char buffer[RX_BUFFER_SIZE]; - int head; - int tail; + unsigned char buffer[RX_BUFFER_SIZE]; + int head; + int tail; }; #if UART_PRESENT(SERIAL_PORT) - extern ring_buffer rx_buffer; +extern ring_buffer rx_buffer; #endif class MarlinSerial //: public Stream { - public: +public: static void begin(long); static void end(); static int peek(void); static int read(void); static void flush(void); - + static FORCE_INLINE int available(void) { - return (unsigned int)(RX_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % RX_BUFFER_SIZE; + return (unsigned int)(RX_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % RX_BUFFER_SIZE; } /* FORCE_INLINE void write(uint8_t c) @@ -109,20 +109,20 @@ class MarlinSerial //: public Stream M_UDRx = c; } */ - static void write(uint8_t c) - { - if (selectedSerialPort == 0) - { - while (!((M_UCSRxA) & (1 << M_UDREx))); - M_UDRx = c; - } - else if (selectedSerialPort == 1) - { - while (!((UCSR1A) & (1 << UDRE1))); - UDR1 = c; - } - } - + static void write(uint8_t c) + { + if (selectedSerialPort == 0) + { + while (!((M_UCSRxA) & (1 << M_UDREx))); + M_UDRx = c; + } + else if (selectedSerialPort == 1) + { + while (!((UCSR1A) & (1 << UDRE1))); + UDR1 = c; + } + } + static void checkRx(void) { if (selectedSerialPort == 0) { @@ -145,7 +145,7 @@ class MarlinSerial //: public Stream } //selectedSerialPort = 0; #ifdef DEBUG_DUMP_TO_2ND_SERIAL - UDR1 = c; + UDR1 = c; #endif //DEBUG_DUMP_TO_2ND_SERIAL } } @@ -169,44 +169,44 @@ class MarlinSerial //: public Stream } //selectedSerialPort = 1; #ifdef DEBUG_DUMP_TO_2ND_SERIAL - M_UDRx = c; + M_UDRx = c; #endif //DEBUG_DUMP_TO_2ND_SERIAL } } } } - - - private: + + +private: static void printNumber(unsigned long, uint8_t); static void printFloat(double, uint8_t); - - - public: - + + +public: + static FORCE_INLINE void write(const char *str) { - while (*str) - write(*str++); + while (*str) + write(*str++); } static FORCE_INLINE void write(const uint8_t *buffer, size_t size) { - while (size--) - write(*buffer++); + while (size--) + write(*buffer++); } -/* static FORCE_INLINE void print(const String &s) - { - for (int i = 0; i < (int)s.length(); i++) { - write(s[i]); - } - }*/ - + /* static FORCE_INLINE void print(const String &s) + { + for (int i = 0; i < (int)s.length(); i++) { + write(s[i]); + } + }*/ + static FORCE_INLINE void print(const char *str) { - write(str); + write(str); } static void print(char, int = BYTE); static void print(unsigned char, int = BYTE); @@ -233,7 +233,7 @@ extern MarlinSerial MSerial; // Use the UART for BT in AT90USB configurations #if defined(AT90USB) && defined (BTENABLED) - extern HardwareSerial bt; +extern HardwareSerial bt; #endif #endif diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 8b61a3fe34..1cfaca6ee1 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -47,14 +47,14 @@ #ifdef ENABLE_AUTO_BED_LEVELING #include "vector_3.h" - #ifdef AUTO_BED_LEVELING_GRID - #include "qr_solve.h" - #endif +#ifdef AUTO_BED_LEVELING_GRID +#include "qr_solve.h" +#endif #endif // ENABLE_AUTO_BED_LEVELING #ifdef MESH_BED_LEVELING - #include "mesh_bed_leveling.h" - #include "mesh_bed_calibration.h" +#include "mesh_bed_leveling.h" +#include "mesh_bed_calibration.h" #endif #include "printers.h" @@ -141,7 +141,7 @@ #define PRINTING_TYPE_SD 0 #define PRINTING_TYPE_USB 1 -//filament types +//filament types #define FILAMENT_DEFAULT 0 #define FILAMENT_FLEX 1 #define FILAMENT_PVA 2 @@ -179,13 +179,13 @@ bool axis_relative_modes[] = AXIS_RELATIVE_MODES; int feedmultiply=100; //100->1 200->2 int extrudemultiply=100; //100->1 200->2 int extruder_multiply[EXTRUDERS] = {100 - #if EXTRUDERS > 1 - , 100 - #if EXTRUDERS > 2 - , 100 - #endif - #endif -}; +#if EXTRUDERS > 1 + , 100 +#if EXTRUDERS > 2 + , 100 +#endif +#endif + }; int bowden_length[4] = {385, 385, 385, 385}; @@ -237,13 +237,13 @@ bool sortAlpha = false; float extruder_multiplier[EXTRUDERS] = {1.0 - #if EXTRUDERS > 1 - , 1.0 - #if EXTRUDERS > 2 - , 1.0 - #endif - #endif -}; +#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 }; //shortcuts for more readable code @@ -258,10 +258,10 @@ bool axis_known_position[3] = {false, false, false}; // Extruder offset #if EXTRUDERS > 1 - #define NUM_EXTRUDER_OFFSETS 2 // only in XY plane +#define NUM_EXTRUDER_OFFSETS 2 // only in XY plane float extruder_offset[NUM_EXTRUDER_OFFSETS][EXTRUDERS] = { #if defined(EXTRUDER_OFFSET_X) && defined(EXTRUDER_OFFSET_Y) - EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y + EXTRUDER_OFFSET_X, EXTRUDER_OFFSET_Y #endif }; #endif @@ -270,43 +270,43 @@ uint8_t active_extruder = 0; int fanSpeed=0; #ifdef FWRETRACT - bool retracted[EXTRUDERS]={false - #if EXTRUDERS > 1 - , false - #if EXTRUDERS > 2 - , false - #endif - #endif - }; - bool retracted_swap[EXTRUDERS]={false - #if EXTRUDERS > 1 - , false - #if EXTRUDERS > 2 - , false - #endif - #endif - }; - - float retract_length_swap = RETRACT_LENGTH_SWAP; - float retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP; -#endif - - #ifdef PS_DEFAULT_OFF - bool powersupply = false; - #else - bool powersupply = true; - #endif +bool retracted[EXTRUDERS]= {false +#if EXTRUDERS > 1 + , false +#if EXTRUDERS > 2 + , false +#endif +#endif + }; +bool retracted_swap[EXTRUDERS]= {false +#if EXTRUDERS > 1 + , false +#if EXTRUDERS > 2 + , false +#endif +#endif + }; + +float retract_length_swap = RETRACT_LENGTH_SWAP; +float retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP; +#endif + +#ifdef PS_DEFAULT_OFF +bool powersupply = false; +#else +bool powersupply = true; +#endif bool cancel_heatup = false ; #ifdef HOST_KEEPALIVE_FEATURE - - int busy_state = NOT_BUSY; - static long prev_busy_signal_ms = -1; - uint8_t host_keepalive_interval = HOST_KEEPALIVE_INTERVAL; + +int busy_state = NOT_BUSY; +static long prev_busy_signal_ms = -1; +uint8_t host_keepalive_interval = HOST_KEEPALIVE_INTERVAL; #else - #define host_keepalive(); - #define KEEPALIVE_STATE(n); +#define host_keepalive(); +#define KEEPALIVE_STATE(n); #endif @@ -318,7 +318,7 @@ uint8_t important_status; uint8_t saved_filament_type; -// save/restore printing in case that mmu was not responding +// save/restore printing in case that mmu was not responding bool mmu_print_saved = false; // storing estimated time to end of print counted by slicer @@ -343,7 +343,7 @@ static float feedrate = 1500.0, next_feedrate, saved_feedrate; // Determines Absolute or Relative Coordinates. // Also there is bool axis_relative_modes[] per axis flag. -static bool relative_mode = false; +static bool relative_mode = false; const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42 @@ -367,7 +367,7 @@ bool extruder_under_pressure = true; bool Stopped=false; #if NUM_SERVOS > 0 - Servo servos[NUM_SERVOS]; +Servo servos[NUM_SERVOS]; #endif bool CooldownNoWait = true; @@ -407,100 +407,111 @@ uint16_t gcode_in_progress = 0; uint16_t mcode_in_progress = 0; void serial_echopair_P(const char *s_P, float v) - { serialprintPGM(s_P); SERIAL_ECHO(v); } +{ + serialprintPGM(s_P); + SERIAL_ECHO(v); +} void serial_echopair_P(const char *s_P, double v) - { serialprintPGM(s_P); SERIAL_ECHO(v); } +{ + serialprintPGM(s_P); + SERIAL_ECHO(v); +} void serial_echopair_P(const char *s_P, unsigned long v) - { serialprintPGM(s_P); SERIAL_ECHO(v); } +{ + serialprintPGM(s_P); + SERIAL_ECHO(v); +} #ifdef SDSUPPORT - #include "SdFatUtil.h" - int freeMemory() { return SdFatUtil::FreeRam(); } +#include "SdFatUtil.h" +int freeMemory() { + return SdFatUtil::FreeRam(); +} #else - extern "C" { +extern "C" { extern unsigned int __bss_end; extern unsigned int __heap_start; extern void *__brkval; int freeMemory() { - int free_memory; + int free_memory; - if ((int)__brkval == 0) - free_memory = ((int)&free_memory) - ((int)&__bss_end); - else - free_memory = ((int)&free_memory) - ((int)__brkval); + if ((int)__brkval == 0) + free_memory = ((int)&free_memory) - ((int)&__bss_end); + else + free_memory = ((int)&free_memory) - ((int)__brkval); - return free_memory; + return free_memory; } - } +} #endif //!SDSUPPORT void setup_killpin() { - #if defined(KILL_PIN) && KILL_PIN > -1 +#if defined(KILL_PIN) && KILL_PIN > -1 SET_INPUT(KILL_PIN); WRITE(KILL_PIN,HIGH); - #endif +#endif } // Set home pin void setup_homepin(void) { #if defined(HOME_PIN) && HOME_PIN > -1 - SET_INPUT(HOME_PIN); - WRITE(HOME_PIN,HIGH); + SET_INPUT(HOME_PIN); + WRITE(HOME_PIN,HIGH); #endif } void setup_photpin() { - #if defined(PHOTOGRAPH_PIN) && PHOTOGRAPH_PIN > -1 +#if defined(PHOTOGRAPH_PIN) && PHOTOGRAPH_PIN > -1 SET_OUTPUT(PHOTOGRAPH_PIN); WRITE(PHOTOGRAPH_PIN, LOW); - #endif +#endif } void setup_powerhold() { - #if defined(SUICIDE_PIN) && SUICIDE_PIN > -1 +#if defined(SUICIDE_PIN) && SUICIDE_PIN > -1 SET_OUTPUT(SUICIDE_PIN); WRITE(SUICIDE_PIN, HIGH); - #endif - #if defined(PS_ON_PIN) && PS_ON_PIN > -1 +#endif +#if defined(PS_ON_PIN) && PS_ON_PIN > -1 SET_OUTPUT(PS_ON_PIN); - #if defined(PS_DEFAULT_OFF) - WRITE(PS_ON_PIN, PS_ON_ASLEEP); - #else - WRITE(PS_ON_PIN, PS_ON_AWAKE); - #endif - #endif +#if defined(PS_DEFAULT_OFF) + WRITE(PS_ON_PIN, PS_ON_ASLEEP); +#else + WRITE(PS_ON_PIN, PS_ON_AWAKE); +#endif +#endif } void suicide() { - #if defined(SUICIDE_PIN) && SUICIDE_PIN > -1 +#if defined(SUICIDE_PIN) && SUICIDE_PIN > -1 SET_OUTPUT(SUICIDE_PIN); WRITE(SUICIDE_PIN, LOW); - #endif +#endif } void servo_init() { - #if (NUM_SERVOS >= 1) && defined(SERVO0_PIN) && (SERVO0_PIN > -1) +#if (NUM_SERVOS >= 1) && defined(SERVO0_PIN) && (SERVO0_PIN > -1) servos[0].attach(SERVO0_PIN); - #endif - #if (NUM_SERVOS >= 2) && defined(SERVO1_PIN) && (SERVO1_PIN > -1) +#endif +#if (NUM_SERVOS >= 2) && defined(SERVO1_PIN) && (SERVO1_PIN > -1) servos[1].attach(SERVO1_PIN); - #endif - #if (NUM_SERVOS >= 3) && defined(SERVO2_PIN) && (SERVO2_PIN > -1) +#endif +#if (NUM_SERVOS >= 3) && defined(SERVO2_PIN) && (SERVO2_PIN > -1) servos[2].attach(SERVO2_PIN); - #endif - #if (NUM_SERVOS >= 4) && defined(SERVO3_PIN) && (SERVO3_PIN > -1) +#endif +#if (NUM_SERVOS >= 4) && defined(SERVO3_PIN) && (SERVO3_PIN > -1) servos[3].attach(SERVO3_PIN); - #endif - #if (NUM_SERVOS >= 5) - #error "TODO: enter initalisation code for more servos" - #endif +#endif +#if (NUM_SERVOS >= 5) +#error "TODO: enter initalisation code for more servos" +#endif } @@ -513,138 +524,138 @@ extern int8_t CrashDetectMenu; void crashdet_enable() { - tmc2130_sg_stop_on_crash = true; - eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0xFF); - CrashDetectMenu = 1; + tmc2130_sg_stop_on_crash = true; + eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0xFF); + CrashDetectMenu = 1; } void crashdet_disable() { - tmc2130_sg_stop_on_crash = false; - tmc2130_sg_crash = 0; - eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0x00); - CrashDetectMenu = 0; + tmc2130_sg_stop_on_crash = false; + tmc2130_sg_crash = 0; + eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0x00); + CrashDetectMenu = 0; } void crashdet_stop_and_save_print() { - stop_and_save_print_to_ram(10, -default_retraction); //XY - no change, Z 10mm up, E -1mm retract + stop_and_save_print_to_ram(10, -default_retraction); //XY - no change, Z 10mm up, E -1mm retract } void crashdet_restore_print_and_continue() { - restore_print_from_ram_and_continue(default_retraction); //XYZ = orig, E +1mm unretract + restore_print_from_ram_and_continue(default_retraction); //XYZ = orig, E +1mm unretract // babystep_apply(); } void crashdet_stop_and_save_print2() { - cli(); - planner_abort_hard(); //abort printing - cmdqueue_reset(); //empty cmdqueue - card.sdprinting = false; - card.closefile(); - // Reset and re-enable the stepper timer just before the global interrupts are enabled. - st_reset_timer(); - sei(); + cli(); + planner_abort_hard(); //abort printing + cmdqueue_reset(); //empty cmdqueue + card.sdprinting = false; + card.closefile(); + // Reset and re-enable the stepper timer just before the global interrupts are enabled. + st_reset_timer(); + sei(); } void crashdet_detected(uint8_t mask) { - st_synchronize(); - static uint8_t crashDet_counter = 0; - bool automatic_recovery_after_crash = true; + st_synchronize(); + static uint8_t crashDet_counter = 0; + bool automatic_recovery_after_crash = true; - if (crashDet_counter++ == 0) { - crashDetTimer.start(); - } - else if (crashDetTimer.expired(CRASHDET_TIMER * 1000ul)){ - crashDetTimer.stop(); - crashDet_counter = 0; - } - else if(crashDet_counter == CRASHDET_COUNTER_MAX){ - automatic_recovery_after_crash = false; - crashDetTimer.stop(); - crashDet_counter = 0; - } - else { - crashDetTimer.start(); - } + if (crashDet_counter++ == 0) { + crashDetTimer.start(); + } + else if (crashDetTimer.expired(CRASHDET_TIMER * 1000ul)) { + crashDetTimer.stop(); + crashDet_counter = 0; + } + else if(crashDet_counter == CRASHDET_COUNTER_MAX) { + automatic_recovery_after_crash = false; + crashDetTimer.stop(); + crashDet_counter = 0; + } + else { + crashDetTimer.start(); + } + + lcd_update_enable(true); + lcd_clear(); + lcd_update(2); - lcd_update_enable(true); - lcd_clear(); - lcd_update(2); + if (mask & X_AXIS_MASK) + { + eeprom_update_byte((uint8_t*)EEPROM_CRASH_COUNT_X, eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X) + 1); + eeprom_update_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT, eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT) + 1); + } + if (mask & Y_AXIS_MASK) + { + eeprom_update_byte((uint8_t*)EEPROM_CRASH_COUNT_Y, eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y) + 1); + eeprom_update_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT, eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT) + 1); + } - if (mask & X_AXIS_MASK) - { - eeprom_update_byte((uint8_t*)EEPROM_CRASH_COUNT_X, eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X) + 1); - eeprom_update_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT, eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT) + 1); - } - if (mask & Y_AXIS_MASK) - { - eeprom_update_byte((uint8_t*)EEPROM_CRASH_COUNT_Y, eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y) + 1); - eeprom_update_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT, eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT) + 1); - } - - - - lcd_update_enable(true); - lcd_update(2); - lcd_setstatuspgm(_T(MSG_CRASH_DETECTED)); - gcode_G28(true, true, false); //home X and Y - st_synchronize(); - - if (automatic_recovery_after_crash) { - enquecommand_P(PSTR("CRASH_RECOVER")); - }else{ - setTargetHotend(0, active_extruder); - bool yesno = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Crash detected. Resume print?"), false); - lcd_update_enable(true); - if (yesno) - { - enquecommand_P(PSTR("CRASH_RECOVER")); - } - else - { - enquecommand_P(PSTR("CRASH_CANCEL")); - } - } + + + lcd_update_enable(true); + lcd_update(2); + lcd_setstatuspgm(_T(MSG_CRASH_DETECTED)); + gcode_G28(true, true, false); //home X and Y + st_synchronize(); + + if (automatic_recovery_after_crash) { + enquecommand_P(PSTR("CRASH_RECOVER")); + } else { + setTargetHotend(0, active_extruder); + bool yesno = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Crash detected. Resume print?"), false); + lcd_update_enable(true); + if (yesno) + { + enquecommand_P(PSTR("CRASH_RECOVER")); + } + else + { + enquecommand_P(PSTR("CRASH_CANCEL")); + } + } } void crashdet_recover() { - crashdet_restore_print_and_continue(); - tmc2130_sg_stop_on_crash = true; + crashdet_restore_print_and_continue(); + tmc2130_sg_stop_on_crash = true; } void crashdet_cancel() { - saved_printing = false; - tmc2130_sg_stop_on_crash = true; - if (saved_printing_type == PRINTING_TYPE_SD) { - lcd_print_stop(); - }else if(saved_printing_type == PRINTING_TYPE_USB){ - SERIAL_ECHOLNPGM("// action:cancel"); //for Octoprint: works the same as clicking "Abort" button in Octoprint GUI - SERIAL_PROTOCOLLNRPGM(_T(MSG_OK)); - } + saved_printing = false; + tmc2130_sg_stop_on_crash = true; + if (saved_printing_type == PRINTING_TYPE_SD) { + lcd_print_stop(); + } else if(saved_printing_type == PRINTING_TYPE_USB) { + SERIAL_ECHOLNPGM("// action:cancel"); //for Octoprint: works the same as clicking "Abort" button in Octoprint GUI + SERIAL_PROTOCOLLNRPGM(_T(MSG_OK)); + } } #endif //TMC2130 void failstats_reset_print() { - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_X, 0); - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_Y, 0); - eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, 0); - eeprom_update_byte((uint8_t *)EEPROM_POWER_COUNT, 0); + eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_X, 0); + eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_Y, 0); + eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, 0); + eeprom_update_byte((uint8_t *)EEPROM_POWER_COUNT, 0); } #ifdef MESH_BED_LEVELING - enum MeshLevelingState { MeshReport, MeshStart, MeshNext, MeshSet }; +enum MeshLevelingState { MeshReport, MeshStart, MeshNext, MeshSet }; #endif @@ -653,127 +664,127 @@ void failstats_reset_print() // Level input parameter sets depth of reset int er_progress = 0; static void factory_reset(char level) -{ - lcd_clear(); +{ + lcd_clear(); switch (level) { - - // Level 0: Language reset - case 0: -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + + // Level 0: Language reset + case 0: + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) WRITE(BEEPER, HIGH); - _delay_ms(100); - WRITE(BEEPER, LOW); - lang_reset(); - break; - - //Level 1: Reset statistics - case 1: -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - WRITE(BEEPER, HIGH); - _delay_ms(100); - WRITE(BEEPER, LOW); - eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); - eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); - - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_X, 0); - eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_Y, 0); - eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, 0); - eeprom_update_byte((uint8_t *)EEPROM_POWER_COUNT, 0); - - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_X_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_Y_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_POWER_COUNT_TOT, 0); - - lcd_menu_statistics(); - - break; - - // Level 2: Prepare for shipping - case 2: - //lcd_puts_P(PSTR("Factory RESET")); - //lcd_puts_at_P(1,2,PSTR("Shipping prep")); - - // Force language selection at the next boot up. - lang_reset(); - // Force the "Follow calibration flow" message at the next boot up. - calibration_status_store(CALIBRATION_STATUS_Z_CALIBRATION); - eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard - farm_no = 0; - farm_mode = false; - eeprom_update_byte((uint8_t*)EEPROM_FARM_MODE, farm_mode); - EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no); + _delay_ms(100); + WRITE(BEEPER, LOW); + lang_reset(); + break; + + //Level 1: Reset statistics + case 1: + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + WRITE(BEEPER, HIGH); + _delay_ms(100); + WRITE(BEEPER, LOW); + eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); + eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); - eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); - eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_X_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_Y_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, 0); - eeprom_update_word((uint16_t *)EEPROM_POWER_COUNT_TOT, 0); + eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_X, 0); + eeprom_update_byte((uint8_t *)EEPROM_CRASH_COUNT_Y, 0); + eeprom_update_byte((uint8_t *)EEPROM_FERROR_COUNT, 0); + eeprom_update_byte((uint8_t *)EEPROM_POWER_COUNT, 0); + + eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_X_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_Y_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_POWER_COUNT_TOT, 0); + + lcd_menu_statistics(); + + break; + + // Level 2: Prepare for shipping + case 2: + //lcd_puts_P(PSTR("Factory RESET")); + //lcd_puts_at_P(1,2,PSTR("Shipping prep")); + + // Force language selection at the next boot up. + lang_reset(); + // Force the "Follow calibration flow" message at the next boot up. + calibration_status_store(CALIBRATION_STATUS_Z_CALIBRATION); + eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard + farm_no = 0; + farm_mode = false; + eeprom_update_byte((uint8_t*)EEPROM_FARM_MODE, farm_mode); + EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no); + + eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); + eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); + eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_X_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_CRASH_COUNT_Y_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_FERROR_COUNT_TOT, 0); + eeprom_update_word((uint16_t *)EEPROM_POWER_COUNT_TOT, 0); #ifdef FILAMENT_SENSOR - fsensor_enable(); - fsensor_autoload_set(true); + fsensor_enable(); + fsensor_autoload_set(true); #endif //FILAMENT_SENSOR - -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - WRITE(BEEPER, HIGH); - _delay_ms(100); - WRITE(BEEPER, LOW); - //_delay_ms(2000); - break; - // Level 3: erase everything, whole EEPROM will be set to 0xFF - - case 3: - lcd_puts_P(PSTR("Factory RESET")); - lcd_puts_at_P(1, 2, PSTR("ERASING all data")); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + WRITE(BEEPER, HIGH); + _delay_ms(100); + WRITE(BEEPER, LOW); + //_delay_ms(2000); + break; -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - WRITE(BEEPER, HIGH); - _delay_ms(100); - WRITE(BEEPER, LOW); + // Level 3: erase everything, whole EEPROM will be set to 0xFF - er_progress = 0; - lcd_puts_at_P(3, 3, PSTR(" ")); - lcd_set_cursor(3, 3); - lcd_print(er_progress); + case 3: + lcd_puts_P(PSTR("Factory RESET")); + lcd_puts_at_P(1, 2, PSTR("ERASING all data")); - // Erase EEPROM - for (int i = 0; i < 4096; i++) { - eeprom_update_byte((uint8_t*)i, 0xFF); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + WRITE(BEEPER, HIGH); + _delay_ms(100); + WRITE(BEEPER, LOW); + + er_progress = 0; + lcd_puts_at_P(3, 3, PSTR(" ")); + lcd_set_cursor(3, 3); + lcd_print(er_progress); + + // Erase EEPROM + for (int i = 0; i < 4096; i++) { + eeprom_update_byte((uint8_t*)i, 0xFF); + + if (i % 41 == 0) { + er_progress++; + lcd_puts_at_P(3, 3, PSTR(" ")); + lcd_set_cursor(3, 3); + lcd_print(er_progress); + lcd_puts_P(PSTR("%")); + } - if (i % 41 == 0) { - er_progress++; - lcd_puts_at_P(3, 3, PSTR(" ")); - lcd_set_cursor(3, 3); - lcd_print(er_progress); - lcd_puts_P(PSTR("%")); - } + } - } + break; + case 4: + bowden_menu(); + break; - break; - case 4: - bowden_menu(); - break; - - default: - break; + default: + break; } - + } extern "C" { -FILE _uartout; //= {0}; Global variable is always zero initialized. No need to explicitly state this. + FILE _uartout; //= {0}; Global variable is always zero initialized. No need to explicitly state this. } int uart_putchar(char c, FILE *) { - MYSERIAL.write(c); - return 0; + MYSERIAL.write(c); + return 0; } @@ -788,86 +799,99 @@ void lcd_splash() } -void factory_reset() +void factory_reset() { - KEEPALIVE_STATE(PAUSED_FOR_USER); - if (!READ(BTN_ENC)) - { - _delay_ms(1000); - if (!READ(BTN_ENC)) - { - lcd_clear(); + KEEPALIVE_STATE(PAUSED_FOR_USER); + if (!READ(BTN_ENC)) + { + _delay_ms(1000); + if (!READ(BTN_ENC)) + { + lcd_clear(); - lcd_puts_P(PSTR("Factory RESET")); + lcd_puts_P(PSTR("Factory RESET")); - SET_OUTPUT(BEEPER); -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - WRITE(BEEPER, HIGH); + SET_OUTPUT(BEEPER); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + WRITE(BEEPER, HIGH); - while (!READ(BTN_ENC)); + while (!READ(BTN_ENC)); - WRITE(BEEPER, LOW); + WRITE(BEEPER, LOW); - _delay_ms(2000); + _delay_ms(2000); - char level = reset_menu(); - factory_reset(level); + char level = reset_menu(); + factory_reset(level); - switch (level) { - case 0: _delay_ms(0); break; - case 1: _delay_ms(0); break; - case 2: _delay_ms(0); break; - case 3: _delay_ms(0); break; - } + switch (level) { + case 0: + _delay_ms(0); + break; + case 1: + _delay_ms(0); + break; + case 2: + _delay_ms(0); + break; + case 3: + _delay_ms(0); + break; + } - } - } - KEEPALIVE_STATE(IN_HANDLER); + } + } + KEEPALIVE_STATE(IN_HANDLER); } void show_fw_version_warnings() { - if (FW_DEV_VERSION == FW_VERSION_GOLD || FW_DEV_VERSION == FW_VERSION_RC) return; - switch (FW_DEV_VERSION) { - case(FW_VERSION_ALPHA): lcd_show_fullscreen_message_and_wait_P(_i("You are using firmware alpha version. This is development version. Using this version is not recommended and may cause printer damage.")); break;////MSG_FW_VERSION_ALPHA c=20 r=8 - case(FW_VERSION_BETA): lcd_show_fullscreen_message_and_wait_P(_i("You are using firmware beta version. This is development version. Using this version is not recommended and may cause printer damage.")); break;////MSG_FW_VERSION_BETA c=20 r=8 - case(FW_VERSION_DEVEL): - case(FW_VERSION_DEBUG): - lcd_update_enable(false); - lcd_clear(); - #if FW_DEV_VERSION == FW_VERSION_DEVEL - lcd_puts_at_P(0, 0, PSTR("Development build !!")); - #else - lcd_puts_at_P(0, 0, PSTR("Debbugging build !!!")); - #endif - lcd_puts_at_P(0, 1, PSTR("May destroy printer!")); - lcd_puts_at_P(0, 2, PSTR("ver ")); lcd_puts_P(PSTR(FW_VERSION_FULL)); - lcd_puts_at_P(0, 3, PSTR(FW_REPOSITORY)); - lcd_wait_for_click(); - break; + if (FW_DEV_VERSION == FW_VERSION_GOLD || FW_DEV_VERSION == FW_VERSION_RC) return; + switch (FW_DEV_VERSION) { + case(FW_VERSION_ALPHA): + lcd_show_fullscreen_message_and_wait_P(_i("You are using firmware alpha version. This is development version. Using this version is not recommended and may cause printer damage.")); + break;////MSG_FW_VERSION_ALPHA c=20 r=8 + case(FW_VERSION_BETA): + lcd_show_fullscreen_message_and_wait_P(_i("You are using firmware beta version. This is development version. Using this version is not recommended and may cause printer damage.")); + break;////MSG_FW_VERSION_BETA c=20 r=8 + case(FW_VERSION_DEVEL): + case(FW_VERSION_DEBUG): + lcd_update_enable(false); + lcd_clear(); +#if FW_DEV_VERSION == FW_VERSION_DEVEL + lcd_puts_at_P(0, 0, PSTR("Development build !!")); +#else + lcd_puts_at_P(0, 0, PSTR("Debbugging build !!!")); +#endif + lcd_puts_at_P(0, 1, PSTR("May destroy printer!")); + lcd_puts_at_P(0, 2, PSTR("ver ")); + lcd_puts_P(PSTR(FW_VERSION_FULL)); + lcd_puts_at_P(0, 3, PSTR(FW_REPOSITORY)); + lcd_wait_for_click(); + break; // default: lcd_show_fullscreen_message_and_wait_P(_i("WARNING: This is an unofficial, unsupported build. Use at your own risk!")); break;////MSG_FW_VERSION_UNKNOWN c=20 r=8 - } - lcd_update_enable(true); + } + lcd_update_enable(true); } uint8_t check_printer_version() { - uint8_t version_changed = 0; - uint16_t printer_type = eeprom_read_word((uint16_t*)EEPROM_PRINTER_TYPE); - uint16_t motherboard = eeprom_read_word((uint16_t*)EEPROM_BOARD_TYPE); + uint8_t version_changed = 0; + uint16_t printer_type = eeprom_read_word((uint16_t*)EEPROM_PRINTER_TYPE); + uint16_t motherboard = eeprom_read_word((uint16_t*)EEPROM_BOARD_TYPE); - if (printer_type != PRINTER_TYPE) { - if (printer_type == 0xffff) eeprom_write_word((uint16_t*)EEPROM_PRINTER_TYPE, PRINTER_TYPE); - else version_changed |= 0b10; - } - if (motherboard != MOTHERBOARD) { - if(motherboard == 0xffff) eeprom_write_word((uint16_t*)EEPROM_BOARD_TYPE, MOTHERBOARD); - else version_changed |= 0b01; - } - return version_changed; + if (printer_type != PRINTER_TYPE) { + if (printer_type == 0xffff) eeprom_write_word((uint16_t*)EEPROM_PRINTER_TYPE, PRINTER_TYPE); + else version_changed |= 0b10; + } + if (motherboard != MOTHERBOARD) { + if(motherboard == 0xffff) eeprom_write_word((uint16_t*)EEPROM_BOARD_TYPE, MOTHERBOARD); + else version_changed |= 0b01; + } + return version_changed; } #ifdef BOOTAPP @@ -885,38 +909,38 @@ uint8_t check_printer_version() void update_sec_lang_from_external_flash() { - if ((boot_app_magic == BOOT_APP_MAGIC) && (boot_app_flags & BOOT_APP_FLG_USER0)) - { - uint8_t lang = boot_reserved >> 4; - uint8_t state = boot_reserved & 0xf; - lang_table_header_t header; - uint32_t src_addr; - if (lang_get_header(lang, &header, &src_addr)) - { - fputs_P(PSTR(ESC_H(1,3) "Language update."), lcdout); - for (uint8_t i = 0; i < state; i++) fputc('.', lcdout); - delay(100); - boot_reserved = (state + 1) | (lang << 4); - if ((state * LANGBOOT_BLOCKSIZE) < header.size) - { - cli(); - uint16_t size = header.size - state * LANGBOOT_BLOCKSIZE; - if (size > LANGBOOT_BLOCKSIZE) size = LANGBOOT_BLOCKSIZE; - w25x20cl_rd_data(src_addr + state * LANGBOOT_BLOCKSIZE, (uint8_t*)LANGBOOT_RAMBUFFER, size); - if (state == 0) - { - //TODO - check header integrity - } - bootapp_ram2flash(LANGBOOT_RAMBUFFER, _SEC_LANG_TABLE + state * LANGBOOT_BLOCKSIZE, size); - } - else - { - //TODO - check sec lang data integrity - eeprom_update_byte((unsigned char *)EEPROM_LANG, LANG_ID_SEC); - } - } - } - boot_app_flags &= ~BOOT_APP_FLG_USER0; + if ((boot_app_magic == BOOT_APP_MAGIC) && (boot_app_flags & BOOT_APP_FLG_USER0)) + { + uint8_t lang = boot_reserved >> 4; + uint8_t state = boot_reserved & 0xf; + lang_table_header_t header; + uint32_t src_addr; + if (lang_get_header(lang, &header, &src_addr)) + { + fputs_P(PSTR(ESC_H(1,3) "Language update."), lcdout); + for (uint8_t i = 0; i < state; i++) fputc('.', lcdout); + delay(100); + boot_reserved = (state + 1) | (lang << 4); + if ((state * LANGBOOT_BLOCKSIZE) < header.size) + { + cli(); + uint16_t size = header.size - state * LANGBOOT_BLOCKSIZE; + if (size > LANGBOOT_BLOCKSIZE) size = LANGBOOT_BLOCKSIZE; + w25x20cl_rd_data(src_addr + state * LANGBOOT_BLOCKSIZE, (uint8_t*)LANGBOOT_RAMBUFFER, size); + if (state == 0) + { + //TODO - check header integrity + } + bootapp_ram2flash(LANGBOOT_RAMBUFFER, _SEC_LANG_TABLE + state * LANGBOOT_BLOCKSIZE, size); + } + else + { + //TODO - check sec lang data integrity + eeprom_update_byte((unsigned char *)EEPROM_LANG, LANG_ID_SEC); + } + } + } + boot_app_flags &= ~BOOT_APP_FLG_USER0; } @@ -924,38 +948,38 @@ void update_sec_lang_from_external_flash() uint8_t lang_xflash_enum_codes(uint16_t* codes) { - lang_table_header_t header; - uint8_t count = 0; - uint32_t addr = 0x00000; - while (1) - { - printf_P(_n("LANGTABLE%d:"), count); - w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); - if (header.magic != LANG_MAGIC) - { - printf_P(_n("NG!\n")); - break; - } - printf_P(_n("OK\n")); - printf_P(_n(" _lt_magic = 0x%08lx %S\n"), header.magic, (header.magic==LANG_MAGIC)?_n("OK"):_n("NA")); - printf_P(_n(" _lt_size = 0x%04x (%d)\n"), header.size, header.size); - printf_P(_n(" _lt_count = 0x%04x (%d)\n"), header.count, header.count); - printf_P(_n(" _lt_chsum = 0x%04x\n"), header.checksum); - printf_P(_n(" _lt_code = 0x%04x (%c%c)\n"), header.code, header.code >> 8, header.code & 0xff); - printf_P(_n(" _lt_sign = 0x%08lx\n"), header.signature); - - addr += header.size; - codes[count] = header.code; - count ++; - } - return count; + lang_table_header_t header; + uint8_t count = 0; + uint32_t addr = 0x00000; + while (1) + { + printf_P(_n("LANGTABLE%d:"), count); + w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); + if (header.magic != LANG_MAGIC) + { + printf_P(_n("NG!\n")); + break; + } + printf_P(_n("OK\n")); + printf_P(_n(" _lt_magic = 0x%08lx %S\n"), header.magic, (header.magic==LANG_MAGIC)?_n("OK"):_n("NA")); + printf_P(_n(" _lt_size = 0x%04x (%d)\n"), header.size, header.size); + printf_P(_n(" _lt_count = 0x%04x (%d)\n"), header.count, header.count); + printf_P(_n(" _lt_chsum = 0x%04x\n"), header.checksum); + printf_P(_n(" _lt_code = 0x%04x (%c%c)\n"), header.code, header.code >> 8, header.code & 0xff); + printf_P(_n(" _lt_sign = 0x%08lx\n"), header.signature); + + addr += header.size; + codes[count] = header.code; + count ++; + } + return count; } void list_sec_lang_from_external_flash() { - uint16_t codes[8]; - uint8_t count = lang_xflash_enum_codes(codes); - printf_P(_n("XFlash lang count = %hhd\n"), count); + uint16_t codes[8]; + uint8_t count = lang_xflash_enum_codes(codes); + printf_P(_n("XFlash lang count = %hhd\n"), count); } #endif //DEBUG_W25X20CL @@ -966,75 +990,75 @@ void list_sec_lang_from_external_flash() // "Setup" function is called by the Arduino framework on startup. -// Before startup, the Timers-functions (PWM)/Analog RW and HardwareSerial provided by the Arduino-code +// Before startup, the Timers-functions (PWM)/Analog RW and HardwareSerial provided by the Arduino-code // are initialized by the main() routine provided by the Arduino framework. void setup() { - mmu_init(); - - ultralcd_init(); + mmu_init(); + + ultralcd_init(); - spi_init(); + spi_init(); - lcd_splash(); - Sound_Init(); // also guarantee "SET_OUTPUT(BEEPER)" + lcd_splash(); + Sound_Init(); // also guarantee "SET_OUTPUT(BEEPER)" #ifdef W25X20CL - if (!w25x20cl_init()) - kill(_i("External SPI flash W25X20CL not responding.")); - // Enter an STK500 compatible Optiboot boot loader waiting for flashing the languages to an external flash memory. - optiboot_w25x20cl_enter(); + if (!w25x20cl_init()) + kill(_i("External SPI flash W25X20CL not responding.")); + // Enter an STK500 compatible Optiboot boot loader waiting for flashing the languages to an external flash memory. + optiboot_w25x20cl_enter(); #endif #if (LANG_MODE != 0) //secondary language support #ifdef W25X20CL - if (w25x20cl_init()) - update_sec_lang_from_external_flash(); + if (w25x20cl_init()) + update_sec_lang_from_external_flash(); #endif //W25X20CL #endif //(LANG_MODE != 0) - setup_killpin(); - setup_powerhold(); - - farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE); - EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no); - if ((farm_mode == 0xFF && farm_no == 0) || ((uint16_t)farm_no == 0xFFFF)) - farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero or EEPROM is fresh, deactivate farm mode - if ((uint16_t)farm_no == 0xFFFF) farm_no = 0; - - selectedSerialPort = eeprom_read_byte((uint8_t*)EEPROM_SECOND_SERIAL_ACTIVE); - if (selectedSerialPort == 0xFF) selectedSerialPort = 0; - if (farm_mode) - { - no_response = true; //we need confirmation by recieving PRUSA thx - important_status = 8; - prusa_statistics(8); - selectedSerialPort = 1; + setup_killpin(); + setup_powerhold(); + + farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE); + EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no); + if ((farm_mode == 0xFF && farm_no == 0) || ((uint16_t)farm_no == 0xFFFF)) + farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero or EEPROM is fresh, deactivate farm mode + if ((uint16_t)farm_no == 0xFFFF) farm_no = 0; + + selectedSerialPort = eeprom_read_byte((uint8_t*)EEPROM_SECOND_SERIAL_ACTIVE); + if (selectedSerialPort == 0xFF) selectedSerialPort = 0; + if (farm_mode) + { + no_response = true; //we need confirmation by recieving PRUSA thx + important_status = 8; + prusa_statistics(8); + selectedSerialPort = 1; #ifdef TMC2130 - //increased extruder current (PFW363) - tmc2130_current_h[E_AXIS] = 36; - tmc2130_current_r[E_AXIS] = 36; + //increased extruder current (PFW363) + tmc2130_current_h[E_AXIS] = 36; + tmc2130_current_r[E_AXIS] = 36; #endif //TMC2130 #ifdef FILAMENT_SENSOR - //disabled filament autoload (PFW360) - fsensor_autoload_set(false); + //disabled filament autoload (PFW360) + fsensor_autoload_set(false); #endif //FILAMENT_SENSOR - } - MYSERIAL.begin(BAUDRATE); - fdev_setup_stream(uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); //setup uart out stream + } + MYSERIAL.begin(BAUDRATE); + fdev_setup_stream(uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE); //setup uart out stream #ifndef W25X20CL - SERIAL_PROTOCOLLNPGM("start"); + SERIAL_PROTOCOLLNPGM("start"); #endif //W25X20CL - stdout = uartout; - SERIAL_ECHO_START; - printf_P(PSTR(" " FW_VERSION_FULL "\n")); + stdout = uartout; + SERIAL_ECHO_START; + printf_P(PSTR(" " FW_VERSION_FULL "\n")); #ifdef DEBUG_SEC_LANG - lang_table_header_t header; - uint32_t src_addr = 0x00000; - if (lang_get_header(1, &header, &src_addr)) - { + lang_table_header_t header; + uint32_t src_addr = 0x00000; + if (lang_get_header(1, &header, &src_addr)) + { //this is comparsion of some printing-methods regarding to flash space usage and code size/readability #define LT_PRINT_TEST 2 // flash usage @@ -1044,555 +1068,556 @@ void setup() //2 253040 322 164 158 //3 253248 530 135 395 #if (LT_PRINT_TEST==1) //not optimized printf - printf_P(_n(" _src_addr = 0x%08lx\n"), src_addr); - printf_P(_n(" _lt_magic = 0x%08lx %S\n"), header.magic, (header.magic==LANG_MAGIC)?_n("OK"):_n("NA")); - printf_P(_n(" _lt_size = 0x%04x (%d)\n"), header.size, header.size); - printf_P(_n(" _lt_count = 0x%04x (%d)\n"), header.count, header.count); - printf_P(_n(" _lt_chsum = 0x%04x\n"), header.checksum); - printf_P(_n(" _lt_code = 0x%04x (%c%c)\n"), header.code, header.code >> 8, header.code & 0xff); - printf_P(_n(" _lt_sign = 0x%08lx\n"), header.signature); + printf_P(_n(" _src_addr = 0x%08lx\n"), src_addr); + printf_P(_n(" _lt_magic = 0x%08lx %S\n"), header.magic, (header.magic==LANG_MAGIC)?_n("OK"):_n("NA")); + printf_P(_n(" _lt_size = 0x%04x (%d)\n"), header.size, header.size); + printf_P(_n(" _lt_count = 0x%04x (%d)\n"), header.count, header.count); + printf_P(_n(" _lt_chsum = 0x%04x\n"), header.checksum); + printf_P(_n(" _lt_code = 0x%04x (%c%c)\n"), header.code, header.code >> 8, header.code & 0xff); + printf_P(_n(" _lt_sign = 0x%08lx\n"), header.signature); #elif (LT_PRINT_TEST==2) //optimized printf - printf_P( - _n( - " _src_addr = 0x%08lx\n" - " _lt_magic = 0x%08lx %S\n" - " _lt_size = 0x%04x (%d)\n" - " _lt_count = 0x%04x (%d)\n" - " _lt_chsum = 0x%04x\n" - " _lt_code = 0x%04x (%c%c)\n" - " _lt_resv1 = 0x%08lx\n" - ), - src_addr, - header.magic, (header.magic==LANG_MAGIC)?_n("OK"):_n("NA"), - header.size, header.size, - header.count, header.count, - header.checksum, - header.code, header.code >> 8, header.code & 0xff, - header.signature - ); + printf_P( + _n( + " _src_addr = 0x%08lx\n" + " _lt_magic = 0x%08lx %S\n" + " _lt_size = 0x%04x (%d)\n" + " _lt_count = 0x%04x (%d)\n" + " _lt_chsum = 0x%04x\n" + " _lt_code = 0x%04x (%c%c)\n" + " _lt_resv1 = 0x%08lx\n" + ), + src_addr, + header.magic, (header.magic==LANG_MAGIC)?_n("OK"):_n("NA"), + header.size, header.size, + header.count, header.count, + header.checksum, + header.code, header.code >> 8, header.code & 0xff, + header.signature + ); #elif (LT_PRINT_TEST==3) //arduino print/println (leading zeros not solved) - MYSERIAL.print(" _src_addr = 0x"); - MYSERIAL.println(src_addr, 16); - MYSERIAL.print(" _lt_magic = 0x"); - MYSERIAL.print(header.magic, 16); - MYSERIAL.println((header.magic==LANG_MAGIC)?" OK":" NA"); - MYSERIAL.print(" _lt_size = 0x"); - MYSERIAL.print(header.size, 16); - MYSERIAL.print(" ("); - MYSERIAL.print(header.size, 10); - MYSERIAL.println(")"); - MYSERIAL.print(" _lt_count = 0x"); - MYSERIAL.print(header.count, 16); - MYSERIAL.print(" ("); - MYSERIAL.print(header.count, 10); - MYSERIAL.println(")"); - MYSERIAL.print(" _lt_chsum = 0x"); - MYSERIAL.println(header.checksum, 16); - MYSERIAL.print(" _lt_code = 0x"); - MYSERIAL.print(header.code, 16); - MYSERIAL.print(" ("); - MYSERIAL.print((char)(header.code >> 8), 0); - MYSERIAL.print((char)(header.code & 0xff), 0); - MYSERIAL.println(")"); - MYSERIAL.print(" _lt_resv1 = 0x"); - MYSERIAL.println(header.signature, 16); + MYSERIAL.print(" _src_addr = 0x"); + MYSERIAL.println(src_addr, 16); + MYSERIAL.print(" _lt_magic = 0x"); + MYSERIAL.print(header.magic, 16); + MYSERIAL.println((header.magic==LANG_MAGIC)?" OK":" NA"); + MYSERIAL.print(" _lt_size = 0x"); + MYSERIAL.print(header.size, 16); + MYSERIAL.print(" ("); + MYSERIAL.print(header.size, 10); + MYSERIAL.println(")"); + MYSERIAL.print(" _lt_count = 0x"); + MYSERIAL.print(header.count, 16); + MYSERIAL.print(" ("); + MYSERIAL.print(header.count, 10); + MYSERIAL.println(")"); + MYSERIAL.print(" _lt_chsum = 0x"); + MYSERIAL.println(header.checksum, 16); + MYSERIAL.print(" _lt_code = 0x"); + MYSERIAL.print(header.code, 16); + MYSERIAL.print(" ("); + MYSERIAL.print((char)(header.code >> 8), 0); + MYSERIAL.print((char)(header.code & 0xff), 0); + MYSERIAL.println(")"); + MYSERIAL.print(" _lt_resv1 = 0x"); + MYSERIAL.println(header.signature, 16); #endif //(LT_PRINT_TEST==) #undef LT_PRINT_TEST #if 0 - w25x20cl_rd_data(0x25ba, (uint8_t*)&block_buffer, 1024); - for (uint16_t i = 0; i < 1024; i++) - { - if ((i % 16) == 0) printf_P(_n("%04x:"), 0x25ba+i); - printf_P(_n(" %02x"), ((uint8_t*)&block_buffer)[i]); - if ((i % 16) == 15) putchar('\n'); - } -#endif - uint16_t sum = 0; - for (uint16_t i = 0; i < header.size; i++) - sum += (uint16_t)pgm_read_byte((uint8_t*)(_SEC_LANG_TABLE + i)) << ((i & 1)?0:8); - printf_P(_n("_SEC_LANG_TABLE checksum = %04x\n"), sum); - sum -= header.checksum; //subtract checksum - printf_P(_n("_SEC_LANG_TABLE checksum = %04x\n"), sum); - sum = (sum >> 8) | ((sum & 0xff) << 8); //swap bytes - if (sum == header.checksum) - printf_P(_n("Checksum OK\n"), sum); - else - printf_P(_n("Checksum NG\n"), sum); - } - else - printf_P(_n("lang_get_header failed!\n")); + w25x20cl_rd_data(0x25ba, (uint8_t*)&block_buffer, 1024); + for (uint16_t i = 0; i < 1024; i++) + { + if ((i % 16) == 0) printf_P(_n("%04x:"), 0x25ba+i); + printf_P(_n(" %02x"), ((uint8_t*)&block_buffer)[i]); + if ((i % 16) == 15) putchar('\n'); + } +#endif + uint16_t sum = 0; + for (uint16_t i = 0; i < header.size; i++) + sum += (uint16_t)pgm_read_byte((uint8_t*)(_SEC_LANG_TABLE + i)) << ((i & 1)?0:8); + printf_P(_n("_SEC_LANG_TABLE checksum = %04x\n"), sum); + sum -= header.checksum; //subtract checksum + printf_P(_n("_SEC_LANG_TABLE checksum = %04x\n"), sum); + sum = (sum >> 8) | ((sum & 0xff) << 8); //swap bytes + if (sum == header.checksum) + printf_P(_n("Checksum OK\n"), sum); + else + printf_P(_n("Checksum NG\n"), sum); + } + else + printf_P(_n("lang_get_header failed!\n")); #if 0 - for (uint16_t i = 0; i < 1024*10; i++) - { - if ((i % 16) == 0) printf_P(_n("%04x:"), _SEC_LANG_TABLE+i); - printf_P(_n(" %02x"), pgm_read_byte((uint8_t*)(_SEC_LANG_TABLE+i))); - if ((i % 16) == 15) putchar('\n'); - } + for (uint16_t i = 0; i < 1024*10; i++) + { + if ((i % 16) == 0) printf_P(_n("%04x:"), _SEC_LANG_TABLE+i); + printf_P(_n(" %02x"), pgm_read_byte((uint8_t*)(_SEC_LANG_TABLE+i))); + if ((i % 16) == 15) putchar('\n'); + } #endif #if 0 - SERIAL_ECHOLN("Reading eeprom from 0 to 100: start"); - for (int i = 0; i < 4096; ++i) { - int b = eeprom_read_byte((unsigned char*)i); - if (b != 255) { - SERIAL_ECHO(i); - SERIAL_ECHO(":"); - SERIAL_ECHO(b); - SERIAL_ECHOLN(""); - } - } - SERIAL_ECHOLN("Reading eeprom from 0 to 100: done"); + SERIAL_ECHOLN("Reading eeprom from 0 to 100: start"); + for (int i = 0; i < 4096; ++i) { + int b = eeprom_read_byte((unsigned char*)i); + if (b != 255) { + SERIAL_ECHO(i); + SERIAL_ECHO(":"); + SERIAL_ECHO(b); + SERIAL_ECHOLN(""); + } + } + SERIAL_ECHOLN("Reading eeprom from 0 to 100: done"); #endif #endif //DEBUG_SEC_LANG - // Check startup - does nothing if bootloader sets MCUSR to 0 - byte mcu = MCUSR; -/* if (mcu & 1) SERIAL_ECHOLNRPGM(_T(MSG_POWERUP)); - if (mcu & 2) SERIAL_ECHOLNRPGM(MSG_EXTERNAL_RESET); - if (mcu & 4) SERIAL_ECHOLNRPGM(MSG_BROWNOUT_RESET); - if (mcu & 8) SERIAL_ECHOLNRPGM(MSG_WATCHDOG_RESET); - if (mcu & 32) SERIAL_ECHOLNRPGM(MSG_SOFTWARE_RESET);*/ - if (mcu & 1) puts_P(_T(MSG_POWERUP)); - if (mcu & 2) puts_P(MSG_EXTERNAL_RESET); - if (mcu & 4) puts_P(MSG_BROWNOUT_RESET); - if (mcu & 8) puts_P(MSG_WATCHDOG_RESET); - if (mcu & 32) puts_P(MSG_SOFTWARE_RESET); - MCUSR = 0; - - //SERIAL_ECHORPGM(MSG_MARLIN); - //SERIAL_ECHOLNRPGM(VERSION_STRING); + // Check startup - does nothing if bootloader sets MCUSR to 0 + byte mcu = MCUSR; + /* if (mcu & 1) SERIAL_ECHOLNRPGM(_T(MSG_POWERUP)); + if (mcu & 2) SERIAL_ECHOLNRPGM(MSG_EXTERNAL_RESET); + if (mcu & 4) SERIAL_ECHOLNRPGM(MSG_BROWNOUT_RESET); + if (mcu & 8) SERIAL_ECHOLNRPGM(MSG_WATCHDOG_RESET); + if (mcu & 32) SERIAL_ECHOLNRPGM(MSG_SOFTWARE_RESET);*/ + if (mcu & 1) puts_P(_T(MSG_POWERUP)); + if (mcu & 2) puts_P(MSG_EXTERNAL_RESET); + if (mcu & 4) puts_P(MSG_BROWNOUT_RESET); + if (mcu & 8) puts_P(MSG_WATCHDOG_RESET); + if (mcu & 32) puts_P(MSG_SOFTWARE_RESET); + MCUSR = 0; + + //SERIAL_ECHORPGM(MSG_MARLIN); + //SERIAL_ECHOLNRPGM(VERSION_STRING); #ifdef STRING_VERSION_CONFIG_H #ifdef STRING_CONFIG_H_AUTHOR - SERIAL_ECHO_START; - SERIAL_ECHORPGM(_i(" Last Updated: "));////MSG_CONFIGURATION_VER c=0 r=0 - SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H); - SERIAL_ECHORPGM(_n(" | Author: "));////MSG_AUTHOR c=0 r=0 - SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR); - SERIAL_ECHOPGM("Compiled: "); - SERIAL_ECHOLNPGM(__DATE__); -#endif -#endif - - SERIAL_ECHO_START; - SERIAL_ECHORPGM(_i(" Free Memory: "));////MSG_FREE_MEMORY c=0 r=0 - SERIAL_ECHO(freeMemory()); - SERIAL_ECHORPGM(_i(" PlannerBufferBytes: "));////MSG_PLANNER_BUFFER_BYTES c=0 r=0 - SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE); - //lcd_update_enable(false); // why do we need this?? - andre - // loads data from EEPROM if available else uses defaults (and resets step acceleration rate) - - bool previous_settings_retrieved = false; - uint8_t hw_changed = check_printer_version(); - if (!(hw_changed & 0b10)) { //if printer version wasn't changed, check for eeprom version and retrieve settings from eeprom in case that version wasn't changed - previous_settings_retrieved = Config_RetrieveSettings(); - } - else { //printer version was changed so use default settings - Config_ResetDefault(); - } - SdFatUtil::set_stack_guard(); //writes magic number at the end of static variables to protect against overwriting static memory by stack + SERIAL_ECHO_START; + SERIAL_ECHORPGM(_i(" Last Updated: "));////MSG_CONFIGURATION_VER c=0 r=0 + SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H); + SERIAL_ECHORPGM(_n(" | Author: "));////MSG_AUTHOR c=0 r=0 + SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR); + SERIAL_ECHOPGM("Compiled: "); + SERIAL_ECHOLNPGM(__DATE__); +#endif +#endif + + SERIAL_ECHO_START; + SERIAL_ECHORPGM(_i(" Free Memory: "));////MSG_FREE_MEMORY c=0 r=0 + SERIAL_ECHO(freeMemory()); + SERIAL_ECHORPGM(_i(" PlannerBufferBytes: "));////MSG_PLANNER_BUFFER_BYTES c=0 r=0 + SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE); + //lcd_update_enable(false); // why do we need this?? - andre + // loads data from EEPROM if available else uses defaults (and resets step acceleration rate) + + bool previous_settings_retrieved = false; + uint8_t hw_changed = check_printer_version(); + if (!(hw_changed & 0b10)) { //if printer version wasn't changed, check for eeprom version and retrieve settings from eeprom in case that version wasn't changed + previous_settings_retrieved = Config_RetrieveSettings(); + } + else { //printer version was changed so use default settings + Config_ResetDefault(); + } + SdFatUtil::set_stack_guard(); //writes magic number at the end of static variables to protect against overwriting static memory by stack - tp_init(); // Initialize temperature loop + tp_init(); // Initialize temperature loop - lcd_splash(); // we need to do this again, because tp_init() kills lcd + lcd_splash(); // we need to do this again, because tp_init() kills lcd - plan_init(); // Initialize planner; + plan_init(); // Initialize planner; - factory_reset(); - lcd_encoder_diff=0; + factory_reset(); + lcd_encoder_diff=0; #ifdef TMC2130 - uint8_t silentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT); - if (silentMode == 0xff) silentMode = 0; - tmc2130_mode = TMC2130_MODE_NORMAL; - uint8_t crashdet = eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET); - if (crashdet && !farm_mode) - { - crashdet_enable(); - puts_P(_N("CrashDetect ENABLED!")); - } - else - { - crashdet_disable(); - puts_P(_N("CrashDetect DISABLED")); - } + uint8_t silentMode = eeprom_read_byte((uint8_t*)EEPROM_SILENT); + if (silentMode == 0xff) silentMode = 0; + tmc2130_mode = TMC2130_MODE_NORMAL; + uint8_t crashdet = eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET); + if (crashdet && !farm_mode) + { + crashdet_enable(); + puts_P(_N("CrashDetect ENABLED!")); + } + else + { + crashdet_disable(); + puts_P(_N("CrashDetect DISABLED")); + } #ifdef TMC2130_LINEARITY_CORRECTION #ifdef TMC2130_LINEARITY_CORRECTION_XYZ - tmc2130_wave_fac[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_X_FAC); - tmc2130_wave_fac[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_Y_FAC); - tmc2130_wave_fac[Z_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_Z_FAC); + tmc2130_wave_fac[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_X_FAC); + tmc2130_wave_fac[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_Y_FAC); + tmc2130_wave_fac[Z_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_Z_FAC); #endif //TMC2130_LINEARITY_CORRECTION_XYZ - tmc2130_wave_fac[E_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_E_FAC); - if (tmc2130_wave_fac[X_AXIS] == 0xff) tmc2130_wave_fac[X_AXIS] = 0; - if (tmc2130_wave_fac[Y_AXIS] == 0xff) tmc2130_wave_fac[Y_AXIS] = 0; - if (tmc2130_wave_fac[Z_AXIS] == 0xff) tmc2130_wave_fac[Z_AXIS] = 0; - if (tmc2130_wave_fac[E_AXIS] == 0xff) tmc2130_wave_fac[E_AXIS] = 0; + tmc2130_wave_fac[E_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_E_FAC); + if (tmc2130_wave_fac[X_AXIS] == 0xff) tmc2130_wave_fac[X_AXIS] = 0; + if (tmc2130_wave_fac[Y_AXIS] == 0xff) tmc2130_wave_fac[Y_AXIS] = 0; + if (tmc2130_wave_fac[Z_AXIS] == 0xff) tmc2130_wave_fac[Z_AXIS] = 0; + if (tmc2130_wave_fac[E_AXIS] == 0xff) tmc2130_wave_fac[E_AXIS] = 0; #endif //TMC2130_LINEARITY_CORRECTION #ifdef TMC2130_VARIABLE_RESOLUTION - tmc2130_mres[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_X_MRES); - tmc2130_mres[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_Y_MRES); - tmc2130_mres[Z_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_Z_MRES); - tmc2130_mres[E_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_E_MRES); - if (tmc2130_mres[X_AXIS] == 0xff) tmc2130_mres[X_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); - if (tmc2130_mres[Y_AXIS] == 0xff) tmc2130_mres[Y_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); - if (tmc2130_mres[Z_AXIS] == 0xff) tmc2130_mres[Z_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_Z); - if (tmc2130_mres[E_AXIS] == 0xff) tmc2130_mres[E_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_E); - eeprom_update_byte((uint8_t*)EEPROM_TMC2130_X_MRES, tmc2130_mres[X_AXIS]); - eeprom_update_byte((uint8_t*)EEPROM_TMC2130_Y_MRES, tmc2130_mres[Y_AXIS]); - eeprom_update_byte((uint8_t*)EEPROM_TMC2130_Z_MRES, tmc2130_mres[Z_AXIS]); - eeprom_update_byte((uint8_t*)EEPROM_TMC2130_E_MRES, tmc2130_mres[E_AXIS]); + tmc2130_mres[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_X_MRES); + tmc2130_mres[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_Y_MRES); + tmc2130_mres[Z_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_Z_MRES); + tmc2130_mres[E_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_E_MRES); + if (tmc2130_mres[X_AXIS] == 0xff) tmc2130_mres[X_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); + if (tmc2130_mres[Y_AXIS] == 0xff) tmc2130_mres[Y_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); + if (tmc2130_mres[Z_AXIS] == 0xff) tmc2130_mres[Z_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_Z); + if (tmc2130_mres[E_AXIS] == 0xff) tmc2130_mres[E_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_E); + eeprom_update_byte((uint8_t*)EEPROM_TMC2130_X_MRES, tmc2130_mres[X_AXIS]); + eeprom_update_byte((uint8_t*)EEPROM_TMC2130_Y_MRES, tmc2130_mres[Y_AXIS]); + eeprom_update_byte((uint8_t*)EEPROM_TMC2130_Z_MRES, tmc2130_mres[Z_AXIS]); + eeprom_update_byte((uint8_t*)EEPROM_TMC2130_E_MRES, tmc2130_mres[E_AXIS]); #else //TMC2130_VARIABLE_RESOLUTION - tmc2130_mres[X_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); - tmc2130_mres[Y_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); - tmc2130_mres[Z_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_Z); - tmc2130_mres[E_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_E); + tmc2130_mres[X_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); + tmc2130_mres[Y_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_XY); + tmc2130_mres[Z_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_Z); + tmc2130_mres[E_AXIS] = tmc2130_usteps2mres(TMC2130_USTEPS_E); #endif //TMC2130_VARIABLE_RESOLUTION #endif //TMC2130 - st_init(); // Initialize stepper, this enables interrupts! + st_init(); // Initialize stepper, this enables interrupts! #ifdef TMC2130 - tmc2130_mode = silentMode?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL; - update_mode_profile(); - tmc2130_init(); + tmc2130_mode = silentMode?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL; + update_mode_profile(); + tmc2130_init(); #endif //TMC2130 - - setup_photpin(); - - servo_init(); - // Reset the machine correction matrix. - // It does not make sense to load the correction matrix until the machine is homed. - world2machine_reset(); - + + setup_photpin(); + + servo_init(); + // Reset the machine correction matrix. + // It does not make sense to load the correction matrix until the machine is homed. + world2machine_reset(); + #ifdef FILAMENT_SENSOR - fsensor_init(); + fsensor_init(); #endif //FILAMENT_SENSOR #if defined(CONTROLLERFAN_PIN) && (CONTROLLERFAN_PIN > -1) - SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan + SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan #endif - setup_homepin(); + setup_homepin(); #ifdef TMC2130 - if (1) { - // try to run to zero phase before powering the Z motor. - // Move in negative direction - WRITE(Z_DIR_PIN,INVERT_Z_DIR); - // Round the current micro-micro steps to micro steps. - for (uint16_t phase = (tmc2130_rd_MSCNT(Z_AXIS) + 8) >> 4; phase > 0; -- phase) { - // Until the phase counter is reset to zero. - WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - delay(2); - WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); - delay(2); + if (1) { + // try to run to zero phase before powering the Z motor. + // Move in negative direction + WRITE(Z_DIR_PIN,INVERT_Z_DIR); + // Round the current micro-micro steps to micro steps. + for (uint16_t phase = (tmc2130_rd_MSCNT(Z_AXIS) + 8) >> 4; phase > 0; -- phase) { + // Until the phase counter is reset to zero. + WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); + delay(2); + WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN); + delay(2); + } } - } #endif //TMC2130 #if defined(Z_AXIS_ALWAYS_ON) - enable_z(); -#endif - farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE); - EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no); - if ((farm_mode == 0xFF && farm_no == 0) || (farm_no == static_cast(0xFFFF))) farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero or EEPROM is fresh, deactivate farm mode - if (farm_no == static_cast(0xFFFF)) farm_no = 0; - if (farm_mode) - { - prusa_statistics(8); - } + enable_z(); +#endif + farm_mode = eeprom_read_byte((uint8_t*)EEPROM_FARM_MODE); + EEPROM_read_B(EEPROM_FARM_NUMBER, &farm_no); + if ((farm_mode == 0xFF && farm_no == 0) || (farm_no == static_cast(0xFFFF))) farm_mode = false; //if farm_mode has not been stored to eeprom yet and farm number is set to zero or EEPROM is fresh, deactivate farm mode + if (farm_no == static_cast(0xFFFF)) farm_no = 0; + if (farm_mode) + { + prusa_statistics(8); + } - // Enable Toshiba FlashAir SD card / WiFi enahanced card. - card.ToshibaFlashAir_enable(eeprom_read_byte((unsigned char*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY) == 1); + // Enable Toshiba FlashAir SD card / WiFi enahanced card. + card.ToshibaFlashAir_enable(eeprom_read_byte((unsigned char*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY) == 1); - if (eeprom_read_dword((uint32_t*)(EEPROM_TOP - 4)) == 0x0ffffffff && - eeprom_read_dword((uint32_t*)(EEPROM_TOP - 8)) == 0x0ffffffff) { - // Maiden startup. The firmware has been loaded and first started on a virgin RAMBo board, - // where all the EEPROM entries are set to 0x0ff. - // Once a firmware boots up, it forces at least a language selection, which changes - // EEPROM_LANG to number lower than 0x0ff. - // 1) Set a high power mode. + if (eeprom_read_dword((uint32_t*)(EEPROM_TOP - 4)) == 0x0ffffffff && + eeprom_read_dword((uint32_t*)(EEPROM_TOP - 8)) == 0x0ffffffff) { + // Maiden startup. The firmware has been loaded and first started on a virgin RAMBo board, + // where all the EEPROM entries are set to 0x0ff. + // Once a firmware boots up, it forces at least a language selection, which changes + // EEPROM_LANG to number lower than 0x0ff. + // 1) Set a high power mode. #ifdef TMC2130 - eeprom_write_byte((uint8_t*)EEPROM_SILENT, 0); - tmc2130_mode = TMC2130_MODE_NORMAL; + eeprom_write_byte((uint8_t*)EEPROM_SILENT, 0); + tmc2130_mode = TMC2130_MODE_NORMAL; #endif //TMC2130 - eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard - } + eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); //run wizard + } - // Force SD card update. Otherwise the SD card update is done from loop() on card.checkautostart(false), - // but this times out if a blocking dialog is shown in setup(). - card.initsd(); + // Force SD card update. Otherwise the SD card update is done from loop() on card.checkautostart(false), + // but this times out if a blocking dialog is shown in setup(). + card.initsd(); #ifdef DEBUG_SD_SPEED_TEST - if (card.cardOK) - { - uint8_t* buff = (uint8_t*)block_buffer; - uint32_t block = 0; - uint32_t sumr = 0; - uint32_t sumw = 0; - for (int i = 0; i < 1024; i++) - { - uint32_t u = micros(); - bool res = card.card.readBlock(i, buff); - u = micros() - u; - if (res) - { - printf_P(PSTR("readBlock %4d 512 bytes %lu us\n"), i, u); - sumr += u; - u = micros(); - res = card.card.writeBlock(i, buff); - u = micros() - u; - if (res) - { - printf_P(PSTR("writeBlock %4d 512 bytes %lu us\n"), i, u); - sumw += u; - } - else - { - printf_P(PSTR("writeBlock %4d error\n"), i); - break; - } - } - else - { - printf_P(PSTR("readBlock %4d error\n"), i); - break; - } - } - uint32_t avg_rspeed = (1024 * 1000000) / (sumr / 512); - uint32_t avg_wspeed = (1024 * 1000000) / (sumw / 512); - printf_P(PSTR("avg read speed %lu bytes/s\n"), avg_rspeed); - printf_P(PSTR("avg write speed %lu bytes/s\n"), avg_wspeed); - } - else - printf_P(PSTR("Card NG!\n")); + if (card.cardOK) + { + uint8_t* buff = (uint8_t*)block_buffer; + uint32_t block = 0; + uint32_t sumr = 0; + uint32_t sumw = 0; + for (int i = 0; i < 1024; i++) + { + uint32_t u = micros(); + bool res = card.card.readBlock(i, buff); + u = micros() - u; + if (res) + { + printf_P(PSTR("readBlock %4d 512 bytes %lu us\n"), i, u); + sumr += u; + u = micros(); + res = card.card.writeBlock(i, buff); + u = micros() - u; + if (res) + { + printf_P(PSTR("writeBlock %4d 512 bytes %lu us\n"), i, u); + sumw += u; + } + else + { + printf_P(PSTR("writeBlock %4d error\n"), i); + break; + } + } + else + { + printf_P(PSTR("readBlock %4d error\n"), i); + break; + } + } + uint32_t avg_rspeed = (1024 * 1000000) / (sumr / 512); + uint32_t avg_wspeed = (1024 * 1000000) / (sumw / 512); + printf_P(PSTR("avg read speed %lu bytes/s\n"), avg_rspeed); + printf_P(PSTR("avg write speed %lu bytes/s\n"), avg_wspeed); + } + else + printf_P(PSTR("Card NG!\n")); #endif //DEBUG_SD_SPEED_TEST - if (eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_POWER_COUNT, 0); - if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_CRASH_COUNT_X, 0); - if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_CRASH_COUNT_Y, 0); - if (eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_FERROR_COUNT, 0); - if (eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_POWER_COUNT_TOT, 0); - if (eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT, 0); - if (eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT, 0); - if (eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, 0); + if (eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_POWER_COUNT, 0); + if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_CRASH_COUNT_X, 0); + if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_CRASH_COUNT_Y, 0); + if (eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) == 0xff) eeprom_write_byte((uint8_t*)EEPROM_FERROR_COUNT, 0); + if (eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_POWER_COUNT_TOT, 0); + if (eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT, 0); + if (eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT, 0); + if (eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) == 0xffff) eeprom_write_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, 0); #ifdef SNMM - if (eeprom_read_dword((uint32_t*)EEPROM_BOWDEN_LENGTH) == 0x0ffffffff) { //bowden length used for SNMM - int _z = BOWDEN_LENGTH; - for(int i = 0; i<4; i++) EEPROM_save_B(EEPROM_BOWDEN_LENGTH + i * 2, &_z); - } + if (eeprom_read_dword((uint32_t*)EEPROM_BOWDEN_LENGTH) == 0x0ffffffff) { //bowden length used for SNMM + int _z = BOWDEN_LENGTH; + for(int i = 0; i<4; i++) EEPROM_save_B(EEPROM_BOWDEN_LENGTH + i * 2, &_z); + } #endif - // In the future, somewhere here would one compare the current firmware version against the firmware version stored in the EEPROM. - // If they differ, an update procedure may need to be performed. At the end of this block, the current firmware version - // is being written into the EEPROM, so the update procedure will be triggered only once. + // In the future, somewhere here would one compare the current firmware version against the firmware version stored in the EEPROM. + // If they differ, an update procedure may need to be performed. At the end of this block, the current firmware version + // is being written into the EEPROM, so the update procedure will be triggered only once. #if (LANG_MODE != 0) //secondary language support #ifdef DEBUG_W25X20CL - W25X20CL_SPI_ENTER(); - uint8_t uid[8]; // 64bit unique id - w25x20cl_rd_uid(uid); - puts_P(_n("W25X20CL UID=")); - for (uint8_t i = 0; i < 8; i ++) - printf_P(PSTR("%02hhx"), uid[i]); - putchar('\n'); - list_sec_lang_from_external_flash(); + W25X20CL_SPI_ENTER(); + uint8_t uid[8]; // 64bit unique id + w25x20cl_rd_uid(uid); + puts_P(_n("W25X20CL UID=")); + for (uint8_t i = 0; i < 8; i ++) + printf_P(PSTR("%02hhx"), uid[i]); + putchar('\n'); + list_sec_lang_from_external_flash(); #endif //DEBUG_W25X20CL // lang_reset(); - if (!lang_select(eeprom_read_byte((uint8_t*)EEPROM_LANG))) - lcd_language(); + if (!lang_select(eeprom_read_byte((uint8_t*)EEPROM_LANG))) + lcd_language(); #ifdef DEBUG_SEC_LANG - uint16_t sec_lang_code = lang_get_code(1); - uint16_t ui = _SEC_LANG_TABLE; //table pointer - printf_P(_n("lang_selected=%d\nlang_table=0x%04x\nSEC_LANG_CODE=0x%04x (%c%c)\n"), lang_selected, ui, sec_lang_code, sec_lang_code >> 8, sec_lang_code & 0xff); + uint16_t sec_lang_code = lang_get_code(1); + uint16_t ui = _SEC_LANG_TABLE; //table pointer + printf_P(_n("lang_selected=%d\nlang_table=0x%04x\nSEC_LANG_CODE=0x%04x (%c%c)\n"), lang_selected, ui, sec_lang_code, sec_lang_code >> 8, sec_lang_code & 0xff); - lang_print_sec_lang(uartout); + lang_print_sec_lang(uartout); #endif //DEBUG_SEC_LANG #endif //(LANG_MODE != 0) - if (eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE) == 255) { - eeprom_write_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE, 0); - temp_cal_active = false; - } else temp_cal_active = eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE); - - if (eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA) == 255) { - //eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); - eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); - int16_t z_shift = 0; - for (uint8_t i = 0; i < 5; i++) EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); - eeprom_write_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE, 0); - temp_cal_active = false; - } - if (eeprom_read_byte((uint8_t*)EEPROM_UVLO) == 255) { - eeprom_write_byte((uint8_t*)EEPROM_UVLO, 0); - } - if (eeprom_read_byte((uint8_t*)EEPROM_SD_SORT) == 255) { - eeprom_write_byte((uint8_t*)EEPROM_SD_SORT, 0); - } + if (eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE) == 255) { + eeprom_write_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE, 0); + temp_cal_active = false; + } else temp_cal_active = eeprom_read_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE); + + if (eeprom_read_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA) == 255) { + //eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); + eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); + int16_t z_shift = 0; + for (uint8_t i = 0; i < 5; i++) EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); + eeprom_write_byte((uint8_t*)EEPROM_TEMP_CAL_ACTIVE, 0); + temp_cal_active = false; + } + if (eeprom_read_byte((uint8_t*)EEPROM_UVLO) == 255) { + eeprom_write_byte((uint8_t*)EEPROM_UVLO, 0); + } + if (eeprom_read_byte((uint8_t*)EEPROM_SD_SORT) == 255) { + eeprom_write_byte((uint8_t*)EEPROM_SD_SORT, 0); + } - check_babystep(); //checking if Z babystep is in allowed range + check_babystep(); //checking if Z babystep is in allowed range #ifdef UVLO_SUPPORT - setup_uvlo_interrupt(); + setup_uvlo_interrupt(); #endif //UVLO_SUPPORT #if !defined(DEBUG_DISABLE_FANCHECK) && defined(FANCHECK) && defined(TACH_1) && TACH_1 >-1 - setup_fan_interrupt(); + setup_fan_interrupt(); #endif //DEBUG_DISABLE_FANCHECK #ifdef FILAMENT_SENSOR - fsensor_setup_interrupt(); + fsensor_setup_interrupt(); #endif //FILAMENT_SENSOR - for (int i = 0; i<4; i++) EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); - + for (int i = 0; i<4; i++) EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); + #ifndef DEBUG_DISABLE_STARTMSGS - KEEPALIVE_STATE(PAUSED_FOR_USER); - - show_fw_version_warnings(); - - switch (hw_changed) { - //if motherboard or printer type was changed inform user as it can indicate flashing wrong firmware version - //if user confirms with knob, new hw version (printer and/or motherboard) is written to eeprom and message will be not shown next time - case(0b01): - lcd_show_fullscreen_message_and_wait_P(_i("Warning: motherboard type changed.")); ////MSG_CHANGED_MOTHERBOARD c=20 r=4 - eeprom_write_word((uint16_t*)EEPROM_BOARD_TYPE, MOTHERBOARD); - break; - case(0b10): - lcd_show_fullscreen_message_and_wait_P(_i("Warning: printer type changed.")); ////MSG_CHANGED_PRINTER c=20 r=4 - eeprom_write_word((uint16_t*)EEPROM_PRINTER_TYPE, PRINTER_TYPE); - break; - case(0b11): - lcd_show_fullscreen_message_and_wait_P(_i("Warning: both printer type and motherboard type changed.")); ////MSG_CHANGED_BOTH c=20 r=4 - eeprom_write_word((uint16_t*)EEPROM_PRINTER_TYPE, PRINTER_TYPE); - eeprom_write_word((uint16_t*)EEPROM_BOARD_TYPE, MOTHERBOARD); - break; - default: break; //no change, show no message - } + KEEPALIVE_STATE(PAUSED_FOR_USER); - if (!previous_settings_retrieved) { - lcd_show_fullscreen_message_and_wait_P(_i("Old settings found. Default PID, Esteps etc. will be set.")); //if EEPROM version or printer type was changed, inform user that default setting were loaded////MSG_DEFAULT_SETTINGS_LOADED c=20 r=4 - Config_StoreSettings(); - } - if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) { - lcd_wizard(WizState::Run); - } - if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 0) { //dont show calibration status messages if wizard is currently active - if (calibration_status() == CALIBRATION_STATUS_ASSEMBLED || - calibration_status() == CALIBRATION_STATUS_UNKNOWN || - calibration_status() == CALIBRATION_STATUS_XYZ_CALIBRATION) { - // Reset the babystepping values, so the printer will not move the Z axis up when the babystepping is enabled. - eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0); - // Show the message. - lcd_show_fullscreen_message_and_wait_P(_T(MSG_FOLLOW_CALIBRATION_FLOW)); - } - else if (calibration_status() == CALIBRATION_STATUS_LIVE_ADJUST) { - // Show the message. - lcd_show_fullscreen_message_and_wait_P(_T(MSG_BABYSTEP_Z_NOT_SET)); - lcd_update_enable(true); - } - else if (calibration_status() == CALIBRATION_STATUS_CALIBRATED && temp_cal_active == true && calibration_status_pinda() == false) { - //lcd_show_fullscreen_message_and_wait_P(_i("Temperature calibration has not been run yet"));////MSG_PINDA_NOT_CALIBRATED c=20 r=4 - lcd_update_enable(true); - } - else if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION) { - // Show the message. - lcd_show_fullscreen_message_and_wait_P(_T(MSG_FOLLOW_Z_CALIBRATION_FLOW)); - } - } + show_fw_version_warnings(); + + switch (hw_changed) { + //if motherboard or printer type was changed inform user as it can indicate flashing wrong firmware version + //if user confirms with knob, new hw version (printer and/or motherboard) is written to eeprom and message will be not shown next time + case(0b01): + lcd_show_fullscreen_message_and_wait_P(_i("Warning: motherboard type changed.")); ////MSG_CHANGED_MOTHERBOARD c=20 r=4 + eeprom_write_word((uint16_t*)EEPROM_BOARD_TYPE, MOTHERBOARD); + break; + case(0b10): + lcd_show_fullscreen_message_and_wait_P(_i("Warning: printer type changed.")); ////MSG_CHANGED_PRINTER c=20 r=4 + eeprom_write_word((uint16_t*)EEPROM_PRINTER_TYPE, PRINTER_TYPE); + break; + case(0b11): + lcd_show_fullscreen_message_and_wait_P(_i("Warning: both printer type and motherboard type changed.")); ////MSG_CHANGED_BOTH c=20 r=4 + eeprom_write_word((uint16_t*)EEPROM_PRINTER_TYPE, PRINTER_TYPE); + eeprom_write_word((uint16_t*)EEPROM_BOARD_TYPE, MOTHERBOARD); + break; + default: + break; //no change, show no message + } + + if (!previous_settings_retrieved) { + lcd_show_fullscreen_message_and_wait_P(_i("Old settings found. Default PID, Esteps etc. will be set.")); //if EEPROM version or printer type was changed, inform user that default setting were loaded////MSG_DEFAULT_SETTINGS_LOADED c=20 r=4 + Config_StoreSettings(); + } + if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) { + lcd_wizard(WizState::Run); + } + if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 0) { //dont show calibration status messages if wizard is currently active + if (calibration_status() == CALIBRATION_STATUS_ASSEMBLED || + calibration_status() == CALIBRATION_STATUS_UNKNOWN || + calibration_status() == CALIBRATION_STATUS_XYZ_CALIBRATION) { + // Reset the babystepping values, so the printer will not move the Z axis up when the babystepping is enabled. + eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0); + // Show the message. + lcd_show_fullscreen_message_and_wait_P(_T(MSG_FOLLOW_CALIBRATION_FLOW)); + } + else if (calibration_status() == CALIBRATION_STATUS_LIVE_ADJUST) { + // Show the message. + lcd_show_fullscreen_message_and_wait_P(_T(MSG_BABYSTEP_Z_NOT_SET)); + lcd_update_enable(true); + } + else if (calibration_status() == CALIBRATION_STATUS_CALIBRATED && temp_cal_active == true && calibration_status_pinda() == false) { + //lcd_show_fullscreen_message_and_wait_P(_i("Temperature calibration has not been run yet"));////MSG_PINDA_NOT_CALIBRATED c=20 r=4 + lcd_update_enable(true); + } + else if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION) { + // Show the message. + lcd_show_fullscreen_message_and_wait_P(_T(MSG_FOLLOW_Z_CALIBRATION_FLOW)); + } + } #if !defined (DEBUG_DISABLE_FORCE_SELFTEST) && defined (TMC2130) - if (force_selftest_if_fw_version() && calibration_status() < CALIBRATION_STATUS_ASSEMBLED) { - lcd_show_fullscreen_message_and_wait_P(_i("Selftest will be run to calibrate accurate sensorless rehoming."));////MSG_FORCE_SELFTEST c=20 r=8 - update_current_firmware_version_to_eeprom(); - lcd_selftest(); - } + if (force_selftest_if_fw_version() && calibration_status() < CALIBRATION_STATUS_ASSEMBLED) { + lcd_show_fullscreen_message_and_wait_P(_i("Selftest will be run to calibrate accurate sensorless rehoming."));////MSG_FORCE_SELFTEST c=20 r=8 + update_current_firmware_version_to_eeprom(); + lcd_selftest(); + } #endif //TMC2130 && !DEBUG_DISABLE_FORCE_SELFTEST - KEEPALIVE_STATE(IN_PROCESS); + KEEPALIVE_STATE(IN_PROCESS); #endif //DEBUG_DISABLE_STARTMSGS - lcd_update_enable(true); - lcd_clear(); - lcd_update(2); - // Store the currently running firmware into an eeprom, - // so the next time the firmware gets updated, it will know from which version it has been updated. - update_current_firmware_version_to_eeprom(); + lcd_update_enable(true); + lcd_clear(); + lcd_update(2); + // Store the currently running firmware into an eeprom, + // so the next time the firmware gets updated, it will know from which version it has been updated. + update_current_firmware_version_to_eeprom(); #ifdef TMC2130 - tmc2130_home_origin[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_X_ORIGIN); - tmc2130_home_bsteps[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_X_BSTEPS); - tmc2130_home_fsteps[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_X_FSTEPS); - if (tmc2130_home_origin[X_AXIS] == 0xff) tmc2130_home_origin[X_AXIS] = 0; - if (tmc2130_home_bsteps[X_AXIS] == 0xff) tmc2130_home_bsteps[X_AXIS] = 48; - if (tmc2130_home_fsteps[X_AXIS] == 0xff) tmc2130_home_fsteps[X_AXIS] = 48; - - tmc2130_home_origin[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_ORIGIN); - tmc2130_home_bsteps[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_BSTEPS); - tmc2130_home_fsteps[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_FSTEPS); - if (tmc2130_home_origin[Y_AXIS] == 0xff) tmc2130_home_origin[Y_AXIS] = 0; - if (tmc2130_home_bsteps[Y_AXIS] == 0xff) tmc2130_home_bsteps[Y_AXIS] = 48; - if (tmc2130_home_fsteps[Y_AXIS] == 0xff) tmc2130_home_fsteps[Y_AXIS] = 48; - - tmc2130_home_enabled = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_ENABLED); - if (tmc2130_home_enabled == 0xff) tmc2130_home_enabled = 0; + tmc2130_home_origin[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_X_ORIGIN); + tmc2130_home_bsteps[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_X_BSTEPS); + tmc2130_home_fsteps[X_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_X_FSTEPS); + if (tmc2130_home_origin[X_AXIS] == 0xff) tmc2130_home_origin[X_AXIS] = 0; + if (tmc2130_home_bsteps[X_AXIS] == 0xff) tmc2130_home_bsteps[X_AXIS] = 48; + if (tmc2130_home_fsteps[X_AXIS] == 0xff) tmc2130_home_fsteps[X_AXIS] = 48; + + tmc2130_home_origin[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_ORIGIN); + tmc2130_home_bsteps[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_BSTEPS); + tmc2130_home_fsteps[Y_AXIS] = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_FSTEPS); + if (tmc2130_home_origin[Y_AXIS] == 0xff) tmc2130_home_origin[Y_AXIS] = 0; + if (tmc2130_home_bsteps[Y_AXIS] == 0xff) tmc2130_home_bsteps[Y_AXIS] = 48; + if (tmc2130_home_fsteps[Y_AXIS] == 0xff) tmc2130_home_fsteps[Y_AXIS] = 48; + + tmc2130_home_enabled = eeprom_read_byte((uint8_t*)EEPROM_TMC2130_HOME_ENABLED); + if (tmc2130_home_enabled == 0xff) tmc2130_home_enabled = 0; #endif //TMC2130 #ifdef UVLO_SUPPORT - if (eeprom_read_byte((uint8_t*)EEPROM_UVLO) != 0) { //previous print was terminated by UVLO -/* - if (lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_RECOVER_PRINT), false)) recover_print(); - else { - eeprom_update_byte((uint8_t*)EEPROM_UVLO, 0); - lcd_update_enable(true); - lcd_update(2); - lcd_setstatuspgm(_T(WELCOME_MSG)); - } -*/ - manage_heater(); // Update temperatures -#ifdef DEBUG_UVLO_AUTOMATIC_RECOVER - printf_P(_N("Power panic detected!\nCurrent bed temp:%d\nSaved bed temp:%d\n"), (int)degBed(), eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED)) -#endif - if ( degBed() > ( (float)eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED) - AUTOMATIC_UVLO_BED_TEMP_OFFSET) ){ - #ifdef DEBUG_UVLO_AUTOMATIC_RECOVER - puts_P(_N("Automatic recovery!")); - #endif - recover_print(1); - } - else{ - #ifdef DEBUG_UVLO_AUTOMATIC_RECOVER - puts_P(_N("Normal recovery!")); - #endif - if ( lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_RECOVER_PRINT), false) ) recover_print(0); - else { - eeprom_update_byte((uint8_t*)EEPROM_UVLO, 0); - lcd_update_enable(true); - lcd_update(2); - lcd_setstatuspgm(_T(WELCOME_MSG)); - } - - } - - - } + if (eeprom_read_byte((uint8_t*)EEPROM_UVLO) != 0) { //previous print was terminated by UVLO + /* + if (lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_RECOVER_PRINT), false)) recover_print(); + else { + eeprom_update_byte((uint8_t*)EEPROM_UVLO, 0); + lcd_update_enable(true); + lcd_update(2); + lcd_setstatuspgm(_T(WELCOME_MSG)); + } + */ + manage_heater(); // Update temperatures +#ifdef DEBUG_UVLO_AUTOMATIC_RECOVER + printf_P(_N("Power panic detected!\nCurrent bed temp:%d\nSaved bed temp:%d\n"), (int)degBed(), eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED)) +#endif + if ( degBed() > ( (float)eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED) - AUTOMATIC_UVLO_BED_TEMP_OFFSET) ) { +#ifdef DEBUG_UVLO_AUTOMATIC_RECOVER + puts_P(_N("Automatic recovery!")); +#endif + recover_print(1); + } + else { +#ifdef DEBUG_UVLO_AUTOMATIC_RECOVER + puts_P(_N("Normal recovery!")); +#endif + if ( lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_RECOVER_PRINT), false) ) recover_print(0); + else { + eeprom_update_byte((uint8_t*)EEPROM_UVLO, 0); + lcd_update_enable(true); + lcd_update(2); + lcd_setstatuspgm(_T(WELCOME_MSG)); + } + + } + + + } #endif //UVLO_SUPPORT - KEEPALIVE_STATE(NOT_BUSY); + KEEPALIVE_STATE(NOT_BUSY); #ifdef WATCHDOG - wdt_enable(WDTO_4S); + wdt_enable(WDTO_4S); #endif //WATCHDOG } @@ -1676,29 +1701,29 @@ void serial_read_stream() { * while the machine is not accepting commands. */ void host_keepalive() { - if (farm_mode) return; - long ms = millis(); - if (host_keepalive_interval && busy_state != NOT_BUSY) { - if ((ms - prev_busy_signal_ms) < (long)(1000L * host_keepalive_interval)) return; - switch (busy_state) { - case IN_HANDLER: - case IN_PROCESS: - SERIAL_ECHO_START; - SERIAL_ECHOLNPGM("busy: processing"); - break; - case PAUSED_FOR_USER: - SERIAL_ECHO_START; - SERIAL_ECHOLNPGM("busy: paused for user"); - break; - case PAUSED_FOR_INPUT: - SERIAL_ECHO_START; - SERIAL_ECHOLNPGM("busy: paused for input"); - break; - default: - break; + if (farm_mode) return; + long ms = millis(); + if (host_keepalive_interval && busy_state != NOT_BUSY) { + if ((ms - prev_busy_signal_ms) < (long)(1000L * host_keepalive_interval)) return; + switch (busy_state) { + case IN_HANDLER: + case IN_PROCESS: + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("busy: processing"); + break; + case PAUSED_FOR_USER: + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("busy: paused for user"); + break; + case PAUSED_FOR_INPUT: + SERIAL_ECHO_START; + SERIAL_ECHOLNPGM("busy: paused for input"); + break; + default: + break; + } } - } - prev_busy_signal_ms = ms; + prev_busy_signal_ms = ms; } #endif @@ -1706,125 +1731,131 @@ void host_keepalive() { // Before loop(), the setup() function is called by the main() routine. void loop() { - KEEPALIVE_STATE(NOT_BUSY); + KEEPALIVE_STATE(NOT_BUSY); - if ((usb_printing_counter > 0) && ((millis()-_usb_timer) > 1000)) - { - is_usb_printing = true; - usb_printing_counter--; - _usb_timer = millis(); - } - if (usb_printing_counter == 0) - { - is_usb_printing = false; - } + if ((usb_printing_counter > 0) && ((millis()-_usb_timer) > 1000)) + { + is_usb_printing = true; + usb_printing_counter--; + _usb_timer = millis(); + } + if (usb_printing_counter == 0) + { + is_usb_printing = false; + } if (prusa_sd_card_upload) { //we read byte-by byte serial_read_stream(); - } else + } else { get_command(); - #ifdef SDSUPPORT - card.checkautostart(false); - #endif - if(buflen) - { - cmdbuffer_front_already_processed = false; - #ifdef SDSUPPORT - if(card.saving) - { - // Saving a G-code file onto an SD-card is in progress. - // Saving starts with M28, saving until M29 is seen. - if(strstr_P(CMDBUFFER_CURRENT_STRING, PSTR("M29")) == NULL) { - card.write_command(CMDBUFFER_CURRENT_STRING); - if(card.logging) +#ifdef SDSUPPORT + card.checkautostart(false); +#endif + if(buflen) + { + cmdbuffer_front_already_processed = false; +#ifdef SDSUPPORT + if(card.saving) + { + // Saving a G-code file onto an SD-card is in progress. + // Saving starts with M28, saving until M29 is seen. + if(strstr_P(CMDBUFFER_CURRENT_STRING, PSTR("M29")) == NULL) { + card.write_command(CMDBUFFER_CURRENT_STRING); + if(card.logging) + process_commands(); + else + SERIAL_PROTOCOLLNRPGM(_T(MSG_OK)); + } else { + card.closefile(); + SERIAL_PROTOCOLLNRPGM(MSG_FILE_SAVED); + } + } else { + process_commands(); + } +#else process_commands(); - else - SERIAL_PROTOCOLLNRPGM(_T(MSG_OK)); - } else { - card.closefile(); - SERIAL_PROTOCOLLNRPGM(MSG_FILE_SAVED); +#endif //SDSUPPORT + + if (! cmdbuffer_front_already_processed && buflen) + { + // ptr points to the start of the block currently being processed. + // The first character in the block is the block type. + char *ptr = cmdbuffer + bufindr; + if (*ptr == CMDBUFFER_CURRENT_TYPE_SDCARD) { + // To support power panic, move the lenght of the command on the SD card to a planner buffer. + union { + struct { + char lo; + char hi; + } lohi; + uint16_t value; + } sdlen; + sdlen.value = 0; + { + // This block locks the interrupts globally for 3.25 us, + // which corresponds to a maximum repeat frequency of 307.69 kHz. + // This blocking is safe in the context of a 10kHz stepper driver interrupt + // or a 115200 Bd serial line receive interrupt, which will not trigger faster than 12kHz. + cli(); + // Reset the command to something, which will be ignored by the power panic routine, + // so this buffer length will not be counted twice. + *ptr ++ = CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED; + // Extract the current buffer length. + sdlen.lohi.lo = *ptr ++; + sdlen.lohi.hi = *ptr; + // and pass it to the planner queue. + planner_add_sd_length(sdlen.value); + sei(); + } + } + else if((*ptr == CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR) && !IS_SD_PRINTING) { + + cli(); + *ptr ++ = CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED; + // and one for each command to previous block in the planner queue. + planner_add_sd_length(1); + sei(); + } + // Now it is safe to release the already processed command block. If interrupted by the power panic now, + // this block's SD card length will not be counted twice as its command type has been replaced + // by CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED. + cmdqueue_pop_front(); + } + host_keepalive(); } - } else { - process_commands(); - } - #else - process_commands(); - #endif //SDSUPPORT - - if (! cmdbuffer_front_already_processed && buflen) + } + //check heater every n milliseconds + manage_heater(); + isPrintPaused ? manage_inactivity(true) : manage_inactivity(false); + checkHitEndstops(); + lcd_update(0); +#ifdef TMC2130 + tmc2130_check_overtemp(); + if (tmc2130_sg_crash) { - // ptr points to the start of the block currently being processed. - // The first character in the block is the block type. - char *ptr = cmdbuffer + bufindr; - if (*ptr == CMDBUFFER_CURRENT_TYPE_SDCARD) { - // To support power panic, move the lenght of the command on the SD card to a planner buffer. - union { - struct { - char lo; - char hi; - } lohi; - uint16_t value; - } sdlen; - sdlen.value = 0; + uint8_t crash = tmc2130_sg_crash; + tmc2130_sg_crash = 0; +// crashdet_stop_and_save_print(); + switch (crash) { - // This block locks the interrupts globally for 3.25 us, - // which corresponds to a maximum repeat frequency of 307.69 kHz. - // This blocking is safe in the context of a 10kHz stepper driver interrupt - // or a 115200 Bd serial line receive interrupt, which will not trigger faster than 12kHz. - cli(); - // Reset the command to something, which will be ignored by the power panic routine, - // so this buffer length will not be counted twice. - *ptr ++ = CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED; - // Extract the current buffer length. - sdlen.lohi.lo = *ptr ++; - sdlen.lohi.hi = *ptr; - // and pass it to the planner queue. - planner_add_sd_length(sdlen.value); - sei(); + case 1: + enquecommand_P((PSTR("CRASH_DETECTEDX"))); + break; + case 2: + enquecommand_P((PSTR("CRASH_DETECTEDY"))); + break; + case 3: + enquecommand_P((PSTR("CRASH_DETECTEDXY"))); + break; } - } - else if((*ptr == CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR) && !IS_SD_PRINTING){ - - cli(); - *ptr ++ = CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED; - // and one for each command to previous block in the planner queue. - planner_add_sd_length(1); - sei(); - } - // Now it is safe to release the already processed command block. If interrupted by the power panic now, - // this block's SD card length will not be counted twice as its command type has been replaced - // by CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED. - cmdqueue_pop_front(); - } - host_keepalive(); - } -} - //check heater every n milliseconds - manage_heater(); - isPrintPaused ? manage_inactivity(true) : manage_inactivity(false); - checkHitEndstops(); - lcd_update(0); -#ifdef TMC2130 - tmc2130_check_overtemp(); - if (tmc2130_sg_crash) - { - uint8_t crash = tmc2130_sg_crash; - tmc2130_sg_crash = 0; -// crashdet_stop_and_save_print(); - switch (crash) - { - case 1: enquecommand_P((PSTR("CRASH_DETECTEDX"))); break; - case 2: enquecommand_P((PSTR("CRASH_DETECTEDY"))); break; - case 3: enquecommand_P((PSTR("CRASH_DETECTEDXY"))); break; - } - } + } #endif //TMC2130 - mmu_loop(); + mmu_loop(); } #define DEFINE_PGM_READ_ANY(type, reader) \ @@ -1850,14 +1881,18 @@ XYZ_CONSTS_FROM_CONFIG(float, home_retract_mm, HOME_RETRACT_MM); XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR); static void axis_is_at_home(int axis) { - current_position[axis] = base_home_pos(axis) + cs.add_homing[axis]; - min_pos[axis] = base_min_pos(axis) + cs.add_homing[axis]; - max_pos[axis] = base_max_pos(axis) + cs.add_homing[axis]; + current_position[axis] = base_home_pos(axis) + cs.add_homing[axis]; + min_pos[axis] = base_min_pos(axis) + cs.add_homing[axis]; + max_pos[axis] = base_max_pos(axis) + cs.add_homing[axis]; } -inline void set_current_to_destination() { memcpy(current_position, destination, sizeof(current_position)); } -inline void set_destination_to_current() { memcpy(destination, current_position, sizeof(destination)); } +inline void set_current_to_destination() { + memcpy(current_position, destination, sizeof(current_position)); +} +inline void set_destination_to_current() { + memcpy(destination, current_position, sizeof(destination)); +} //! @return original feedmultiply static int setup_for_endstop_move(bool enable_endstops_now = true) { @@ -1865,7 +1900,7 @@ static int setup_for_endstop_move(bool enable_endstops_now = true) { int l_feedmultiply = feedmultiply; feedmultiply = 100; previous_millis_cmd = millis(); - + enable_endstops(enable_endstops_now); return l_feedmultiply; } @@ -1875,7 +1910,7 @@ static void clean_up_after_endstop_move(int original_feedmultiply) { #ifdef ENDSTOPS_ONLY_FOR_HOMING enable_endstops(false); #endif - + feedrate = saved_feedrate; feedmultiply = original_feedmultiply; previous_millis_cmd = millis(); @@ -1948,7 +1983,7 @@ static void run_z_probe() { 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. + // 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]); @@ -1994,119 +2029,120 @@ static void do_blocking_move_relative(float offset_x, float offset_y, float offs /// 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]); - - run_z_probe(); - float measured_z = current_position[Z_AXIS]; - - SERIAL_PROTOCOLRPGM(_T(MSG_BED)); - SERIAL_PROTOCOLPGM(" x: "); - SERIAL_PROTOCOL(x); - SERIAL_PROTOCOLPGM(" y: "); - SERIAL_PROTOCOL(y); - SERIAL_PROTOCOLPGM(" z: "); - SERIAL_PROTOCOL(measured_z); - SERIAL_PROTOCOLPGM("\n"); - return measured_z; + // 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]); + + run_z_probe(); + float measured_z = current_position[Z_AXIS]; + + SERIAL_PROTOCOLRPGM(_T(MSG_BED)); + SERIAL_PROTOCOLPGM(" 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 #ifdef LIN_ADVANCE - /** - * M900: Set and/or Get advance K factor and WH/D ratio - * - * K Set advance K factor - * R Set ratio directly (overrides WH/D) - * W H D Set ratio from WH/D - */ +/** + * M900: Set and/or Get advance K factor and WH/D ratio + * + * K Set advance K factor + * R Set ratio directly (overrides WH/D) + * W H D Set ratio from WH/D + */ inline void gcode_M900() { st_synchronize(); - + const float newK = code_seen('K') ? code_value_float() : -1; if (newK >= 0) extruder_advance_k = newK; - + float newR = code_seen('R') ? code_value_float() : -1; if (newR < 0) { const float newD = code_seen('D') ? code_value_float() : -1, - newW = code_seen('W') ? code_value_float() : -1, - newH = code_seen('H') ? code_value_float() : -1; + newW = code_seen('W') ? code_value_float() : -1, + newH = code_seen('H') ? code_value_float() : -1; if (newD >= 0 && newW >= 0 && newH >= 0) newR = newD ? (newW * newH) / (sq(newD * 0.5) * M_PI) : 0; } if (newR >= 0) advance_ed_ratio = newR; - + SERIAL_ECHO_START; SERIAL_ECHOPGM("Advance K="); SERIAL_ECHOLN(extruder_advance_k); SERIAL_ECHOPGM(" E/D="); const float ratio = advance_ed_ratio; - if (ratio) SERIAL_ECHOLN(ratio); else SERIAL_ECHOLNPGM("Auto"); - } + if (ratio) SERIAL_ECHOLN(ratio); + else SERIAL_ECHOLNPGM("Auto"); +} #endif // LIN_ADVANCE bool check_commands() { - bool end_command_found = false; - - while (buflen) - { - if ((code_seen("M84")) || (code_seen("M 84"))) end_command_found = true; - if (!cmdbuffer_front_already_processed) - cmdqueue_pop_front(); - cmdbuffer_front_already_processed = false; - } - return end_command_found; - + bool end_command_found = false; + + while (buflen) + { + if ((code_seen("M84")) || (code_seen("M 84"))) end_command_found = true; + if (!cmdbuffer_front_already_processed) + cmdqueue_pop_front(); + cmdbuffer_front_already_processed = false; + } + return end_command_found; + } #ifdef TMC2130 bool calibrate_z_auto() { - //lcd_display_message_fullscreen_P(_T(MSG_CALIBRATE_Z_AUTO)); - lcd_clear(); - lcd_puts_at_P(0,1, _T(MSG_CALIBRATE_Z_AUTO)); - bool endstops_enabled = enable_endstops(true); - int axis_up_dir = -home_dir(Z_AXIS); - tmc2130_home_enter(Z_AXIS_MASK); - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - set_destination_to_current(); - destination[Z_AXIS] += (1.1 * max_length(Z_AXIS) * axis_up_dir); - feedrate = homing_feedrate[Z_AXIS]; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); + //lcd_display_message_fullscreen_P(_T(MSG_CALIBRATE_Z_AUTO)); + lcd_clear(); + lcd_puts_at_P(0,1, _T(MSG_CALIBRATE_Z_AUTO)); + bool endstops_enabled = enable_endstops(true); + int axis_up_dir = -home_dir(Z_AXIS); + tmc2130_home_enter(Z_AXIS_MASK); + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + set_destination_to_current(); + destination[Z_AXIS] += (1.1 * max_length(Z_AXIS) * axis_up_dir); + feedrate = homing_feedrate[Z_AXIS]; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); // current_position[axis] = 0; // plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - tmc2130_home_exit(); + tmc2130_home_exit(); enable_endstops(false); - current_position[Z_AXIS] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - set_destination_to_current(); - destination[Z_AXIS] += 10 * axis_up_dir; //10mm up - feedrate = homing_feedrate[Z_AXIS] / 2; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); + current_position[Z_AXIS] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + set_destination_to_current(); + destination[Z_AXIS] += 10 * axis_up_dir; //10mm up + feedrate = homing_feedrate[Z_AXIS] / 2; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); enable_endstops(endstops_enabled); current_position[Z_AXIS] = Z_MAX_POS+2.0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - return true; + return true; } #endif //TMC2130 void homeaxis(int axis, uint8_t cnt, uint8_t* pstep) { - bool endstops_enabled = enable_endstops(true); //RP: endstops should be allways enabled durring homing + bool endstops_enabled = enable_endstops(true); //RP: endstops should be allways enabled durring homing #define HOMEAXIS_DO(LETTER) \ ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1)) if ((axis==X_AXIS)?HOMEAXIS_DO(X):(axis==Y_AXIS)?HOMEAXIS_DO(Y):0) - { + { int axis_home_dir = home_dir(axis); feedrate = homing_feedrate[axis]; #ifdef TMC2130 - tmc2130_home_enter(X_AXIS_MASK << axis); + tmc2130_home_enter(X_AXIS_MASK << axis); #endif //TMC2130 @@ -2115,7 +2151,7 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep) // for the stall guard to work. current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - set_destination_to_current(); + set_destination_to_current(); // destination[axis] = 11.f; destination[axis] = -3.f * axis_home_dir; plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); @@ -2133,48 +2169,48 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep) destination[axis] = 1.1 * axis_home_dir * max_length(axis); plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); st_synchronize(); - for (uint8_t i = 0; i < cnt; i++) - { - // Move away from the collision to a known distance from the left end stop with the collision detection disabled. - endstops_hit_on_purpose(); - enable_endstops(false); - 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] = -10.f * axis_home_dir; - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); - endstops_hit_on_purpose(); - // Now move left up to the collision, this time with a repeatable velocity. - enable_endstops(true); - destination[axis] = 11.f * axis_home_dir; + for (uint8_t i = 0; i < cnt; i++) + { + // Move away from the collision to a known distance from the left end stop with the collision detection disabled. + endstops_hit_on_purpose(); + enable_endstops(false); + 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] = -10.f * axis_home_dir; + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); + endstops_hit_on_purpose(); + // Now move left up to the collision, this time with a repeatable velocity. + enable_endstops(true); + destination[axis] = 11.f * axis_home_dir; #ifdef TMC2130 - feedrate = homing_feedrate[axis]; + feedrate = homing_feedrate[axis]; #else //TMC2130 - feedrate = homing_feedrate[axis] / 2; + feedrate = homing_feedrate[axis] / 2; #endif //TMC2130 - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); - st_synchronize(); + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); + st_synchronize(); #ifdef TMC2130 - uint16_t mscnt = tmc2130_rd_MSCNT(axis); - if (pstep) pstep[i] = mscnt >> 4; - printf_P(PSTR("%3d step=%2d mscnt=%4d\n"), i, mscnt >> 4, mscnt); + uint16_t mscnt = tmc2130_rd_MSCNT(axis); + if (pstep) pstep[i] = mscnt >> 4; + printf_P(PSTR("%3d step=%2d mscnt=%4d\n"), i, mscnt >> 4, mscnt); #endif //TMC2130 - } - endstops_hit_on_purpose(); - enable_endstops(false); + } + endstops_hit_on_purpose(); + enable_endstops(false); #ifdef TMC2130 - uint8_t orig = tmc2130_home_origin[axis]; - uint8_t back = tmc2130_home_bsteps[axis]; - if (tmc2130_home_enabled && (orig <= 63)) - { - tmc2130_goto_step(axis, orig, 2, 1000, tmc2130_get_res(axis)); - if (back > 0) - tmc2130_do_steps(axis, back, -axis_home_dir, 1000); - } - else - tmc2130_do_steps(axis, 8, -axis_home_dir, 1000); - tmc2130_home_exit(); + uint8_t orig = tmc2130_home_origin[axis]; + uint8_t back = tmc2130_home_bsteps[axis]; + if (tmc2130_home_enabled && (orig <= 63)) + { + tmc2130_goto_step(axis, orig, 2, 1000, tmc2130_get_res(axis)); + if (back > 0) + tmc2130_do_steps(axis, back, -axis_home_dir, 1000); + } + else + tmc2130_do_steps(axis, 8, -axis_home_dir, 1000); + tmc2130_home_exit(); #endif //TMC2130 axis_is_at_home(axis); @@ -2192,13 +2228,13 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep) plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], 0.5f*feedrate/60, active_extruder); st_synchronize(); - feedrate = 0.0; + feedrate = 0.0; } else if ((axis==Z_AXIS)?HOMEAXIS_DO(Z):0) - { + { #ifdef TMC2130 - FORCE_HIGH_POWER_START; -#endif + FORCE_HIGH_POWER_START; +#endif int axis_home_dir = home_dir(axis); current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); @@ -2207,11 +2243,11 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep) plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); st_synchronize(); #ifdef TMC2130 - if (READ(Z_TMC2130_DIAG) != 0) { //Z crash - FORCE_HIGH_POWER_END; - kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); - return; - } + if (READ(Z_TMC2130_DIAG) != 0) { //Z crash + FORCE_HIGH_POWER_END; + kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); + return; + } #endif //TMC2130 current_position[axis] = 0; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); @@ -2223,11 +2259,11 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep) plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); st_synchronize(); #ifdef TMC2130 - if (READ(Z_TMC2130_DIAG) != 0) { //Z crash - FORCE_HIGH_POWER_END; - kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); - return; - } + if (READ(Z_TMC2130_DIAG) != 0) { //Z crash + FORCE_HIGH_POWER_END; + kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); + return; + } #endif //TMC2130 axis_is_at_home(axis); destination[axis] = current_position[axis]; @@ -2235,8 +2271,8 @@ void homeaxis(int axis, uint8_t cnt, uint8_t* pstep) endstops_hit_on_purpose(); axis_known_position[axis] = true; #ifdef TMC2130 - FORCE_HIGH_POWER_END; -#endif + FORCE_HIGH_POWER_END; +#endif } enable_endstops(endstops_enabled); } @@ -2253,42 +2289,42 @@ void home_xy() void refresh_cmd_timeout(void) { - previous_millis_cmd = millis(); + previous_millis_cmd = millis(); } #ifdef FWRETRACT - void retract(bool retracting, bool swapretract = false) { +void retract(bool retracting, bool swapretract = false) { if(retracting && !retracted[active_extruder]) { - 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]+=(swapretract?retract_length_swap:cs.retract_length)*float(extrudemultiply)*0.01f; - plan_set_e_position(current_position[E_AXIS]); - float oldFeedrate = feedrate; - feedrate=cs.retract_feedrate*60; - retracted[active_extruder]=true; - prepare_move(); - current_position[Z_AXIS]-=cs.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; + 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]+=(swapretract?retract_length_swap:cs.retract_length)*float(extrudemultiply)*0.01f; + plan_set_e_position(current_position[E_AXIS]); + float oldFeedrate = feedrate; + feedrate=cs.retract_feedrate*60; + retracted[active_extruder]=true; + prepare_move(); + current_position[Z_AXIS]-=cs.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[active_extruder]) { - 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]+=cs.retract_zlift; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - current_position[E_AXIS]-=(swapretract?(retract_length_swap+retract_recover_length_swap):(cs.retract_length+cs.retract_recover_length))*float(extrudemultiply)*0.01f; - plan_set_e_position(current_position[E_AXIS]); - float oldFeedrate = feedrate; - feedrate=cs.retract_recover_feedrate*60; - retracted[active_extruder]=false; - prepare_move(); - feedrate = oldFeedrate; - } - } //retract + 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]+=cs.retract_zlift; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + current_position[E_AXIS]-=(swapretract?(retract_length_swap+retract_recover_length_swap):(cs.retract_length+cs.retract_recover_length))*float(extrudemultiply)*0.01f; + plan_set_e_position(current_position[E_AXIS]); + float oldFeedrate = feedrate; + feedrate=cs.retract_recover_feedrate*60; + retracted[active_extruder]=false; + prepare_move(); + feedrate = oldFeedrate; + } +} //retract #endif //FWRETRACT void trace() { @@ -2385,114 +2421,118 @@ void ramming() { #ifdef TMC2130 void force_high_power_mode(bool start_high_power_section) { - uint8_t silent; - silent = eeprom_read_byte((uint8_t*)EEPROM_SILENT); - if (silent == 1) { - //we are in silent mode, set to normal mode to enable crash detection + uint8_t silent; + silent = eeprom_read_byte((uint8_t*)EEPROM_SILENT); + if (silent == 1) { + //we are in silent mode, set to normal mode to enable crash detection - // Wait for the planner queue to drain and for the stepper timer routine to reach an idle state. - st_synchronize(); - cli(); - tmc2130_mode = (start_high_power_section == true) ? TMC2130_MODE_NORMAL : TMC2130_MODE_SILENT; - update_mode_profile(); - tmc2130_init(); - // We may have missed a stepper timer interrupt due to the time spent in the tmc2130_init() routine. - // Be safe than sorry, reset the stepper timer before re-enabling interrupts. - st_reset_timer(); - sei(); - } + // Wait for the planner queue to drain and for the stepper timer routine to reach an idle state. + st_synchronize(); + cli(); + tmc2130_mode = (start_high_power_section == true) ? TMC2130_MODE_NORMAL : TMC2130_MODE_SILENT; + update_mode_profile(); + tmc2130_init(); + // We may have missed a stepper timer interrupt due to the time spent in the tmc2130_init() routine. + // Be safe than sorry, reset the stepper timer before re-enabling interrupts. + st_reset_timer(); + sei(); + } } #endif //TMC2130 void gcode_G28(bool home_x_axis, bool home_y_axis, bool home_z_axis) { - gcode_G28(home_x_axis, 0, home_y_axis, 0, home_z_axis, 0, false, true); + gcode_G28(home_x_axis, 0, home_y_axis, 0, home_z_axis, 0, false, true); } void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, long home_y_value, bool home_z_axis, long home_z_value, bool calib, bool without_mbl) { - st_synchronize(); + st_synchronize(); #if 0 - SERIAL_ECHOPGM("G28, initial "); print_world_coordinates(); - SERIAL_ECHOPGM("G28, initial "); print_physical_coordinates(); + SERIAL_ECHOPGM("G28, initial "); + print_world_coordinates(); + SERIAL_ECHOPGM("G28, initial "); + print_physical_coordinates(); #endif - // Flag for the display update routine and to disable the print cancelation during homing. - homing_flag = true; - - // Which axes should be homed? - bool home_x = home_x_axis; - bool home_y = home_y_axis; - bool home_z = home_z_axis; - - // Either all X,Y,Z codes are present, or none of them. - bool home_all_axes = home_x == home_y && home_x == home_z; - if (home_all_axes) - // No X/Y/Z code provided means to home all axes. - home_x = home_y = home_z = true; - - //if we are homing all axes, first move z higher to protect heatbed/steel sheet - if (home_all_axes) { - current_position[Z_AXIS] += MESH_HOME_Z_SEARCH; - feedrate = homing_feedrate[Z_AXIS]; - 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(); - } + // Flag for the display update routine and to disable the print cancelation during homing. + homing_flag = true; + + // Which axes should be homed? + bool home_x = home_x_axis; + bool home_y = home_y_axis; + bool home_z = home_z_axis; + + // Either all X,Y,Z codes are present, or none of them. + bool home_all_axes = home_x == home_y && home_x == home_z; + if (home_all_axes) + // No X/Y/Z code provided means to home all axes. + home_x = home_y = home_z = true; + + //if we are homing all axes, first move z higher to protect heatbed/steel sheet + if (home_all_axes) { + current_position[Z_AXIS] += MESH_HOME_Z_SEARCH; + feedrate = homing_feedrate[Z_AXIS]; + 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(); + } #ifdef ENABLE_AUTO_BED_LEVELING - plan_bed_level_matrix.set_to_identity(); //Reset the plane ("erase" all leveling data) + plan_bed_level_matrix.set_to_identity(); //Reset the plane ("erase" all leveling data) #endif //ENABLE_AUTO_BED_LEVELING - - // Reset world2machine_rotation_and_skew and world2machine_shift, therefore - // the planner will not perform any adjustments in the XY plane. - // Wait for the motors to stop and update the current position with the absolute values. - world2machine_revert_to_uncorrected(); - - // For mesh bed leveling deactivate the matrix temporarily. - // It is necessary to disable the bed leveling for the X and Y homing moves, so that the move is performed - // in a single axis only. - // In case of re-homing the X or Y axes only, the mesh bed leveling is restored after G28. + + // Reset world2machine_rotation_and_skew and world2machine_shift, therefore + // the planner will not perform any adjustments in the XY plane. + // Wait for the motors to stop and update the current position with the absolute values. + world2machine_revert_to_uncorrected(); + + // For mesh bed leveling deactivate the matrix temporarily. + // It is necessary to disable the bed leveling for the X and Y homing moves, so that the move is performed + // in a single axis only. + // In case of re-homing the X or Y axes only, the mesh bed leveling is restored after G28. #ifdef MESH_BED_LEVELING - uint8_t mbl_was_active = mbl.active; - mbl.active = 0; - current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); + uint8_t mbl_was_active = mbl.active; + mbl.active = 0; + current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); #endif - // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be - // consumed during the first movements following this statement. - if (home_z) + // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be + // consumed during the first movements following this statement. + if (home_z) babystep_undo(); - saved_feedrate = feedrate; - int l_feedmultiply = feedmultiply; - feedmultiply = 100; - previous_millis_cmd = millis(); + saved_feedrate = feedrate; + int l_feedmultiply = feedmultiply; + feedmultiply = 100; + previous_millis_cmd = millis(); - enable_endstops(true); + enable_endstops(true); - memcpy(destination, current_position, sizeof(destination)); - feedrate = 0.0; + memcpy(destination, current_position, sizeof(destination)); + feedrate = 0.0; - #if Z_HOME_DIR > 0 // If homing away from BED do Z first - if(home_z) +#if Z_HOME_DIR > 0 // If homing away from BED do Z first + if(home_z) homeaxis(Z_AXIS); - #endif +#endif - #ifdef QUICK_HOME - // In the quick mode, if both x and y are to be homed, a diagonal move will be performed initially. - if(home_x && home_y) //first diagonal move - { - current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0; +#ifdef QUICK_HOME + // In the quick mode, if both x and y are to be homed, a diagonal move will be performed initially. + if(home_x && home_y) //first diagonal move + { + current_position[X_AXIS] = 0; + current_position[Y_AXIS] = 0; int x_axis_home_dir = home_dir(X_AXIS); 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); + 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); + 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); + 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(); @@ -2510,155 +2550,160 @@ void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, long home_ current_position[X_AXIS] = destination[X_AXIS]; current_position[Y_AXIS] = destination[Y_AXIS]; current_position[Z_AXIS] = destination[Z_AXIS]; - } - #endif /* QUICK_HOME */ - -#ifdef TMC2130 - if(home_x) - { - if (!calib) - homeaxis(X_AXIS); - else - tmc2130_home_calibrate(X_AXIS); - } - - if(home_y) - { - if (!calib) - homeaxis(Y_AXIS); - else - tmc2130_home_calibrate(Y_AXIS); - } + } +#endif /* QUICK_HOME */ + +#ifdef TMC2130 + if(home_x) + { + if (!calib) + homeaxis(X_AXIS); + else + tmc2130_home_calibrate(X_AXIS); + } + + if(home_y) + { + if (!calib) + homeaxis(Y_AXIS); + else + tmc2130_home_calibrate(Y_AXIS); + } #else //TMC2130 - if(home_x) homeaxis(X_AXIS); - if(home_y) homeaxis(Y_AXIS); + if(home_x) homeaxis(X_AXIS); + if(home_y) homeaxis(Y_AXIS); #endif //TMC2130 - if(home_x_axis && home_x_value != 0) + if(home_x_axis && home_x_value != 0) current_position[X_AXIS]=home_x_value+cs.add_homing[X_AXIS]; - if(home_y_axis && home_y_value != 0) + if(home_y_axis && home_y_value != 0) current_position[Y_AXIS]=home_y_value+cs.add_homing[Y_AXIS]; - #if Z_HOME_DIR < 0 // If homing towards BED do Z last - #ifndef Z_SAFE_HOMING - if(home_z) { - #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 // defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0) - #if (defined(MESH_BED_LEVELING) && !defined(MK1BP)) // If Mesh bed leveling, move X&Y to safe position for home - if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] )) - { - homeaxis(X_AXIS); - homeaxis(Y_AXIS); - } - // 1st mesh bed leveling measurement point, corrected. - world2machine_initialize(); - world2machine(pgm_read_float(bed_ref_points_4), pgm_read_float(bed_ref_points_4+1), destination[X_AXIS], destination[Y_AXIS]); - world2machine_reset(); - if (destination[Y_AXIS] < Y_MIN_POS) - destination[Y_AXIS] = Y_MIN_POS; - destination[Z_AXIS] = MESH_HOME_Z_SEARCH; // Set destination away from bed - feedrate = homing_feedrate[Z_AXIS]/10; - current_position[Z_AXIS] = 0; - enable_endstops(false); +#if Z_HOME_DIR < 0 // If homing towards BED do Z last +#ifndef Z_SAFE_HOMING + if(home_z) { +#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 // defined (Z_RAISE_BEFORE_HOMING) && (Z_RAISE_BEFORE_HOMING > 0) +#if (defined(MESH_BED_LEVELING) && !defined(MK1BP)) // If Mesh bed leveling, move X&Y to safe position for home + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] )) + { + homeaxis(X_AXIS); + homeaxis(Y_AXIS); + } + // 1st mesh bed leveling measurement point, corrected. + world2machine_initialize(); + world2machine(pgm_read_float(bed_ref_points_4), pgm_read_float(bed_ref_points_4+1), destination[X_AXIS], destination[Y_AXIS]); + world2machine_reset(); + if (destination[Y_AXIS] < Y_MIN_POS) + destination[Y_AXIS] = Y_MIN_POS; + destination[Z_AXIS] = MESH_HOME_Z_SEARCH; // Set destination away from bed + feedrate = homing_feedrate[Z_AXIS]/10; + current_position[Z_AXIS] = 0; + enable_endstops(false); #ifdef DEBUG_BUILD - SERIAL_ECHOLNPGM("plan_set_position()"); - MYSERIAL.println(current_position[X_AXIS]);MYSERIAL.println(current_position[Y_AXIS]); - MYSERIAL.println(current_position[Z_AXIS]);MYSERIAL.println(current_position[E_AXIS]); + SERIAL_ECHOLNPGM("plan_set_position()"); + MYSERIAL.println(current_position[X_AXIS]); + MYSERIAL.println(current_position[Y_AXIS]); + MYSERIAL.println(current_position[Z_AXIS]); + MYSERIAL.println(current_position[E_AXIS]); #endif - 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]); #ifdef DEBUG_BUILD - SERIAL_ECHOLNPGM("plan_buffer_line()"); - MYSERIAL.println(destination[X_AXIS]);MYSERIAL.println(destination[Y_AXIS]); - MYSERIAL.println(destination[Z_AXIS]);MYSERIAL.println(destination[E_AXIS]); - MYSERIAL.println(feedrate);MYSERIAL.println(active_extruder); -#endif - 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]; - enable_endstops(true); - endstops_hit_on_purpose(); - homeaxis(Z_AXIS); - #else // MESH_BED_LEVELING - homeaxis(Z_AXIS); - #endif // MESH_BED_LEVELING - } - #else // defined(Z_SAFE_HOMING): Z Safe mode activated. - if(home_all_axes) { - 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/60; - current_position[Z_AXIS] = 0; + SERIAL_ECHOLNPGM("plan_buffer_line()"); + MYSERIAL.println(destination[X_AXIS]); + MYSERIAL.println(destination[Y_AXIS]); + MYSERIAL.println(destination[Z_AXIS]); + MYSERIAL.println(destination[E_AXIS]); + MYSERIAL.println(feedrate); + MYSERIAL.println(active_extruder); +#endif + 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]; + enable_endstops(true); + endstops_hit_on_purpose(); + homeaxis(Z_AXIS); +#else // MESH_BED_LEVELING + homeaxis(Z_AXIS); +#endif // MESH_BED_LEVELING + } +#else // defined(Z_SAFE_HOMING): Z Safe mode activated. + if(home_all_axes) { + 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/60; + 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_AXIS); + } + // Let's see if X and Y are homed and probe is inside bed area. + if(home_z) { + 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(); - current_position[X_AXIS] = destination[X_AXIS]; - current_position[Y_AXIS] = destination[Y_AXIS]; homeaxis(Z_AXIS); - } - // Let's see if X and Y are homed and probe is inside bed area. - if(home_z) { - 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_AXIS); - } else if (!((axis_known_position[X_AXIS]) && (axis_known_position[Y_AXIS]))) { - LCD_MESSAGERPGM(MSG_POSITION_UNKNOWN); - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM(MSG_POSITION_UNKNOWN); - } else { - LCD_MESSAGERPGM(MSG_ZPROBE_OUT); - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM(MSG_ZPROBE_OUT); - } - } - #endif // Z_SAFE_HOMING - #endif // Z_HOME_DIR < 0 + } else if (!((axis_known_position[X_AXIS]) && (axis_known_position[Y_AXIS]))) { + LCD_MESSAGERPGM(MSG_POSITION_UNKNOWN); + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(MSG_POSITION_UNKNOWN); + } else { + LCD_MESSAGERPGM(MSG_ZPROBE_OUT); + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(MSG_ZPROBE_OUT); + } + } +#endif // Z_SAFE_HOMING +#endif // Z_HOME_DIR < 0 - if(home_z_axis && home_z_value != 0) + if(home_z_axis && home_z_value != 0) current_position[Z_AXIS]=home_z_value+cs.add_homing[Z_AXIS]; - #ifdef ENABLE_AUTO_BED_LEVELING - if(home_z) - current_position[Z_AXIS] += cs.zprobe_zoffset; //Add Z_Probe offset (the distance is negative) - #endif - - // Set the planner and stepper routine positions. - // At this point the mesh bed leveling and world2machine corrections are disabled and current_position - // contains the machine coordinates. - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - - #ifdef ENDSTOPS_ONLY_FOR_HOMING - enable_endstops(false); - #endif +#ifdef ENABLE_AUTO_BED_LEVELING + if(home_z) + current_position[Z_AXIS] += cs.zprobe_zoffset; //Add Z_Probe offset (the distance is negative) +#endif + + // Set the planner and stepper routine positions. + // At this point the mesh bed leveling and world2machine corrections are disabled and current_position + // contains the machine coordinates. + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + +#ifdef ENDSTOPS_ONLY_FOR_HOMING + enable_endstops(false); +#endif - feedrate = saved_feedrate; - feedmultiply = l_feedmultiply; - previous_millis_cmd = millis(); - endstops_hit_on_purpose(); + feedrate = saved_feedrate; + feedmultiply = l_feedmultiply; + previous_millis_cmd = millis(); + endstops_hit_on_purpose(); #ifndef MESH_BED_LEVELING - // If MESH_BED_LEVELING is not active, then it is the original Prusa i3. - // Offer the user to load the baby step value, which has been adjusted at the previous print session. - if(card.sdprinting && eeprom_read_word((uint16_t *)EEPROM_BABYSTEP_Z)) - lcd_adjust_z(); + // If MESH_BED_LEVELING is not active, then it is the original Prusa i3. + // Offer the user to load the baby step value, which has been adjusted at the previous print session. + if(card.sdprinting && eeprom_read_word((uint16_t *)EEPROM_BABYSTEP_Z)) + lcd_adjust_z(); #endif // Load the machine correction matrix @@ -2667,39 +2712,44 @@ void gcode_G28(bool home_x_axis, long home_x_value, bool home_y_axis, long home_ world2machine_update_current(); #if (defined(MESH_BED_LEVELING) && !defined(MK1BP)) - if (home_x_axis || home_y_axis || without_mbl || home_z_axis) - { - if (! home_z && mbl_was_active) { - // Re-enable the mesh bed leveling if only the X and Y axes were re-homed. - mbl.active = true; - // and re-adjust the current logical Z axis with the bed leveling offset applicable at the current XY position. - current_position[Z_AXIS] -= mbl.get_z(st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS)); - } - } - else - { - st_synchronize(); - homing_flag = false; - } -#endif - - if (farm_mode) { prusa_statistics(20); }; - - homing_flag = false; + if (home_x_axis || home_y_axis || without_mbl || home_z_axis) + { + if (! home_z && mbl_was_active) { + // Re-enable the mesh bed leveling if only the X and Y axes were re-homed. + mbl.active = true; + // and re-adjust the current logical Z axis with the bed leveling offset applicable at the current XY position. + current_position[Z_AXIS] -= mbl.get_z(st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS)); + } + } + else + { + st_synchronize(); + homing_flag = false; + } +#endif + + if (farm_mode) { + prusa_statistics(20); + }; + + homing_flag = false; #if 0 - SERIAL_ECHOPGM("G28, final "); print_world_coordinates(); - SERIAL_ECHOPGM("G28, final "); print_physical_coordinates(); - SERIAL_ECHOPGM("G28, final "); print_mesh_bed_leveling_table(); + SERIAL_ECHOPGM("G28, final "); + print_world_coordinates(); + SERIAL_ECHOPGM("G28, final "); + print_physical_coordinates(); + SERIAL_ECHOPGM("G28, final "); + print_mesh_bed_leveling_table(); #endif } void adjust_bed_reset() { - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT, 0); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR, 0); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT, 0); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR, 0); } //! @brief Calibrate XYZ @@ -2709,216 +2759,216 @@ void adjust_bed_reset() //! @retval false Failed bool gcode_M45(bool onlyZ, int8_t verbosity_level) { - bool final_result = false; - #ifdef TMC2130 - FORCE_HIGH_POWER_START; - #endif // TMC2130 - // Only Z calibration? - if (!onlyZ) - { - setTargetBed(0); - setAllTargetHotends(0); - adjust_bed_reset(); //reset bed level correction - } + bool final_result = false; +#ifdef TMC2130 + FORCE_HIGH_POWER_START; +#endif // TMC2130 + // Only Z calibration? + if (!onlyZ) + { + setTargetBed(0); + setAllTargetHotends(0); + adjust_bed_reset(); //reset bed level correction + } + + // Disable the default update procedure of the display. We will do a modal dialog. + lcd_update_enable(false); + // Let the planner use the uncorrected coordinates. + mbl.reset(); + // Reset world2machine_rotation_and_skew and world2machine_shift, therefore + // the planner will not perform any adjustments in the XY plane. + // Wait for the motors to stop and update the current position with the absolute values. + world2machine_revert_to_uncorrected(); + // Reset the baby step value applied without moving the axes. + babystep_reset(); + // Mark all axes as in a need for homing. + memset(axis_known_position, 0, sizeof(axis_known_position)); + + // Home in the XY plane. + //set_destination_to_current(); + int l_feedmultiply = setup_for_endstop_move(); + lcd_display_message_fullscreen_P(_T(MSG_AUTO_HOME)); + home_xy(); + + enable_endstops(false); + current_position[X_AXIS] += 5; + current_position[Y_AXIS] += 5; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); + st_synchronize(); - // Disable the default update procedure of the display. We will do a modal dialog. - lcd_update_enable(false); - // Let the planner use the uncorrected coordinates. - mbl.reset(); - // Reset world2machine_rotation_and_skew and world2machine_shift, therefore - // the planner will not perform any adjustments in the XY plane. - // Wait for the motors to stop and update the current position with the absolute values. - world2machine_revert_to_uncorrected(); - // Reset the baby step value applied without moving the axes. - babystep_reset(); - // Mark all axes as in a need for homing. - memset(axis_known_position, 0, sizeof(axis_known_position)); - - // Home in the XY plane. - //set_destination_to_current(); - int l_feedmultiply = setup_for_endstop_move(); - lcd_display_message_fullscreen_P(_T(MSG_AUTO_HOME)); - home_xy(); - - enable_endstops(false); - current_position[X_AXIS] += 5; - current_position[Y_AXIS] += 5; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); - st_synchronize(); - - // Let the user move the Z axes up to the end stoppers. + // Let the user move the Z axes up to the end stoppers. #ifdef TMC2130 - if (calibrate_z_auto()) - { + if (calibrate_z_auto()) + { #else //TMC2130 - if (lcd_calibrate_z_end_stop_manual(onlyZ)) - { + if (lcd_calibrate_z_end_stop_manual(onlyZ)) + { #endif //TMC2130 - - lcd_show_fullscreen_message_and_wait_P(_T(MSG_CONFIRM_NOZZLE_CLEAN)); - if(onlyZ){ - lcd_display_message_fullscreen_P(_T(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1)); - lcd_set_cursor(0, 3); - lcd_print(1); - lcd_puts_P(_T(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2)); - }else{ - //lcd_show_fullscreen_message_and_wait_P(_T(MSG_PAPER)); - lcd_display_message_fullscreen_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1)); - lcd_set_cursor(0, 2); - lcd_print(1); - lcd_puts_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2)); - } - - refresh_cmd_timeout(); - #ifndef STEEL_SHEET - if (((degHotend(0) > MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) && (!onlyZ)) - { - lcd_wait_for_cool_down(); - } - #endif //STEEL_SHEET - if(!onlyZ) - { - KEEPALIVE_STATE(PAUSED_FOR_USER); - #ifdef STEEL_SHEET - bool result = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false); - if(result) lcd_show_fullscreen_message_and_wait_P(_T(MSG_REMOVE_STEEL_SHEET)); - #endif //STEEL_SHEET - lcd_show_fullscreen_message_and_wait_P(_T(MSG_PAPER)); - KEEPALIVE_STATE(IN_HANDLER); - lcd_display_message_fullscreen_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1)); - lcd_set_cursor(0, 2); - lcd_print(1); - lcd_puts_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2)); - } - - // Move the print head close to the bed. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - - bool endstops_enabled = enable_endstops(true); + + lcd_show_fullscreen_message_and_wait_P(_T(MSG_CONFIRM_NOZZLE_CLEAN)); + if(onlyZ) { + lcd_display_message_fullscreen_P(_T(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE1)); + lcd_set_cursor(0, 3); + lcd_print(1); + lcd_puts_P(_T(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2)); + } else { + //lcd_show_fullscreen_message_and_wait_P(_T(MSG_PAPER)); + lcd_display_message_fullscreen_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1)); + lcd_set_cursor(0, 2); + lcd_print(1); + lcd_puts_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2)); + } + + refresh_cmd_timeout(); +#ifndef STEEL_SHEET + if (((degHotend(0) > MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) && (!onlyZ)) + { + lcd_wait_for_cool_down(); + } +#endif //STEEL_SHEET + if(!onlyZ) + { + KEEPALIVE_STATE(PAUSED_FOR_USER); +#ifdef STEEL_SHEET + bool result = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false); + if(result) lcd_show_fullscreen_message_and_wait_P(_T(MSG_REMOVE_STEEL_SHEET)); +#endif //STEEL_SHEET + lcd_show_fullscreen_message_and_wait_P(_T(MSG_PAPER)); + KEEPALIVE_STATE(IN_HANDLER); + lcd_display_message_fullscreen_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1)); + lcd_set_cursor(0, 2); + lcd_print(1); + lcd_puts_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2)); + } + + // Move the print head close to the bed. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + + bool endstops_enabled = enable_endstops(true); #ifdef TMC2130 - tmc2130_home_enter(Z_AXIS_MASK); + tmc2130_home_enter(Z_AXIS_MASK); #endif //TMC2130 - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); - st_synchronize(); + st_synchronize(); #ifdef TMC2130 - tmc2130_home_exit(); + tmc2130_home_exit(); #endif //TMC2130 - enable_endstops(endstops_enabled); - - if (st_get_position_mm(Z_AXIS) == MESH_HOME_Z_SEARCH) - { - if (onlyZ) - { - clean_up_after_endstop_move(l_feedmultiply); - // Z only calibration. - // Load the machine correction matrix - world2machine_initialize(); - // and correct the current_position to match the transformed coordinate system. - world2machine_update_current(); - //FIXME - bool result = sample_mesh_and_store_reference(); - if (result) - { - if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION) - // Shipped, the nozzle height has been set already. The user can start printing now. - calibration_status_store(CALIBRATION_STATUS_CALIBRATED); - final_result = true; - // babystep_apply(); - } - } - else - { - // Reset the baby step value and the baby step applied flag. - calibration_status_store(CALIBRATION_STATUS_XYZ_CALIBRATION); - eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0); - // Complete XYZ calibration. - uint8_t point_too_far_mask = 0; - BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level, point_too_far_mask); - clean_up_after_endstop_move(l_feedmultiply); - // Print head up. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); - st_synchronize(); + enable_endstops(endstops_enabled); + + if (st_get_position_mm(Z_AXIS) == MESH_HOME_Z_SEARCH) + { + if (onlyZ) + { + clean_up_after_endstop_move(l_feedmultiply); + // Z only calibration. + // Load the machine correction matrix + world2machine_initialize(); + // and correct the current_position to match the transformed coordinate system. + world2machine_update_current(); + //FIXME + bool result = sample_mesh_and_store_reference(); + if (result) + { + if (calibration_status() == CALIBRATION_STATUS_Z_CALIBRATION) + // Shipped, the nozzle height has been set already. The user can start printing now. + calibration_status_store(CALIBRATION_STATUS_CALIBRATED); + final_result = true; + // babystep_apply(); + } + } + else + { + // Reset the baby step value and the baby step applied flag. + calibration_status_store(CALIBRATION_STATUS_XYZ_CALIBRATION); + eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0); + // Complete XYZ calibration. + uint8_t point_too_far_mask = 0; + BedSkewOffsetDetectionResultType result = find_bed_offset_and_skew(verbosity_level, point_too_far_mask); + clean_up_after_endstop_move(l_feedmultiply); + // Print head up. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); + st_synchronize(); //#ifndef NEW_XYZCAL - if (result >= 0) - { - #ifdef HEATBED_V2 - sample_z(); - #else //HEATBED_V2 - point_too_far_mask = 0; - // Second half: The fine adjustment. - // Let the planner use the uncorrected coordinates. - mbl.reset(); - world2machine_reset(); - // Home in the XY plane. - int l_feedmultiply = setup_for_endstop_move(); - home_xy(); - result = improve_bed_offset_and_skew(1, verbosity_level, point_too_far_mask); - clean_up_after_endstop_move(l_feedmultiply); - // Print head up. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); - st_synchronize(); - // if (result >= 0) babystep_apply(); - #endif //HEATBED_V2 - } + if (result >= 0) + { +#ifdef HEATBED_V2 + sample_z(); +#else //HEATBED_V2 + point_too_far_mask = 0; + // Second half: The fine adjustment. + // Let the planner use the uncorrected coordinates. + mbl.reset(); + world2machine_reset(); + // Home in the XY plane. + int l_feedmultiply = setup_for_endstop_move(); + home_xy(); + result = improve_bed_offset_and_skew(1, verbosity_level, point_too_far_mask); + clean_up_after_endstop_move(l_feedmultiply); + // Print head up. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); + st_synchronize(); + // if (result >= 0) babystep_apply(); +#endif //HEATBED_V2 + } //#endif //NEW_XYZCAL - lcd_update_enable(true); - lcd_update(2); - - lcd_bed_calibration_show_result(result, point_too_far_mask); - if (result >= 0) - { - // Calibration valid, the machine should be able to print. Advise the user to run the V2Calibration.gcode. - calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST); - if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) lcd_show_fullscreen_message_and_wait_P(_T(MSG_BABYSTEP_Z_NOT_SET)); - final_result = true; - } - } -#ifdef TMC2130 - tmc2130_home_exit(); -#endif - } - else - { - lcd_show_fullscreen_message_and_wait_P(PSTR("Calibration failed! Check the axes and run again.")); - final_result = false; - } - } - else - { - // Timeouted. - } - lcd_update_enable(true); + lcd_update_enable(true); + lcd_update(2); + + lcd_bed_calibration_show_result(result, point_too_far_mask); + if (result >= 0) + { + // Calibration valid, the machine should be able to print. Advise the user to run the V2Calibration.gcode. + calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST); + if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) lcd_show_fullscreen_message_and_wait_P(_T(MSG_BABYSTEP_Z_NOT_SET)); + final_result = true; + } + } +#ifdef TMC2130 + tmc2130_home_exit(); +#endif + } + else + { + lcd_show_fullscreen_message_and_wait_P(PSTR("Calibration failed! Check the axes and run again.")); + final_result = false; + } + } + else + { + // Timeouted. + } + lcd_update_enable(true); #ifdef TMC2130 - FORCE_HIGH_POWER_END; + FORCE_HIGH_POWER_END; #endif // TMC2130 - return final_result; + return final_result; } void gcode_M114() { - SERIAL_PROTOCOLPGM("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(" E:"); - SERIAL_PROTOCOL(current_position[E_AXIS]); - - SERIAL_PROTOCOLRPGM(_n(" Count X: "));////MSG_COUNT_X c=0 r=0 - SERIAL_PROTOCOL(float(st_get_position(X_AXIS)) / cs.axis_steps_per_unit[X_AXIS]); - SERIAL_PROTOCOLPGM(" Y:"); - SERIAL_PROTOCOL(float(st_get_position(Y_AXIS)) / cs.axis_steps_per_unit[Y_AXIS]); - SERIAL_PROTOCOLPGM(" Z:"); - SERIAL_PROTOCOL(float(st_get_position(Z_AXIS)) / cs.axis_steps_per_unit[Z_AXIS]); - SERIAL_PROTOCOLPGM(" E:"); - SERIAL_PROTOCOL(float(st_get_position(E_AXIS)) / cs.axis_steps_per_unit[E_AXIS]); - - SERIAL_PROTOCOLLN(""); + SERIAL_PROTOCOLPGM("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(" E:"); + SERIAL_PROTOCOL(current_position[E_AXIS]); + + SERIAL_PROTOCOLRPGM(_n(" Count X: "));////MSG_COUNT_X c=0 r=0 + SERIAL_PROTOCOL(float(st_get_position(X_AXIS)) / cs.axis_steps_per_unit[X_AXIS]); + SERIAL_PROTOCOLPGM(" Y:"); + SERIAL_PROTOCOL(float(st_get_position(Y_AXIS)) / cs.axis_steps_per_unit[Y_AXIS]); + SERIAL_PROTOCOLPGM(" Z:"); + SERIAL_PROTOCOL(float(st_get_position(Z_AXIS)) / cs.axis_steps_per_unit[Z_AXIS]); + SERIAL_PROTOCOLPGM(" E:"); + SERIAL_PROTOCOL(float(st_get_position(E_AXIS)) / cs.axis_steps_per_unit[E_AXIS]); + + SERIAL_PROTOCOLLN(""); } static void gcode_M600(bool automatic, float x_position, float y_position, float z_shift, float e_shift, float /*e_shift_late*/) @@ -2945,20 +2995,20 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float //Retract E current_position[E_AXIS] += e_shift; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder); + current_position[E_AXIS], FILAMENTCHANGE_RFEED, active_extruder); st_synchronize(); //Lift Z current_position[Z_AXIS] += z_shift; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder); + current_position[E_AXIS], FILAMENTCHANGE_ZFEED, active_extruder); st_synchronize(); //Move XY to side current_position[X_AXIS] = x_position; current_position[Y_AXIS] = y_position; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder); + current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder); st_synchronize(); //Beep, manage nozzle heater and wait for user to start unload filament @@ -2976,18 +3026,18 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float { KEEPALIVE_STATE(PAUSED_FOR_USER); lcd_change_fil_state = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Was filament unload successful?"), - false, true); ////MSG_UNLOAD_SUCCESSFUL c=20 r=2 + false, true); ////MSG_UNLOAD_SUCCESSFUL c=20 r=2 if (lcd_change_fil_state == 0) { - lcd_clear(); - lcd_set_cursor(0, 2); - lcd_puts_P(_T(MSG_PLEASE_WAIT)); - current_position[X_AXIS] -= 100; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder); - st_synchronize(); - lcd_show_fullscreen_message_and_wait_P(_i("Please open idler and remove filament manually."));////MSG_CHECK_IDLER c=20 r=4 - lcd_update_enable(true); + lcd_clear(); + lcd_set_cursor(0, 2); + lcd_puts_P(_T(MSG_PLEASE_WAIT)); + current_position[X_AXIS] -= 100; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], + current_position[E_AXIS], FILAMENTCHANGE_XYFEED, active_extruder); + st_synchronize(); + lcd_show_fullscreen_message_and_wait_P(_i("Please open idler and remove filament manually."));////MSG_CHECK_IDLER c=20 r=4 + lcd_update_enable(true); } } @@ -3013,7 +3063,7 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float if (!automatic) M600_check_state(); - lcd_update_enable(true); + lcd_update_enable(true); //Not let's go back to print fanSpeed = fanSpeedBckp; @@ -3023,16 +3073,16 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float { current_position[E_AXIS] += FILAMENTCHANGE_RECFEED; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], - current_position[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder); + current_position[E_AXIS], FILAMENTCHANGE_EXFEED, active_extruder); } //Move XY back plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], - FILAMENTCHANGE_XYFEED, active_extruder); + FILAMENTCHANGE_XYFEED, active_extruder); st_synchronize(); //Move Z back plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], current_position[E_AXIS], - FILAMENTCHANGE_ZFEED, active_extruder); + FILAMENTCHANGE_ZFEED, active_extruder); st_synchronize(); //Set E position to original @@ -3056,47 +3106,47 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float void gcode_M701() { - printf_P(PSTR("gcode_M701 begin\n")); + printf_P(PSTR("gcode_M701 begin\n")); - if (mmu_enabled) - { - extr_adj(tmp_extruder);//loads current extruder - mmu_extruder = tmp_extruder; - } - else - { - enable_z(); - custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; + if (mmu_enabled) + { + extr_adj(tmp_extruder);//loads current extruder + mmu_extruder = tmp_extruder; + } + else + { + enable_z(); + custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; #ifdef FSENSOR_QUALITY - fsensor_oq_meassure_start(40); + fsensor_oq_meassure_start(40); #endif //FSENSOR_QUALITY - lcd_setstatuspgm(_T(MSG_LOADING_FILAMENT)); - current_position[E_AXIS] += 40; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder); //fast sequence - st_synchronize(); + lcd_setstatuspgm(_T(MSG_LOADING_FILAMENT)); + current_position[E_AXIS] += 40; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder); //fast sequence + st_synchronize(); - if (current_position[Z_AXIS] < 20) current_position[Z_AXIS] += 30; - current_position[E_AXIS] += 30; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder); //fast sequence - - load_filament_final_feed(); //slow sequence - st_synchronize(); + if (current_position[Z_AXIS] < 20) current_position[Z_AXIS] += 30; + current_position[E_AXIS] += 30; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400 / 60, active_extruder); //fast sequence + + load_filament_final_feed(); //slow sequence + st_synchronize(); - if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) tone(BEEPER, 500); - delay_keep_alive(50); - noTone(BEEPER); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) tone(BEEPER, 500); + delay_keep_alive(50); + noTone(BEEPER); - if (!farm_mode && loading_flag) { - lcd_load_filament_color_check(); - } - lcd_update_enable(true); - lcd_update(2); - lcd_setstatuspgm(_T(WELCOME_MSG)); - disable_z(); - loading_flag = false; - custom_message_type = CUSTOM_MSG_TYPE_STATUS; + if (!farm_mode && loading_flag) { + lcd_load_filament_color_check(); + } + lcd_update_enable(true); + lcd_update(2); + lcd_setstatuspgm(_T(WELCOME_MSG)); + disable_z(); + loading_flag = false; + custom_message_type = CUSTOM_MSG_TYPE_STATUS; #ifdef FSENSOR_QUALITY fsensor_oq_meassure_stop(); @@ -3110,7 +3160,7 @@ void gcode_M701() fsensor_disable(); } #endif //FSENSOR_QUALITY - } + } } /** * @brief Get serial number from 32U2 processor @@ -3299,179 +3349,179 @@ extern uint8_t st_backlash_y; //!@n M999 - Restart after being stopped by error void process_commands() { - if (!buflen) return; //empty command - #ifdef FILAMENT_RUNOUT_SUPPORT + if (!buflen) return; //empty command +#ifdef FILAMENT_RUNOUT_SUPPORT SET_INPUT(FR_SENS); - #endif +#endif #ifdef CMDBUFFER_DEBUG - SERIAL_ECHOPGM("Processing a GCODE command: "); - SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("In cmdqueue: "); - SERIAL_ECHO(buflen); - SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Processing a GCODE command: "); + SERIAL_ECHO(cmdbuffer+bufindr+CMDHDRSIZE); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("In cmdqueue: "); + SERIAL_ECHO(buflen); + SERIAL_ECHOLNPGM(""); #endif /* CMDBUFFER_DEBUG */ - - unsigned long codenum; //throw away variable - char *starpos = NULL; + + unsigned long codenum; //throw away variable + char *starpos = NULL; #ifdef ENABLE_AUTO_BED_LEVELING - float x_tmp, y_tmp, z_tmp, real_z; + float x_tmp, y_tmp, z_tmp, real_z; #endif - // PRUSA GCODES - KEEPALIVE_STATE(IN_HANDLER); + // PRUSA GCODES + KEEPALIVE_STATE(IN_HANDLER); #ifdef SNMM - float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT; - float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; - int8_t SilentMode; -#endif - - if (code_seen("M117")) { //moved to highest priority place to be able to to print strings which includes "G", "PRUSA" and "^" - starpos = (strchr(strchr_pointer + 5, '*')); - if (starpos != NULL) - *(starpos) = '\0'; - lcd_setstatus(strchr_pointer + 5); - } + float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT; + float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; + int8_t SilentMode; +#endif + + if (code_seen("M117")) { //moved to highest priority place to be able to to print strings which includes "G", "PRUSA" and "^" + starpos = (strchr(strchr_pointer + 5, '*')); + if (starpos != NULL) + *(starpos) = '\0'; + lcd_setstatus(strchr_pointer + 5); + } #ifdef TMC2130 - else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("CRASH_"), 6) == 0) - { - if(code_seen("CRASH_DETECTED")) //! CRASH_DETECTED - { - uint8_t mask = 0; - if (code_seen('X')) mask |= X_AXIS_MASK; - if (code_seen('Y')) mask |= Y_AXIS_MASK; - crashdet_detected(mask); - } - else if(code_seen("CRASH_RECOVER")) //! CRASH_RECOVER - crashdet_recover(); - else if(code_seen("CRASH_CANCEL")) //! CRASH_CANCEL - crashdet_cancel(); - } - else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("TMC_"), 4) == 0) - { - if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_WAVE_"), 9) == 0) //! TMC_SET_WAVE_ - { - uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13); - axis = (axis == 'E')?3:(axis - 'X'); - if (axis < 4) - { - uint8_t fac = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 14, NULL, 10); - tmc2130_set_wave(axis, 247, fac); - } - } - else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_STEP_"), 9) == 0) //! TMC_SET_STEP_ - { - uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13); - axis = (axis == 'E')?3:(axis - 'X'); - if (axis < 4) - { - uint8_t step = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 14, NULL, 10); - uint16_t res = tmc2130_get_res(axis); - tmc2130_goto_step(axis, step & (4*res - 1), 2, 1000, res); - } - } - else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_CHOP_"), 9) == 0) //! TMC_SET_CHOP_ - { - uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13); - axis = (axis == 'E')?3:(axis - 'X'); - if (axis < 4) - { - uint8_t chop0 = tmc2130_chopper_config[axis].toff; - uint8_t chop1 = tmc2130_chopper_config[axis].hstr; - uint8_t chop2 = tmc2130_chopper_config[axis].hend; - uint8_t chop3 = tmc2130_chopper_config[axis].tbl; - char* str_end = 0; - if (CMDBUFFER_CURRENT_STRING[14]) - { - chop0 = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 14, &str_end, 10) & 15; - if (str_end && *str_end) - { - chop1 = (uint8_t)strtol(str_end, &str_end, 10) & 7; - if (str_end && *str_end) - { - chop2 = (uint8_t)strtol(str_end, &str_end, 10) & 15; - if (str_end && *str_end) - chop3 = (uint8_t)strtol(str_end, &str_end, 10) & 3; - } - } - } - tmc2130_chopper_config[axis].toff = chop0; - tmc2130_chopper_config[axis].hstr = chop1 & 7; - tmc2130_chopper_config[axis].hend = chop2 & 15; - tmc2130_chopper_config[axis].tbl = chop3 & 3; - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); - //printf_P(_N("TMC_SET_CHOP_%c %hhd %hhd %hhd %hhd\n"), "xyze"[axis], chop0, chop1, chop2, chop3); - } - } - } + else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("CRASH_"), 6) == 0) + { + if(code_seen("CRASH_DETECTED")) //! CRASH_DETECTED + { + uint8_t mask = 0; + if (code_seen('X')) mask |= X_AXIS_MASK; + if (code_seen('Y')) mask |= Y_AXIS_MASK; + crashdet_detected(mask); + } + else if(code_seen("CRASH_RECOVER")) //! CRASH_RECOVER + crashdet_recover(); + else if(code_seen("CRASH_CANCEL")) //! CRASH_CANCEL + crashdet_cancel(); + } + else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("TMC_"), 4) == 0) + { + if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_WAVE_"), 9) == 0) //! TMC_SET_WAVE_ + { + uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13); + axis = (axis == 'E')?3:(axis - 'X'); + if (axis < 4) + { + uint8_t fac = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 14, NULL, 10); + tmc2130_set_wave(axis, 247, fac); + } + } + else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_STEP_"), 9) == 0) //! TMC_SET_STEP_ + { + uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13); + axis = (axis == 'E')?3:(axis - 'X'); + if (axis < 4) + { + uint8_t step = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 14, NULL, 10); + uint16_t res = tmc2130_get_res(axis); + tmc2130_goto_step(axis, step & (4*res - 1), 2, 1000, res); + } + } + else if (strncmp_P(CMDBUFFER_CURRENT_STRING + 4, PSTR("SET_CHOP_"), 9) == 0) //! TMC_SET_CHOP_ + { + uint8_t axis = *(CMDBUFFER_CURRENT_STRING + 13); + axis = (axis == 'E')?3:(axis - 'X'); + if (axis < 4) + { + uint8_t chop0 = tmc2130_chopper_config[axis].toff; + uint8_t chop1 = tmc2130_chopper_config[axis].hstr; + uint8_t chop2 = tmc2130_chopper_config[axis].hend; + uint8_t chop3 = tmc2130_chopper_config[axis].tbl; + char* str_end = 0; + if (CMDBUFFER_CURRENT_STRING[14]) + { + chop0 = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 14, &str_end, 10) & 15; + if (str_end && *str_end) + { + chop1 = (uint8_t)strtol(str_end, &str_end, 10) & 7; + if (str_end && *str_end) + { + chop2 = (uint8_t)strtol(str_end, &str_end, 10) & 15; + if (str_end && *str_end) + chop3 = (uint8_t)strtol(str_end, &str_end, 10) & 3; + } + } + } + tmc2130_chopper_config[axis].toff = chop0; + tmc2130_chopper_config[axis].hstr = chop1 & 7; + tmc2130_chopper_config[axis].hend = chop2 & 15; + tmc2130_chopper_config[axis].tbl = chop3 & 3; + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + //printf_P(_N("TMC_SET_CHOP_%c %hhd %hhd %hhd %hhd\n"), "xyze"[axis], chop0, chop1, chop2, chop3); + } + } + } #ifdef BACKLASH_X - else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("BACKLASH_X"), 10) == 0) - { - uint8_t bl = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 10, NULL, 10); - st_backlash_x = bl; - printf_P(_N("st_backlash_x = %hhd\n"), st_backlash_x); - } + else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("BACKLASH_X"), 10) == 0) + { + uint8_t bl = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 10, NULL, 10); + st_backlash_x = bl; + printf_P(_N("st_backlash_x = %hhd\n"), st_backlash_x); + } #endif //BACKLASH_X #ifdef BACKLASH_Y - else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("BACKLASH_Y"), 10) == 0) - { - uint8_t bl = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 10, NULL, 10); - st_backlash_y = bl; - printf_P(_N("st_backlash_y = %hhd\n"), st_backlash_y); - } + else if (strncmp_P(CMDBUFFER_CURRENT_STRING, PSTR("BACKLASH_Y"), 10) == 0) + { + uint8_t bl = (uint8_t)strtol(CMDBUFFER_CURRENT_STRING + 10, NULL, 10); + st_backlash_y = bl; + printf_P(_N("st_backlash_y = %hhd\n"), st_backlash_y); + } #endif //BACKLASH_Y #endif //TMC2130 #ifdef PAT9125 - else if (code_seen("FSENSOR_RECOVER")) { //! FSENSOR_RECOVER - fsensor_restore_print_and_continue(); - } + else if (code_seen("FSENSOR_RECOVER")) { //! FSENSOR_RECOVER + fsensor_restore_print_and_continue(); + } #endif //PAT9125 - else if(code_seen("PRUSA")){ - if (code_seen("Ping")) { //! PRUSA Ping - if (farm_mode) { - PingTime = millis(); - //MYSERIAL.print(farm_no); MYSERIAL.println(": OK"); - } - } - else if (code_seen("PRN")) { //! PRUSA PRN - printf_P(_N("%d"), status_number); - - }else if (code_seen("FAN")) { //! PRUSA FAN - printf_P(_N("E0:%d RPM\nPRN0:%d RPM\n"), 60*fan_speed[0], 60*fan_speed[1]); - }else if (code_seen("fn")) { //! PRUSA fn - if (farm_mode) { - printf_P(_N("%d"), farm_no); - } - else { - puts_P(_N("Not in farm mode.")); - } - - } - else if (code_seen("thx")) //! PRUSA thx - { - no_response = false; - } - else if (code_seen("uvlo")) //! PRUSA uvlo - { - eeprom_update_byte((uint8_t*)EEPROM_UVLO,0); - enquecommand_P(PSTR("M24")); - } - else if (code_seen("MMURES")) //! PRUSA MMURES - { - mmu_reset(); - } - else if (code_seen("RESET")) { //! PRUSA RESET + else if(code_seen("PRUSA")) { + if (code_seen("Ping")) { //! PRUSA Ping + if (farm_mode) { + PingTime = millis(); + //MYSERIAL.print(farm_no); MYSERIAL.println(": OK"); + } + } + else if (code_seen("PRN")) { //! PRUSA PRN + printf_P(_N("%d"), status_number); + + } else if (code_seen("FAN")) { //! PRUSA FAN + printf_P(_N("E0:%d RPM\nPRN0:%d RPM\n"), 60*fan_speed[0], 60*fan_speed[1]); + } else if (code_seen("fn")) { //! PRUSA fn + if (farm_mode) { + printf_P(_N("%d"), farm_no); + } + else { + puts_P(_N("Not in farm mode.")); + } + + } + else if (code_seen("thx")) //! PRUSA thx + { + no_response = false; + } + else if (code_seen("uvlo")) //! PRUSA uvlo + { + eeprom_update_byte((uint8_t*)EEPROM_UVLO,0); + enquecommand_P(PSTR("M24")); + } + else if (code_seen("MMURES")) //! PRUSA MMURES + { + mmu_reset(); + } + else if (code_seen("RESET")) { //! PRUSA RESET // careful! if (farm_mode) { #ifdef WATCHDOG boot_app_magic = BOOT_APP_MAGIC; boot_app_flags = BOOT_APP_FLG_RUN; - wdt_enable(WDTO_15MS); - cli(); - while(1); + wdt_enable(WDTO_15MS); + cli(); + while(1); #else //WATCHDOG asm volatile("jmp 0x3E000"); #endif //WATCHDOG @@ -3479,333 +3529,333 @@ void process_commands() else { MYSERIAL.println("Not in farm mode."); } - }else if (code_seen("fv")) { //! PRUSA fv - // get file version - #ifdef SDSUPPORT - card.openFile(strchr_pointer + 3,true); - while (true) { - uint16_t readByte = card.get(); - MYSERIAL.write(readByte); - if (readByte=='\n') { - break; + } else if (code_seen("fv")) { //! PRUSA fv + // get file version +#ifdef SDSUPPORT + card.openFile(strchr_pointer + 3,true); + while (true) { + uint16_t readByte = card.get(); + MYSERIAL.write(readByte); + if (readByte=='\n') { + break; + } } - } - card.closefile(); + card.closefile(); - #endif // SDSUPPORT +#endif // SDSUPPORT - } else if (code_seen("M28")) { //! PRUSA M28 - trace(); - prusa_sd_card_upload = true; - card.openFile(strchr_pointer+4,false); + } else if (code_seen("M28")) { //! PRUSA M28 + trace(); + prusa_sd_card_upload = true; + card.openFile(strchr_pointer+4,false); - } else if (code_seen("SN")) { //! PRUSA SN - gcode_PRUSA_SN(); + } else if (code_seen("SN")) { //! PRUSA SN + gcode_PRUSA_SN(); - } else if(code_seen("Fir")){ //! PRUSA Fir + } else if(code_seen("Fir")) { //! PRUSA Fir - SERIAL_PROTOCOLLN(FW_VERSION_FULL); + SERIAL_PROTOCOLLN(FW_VERSION_FULL); - } else if(code_seen("Rev")){ //! PRUSA Rev + } else if(code_seen("Rev")) { //! PRUSA Rev - SERIAL_PROTOCOLLN(FILAMENT_SIZE "-" ELECTRONICS "-" NOZZLE_TYPE ); + SERIAL_PROTOCOLLN(FILAMENT_SIZE "-" ELECTRONICS "-" NOZZLE_TYPE ); - } else if(code_seen("Lang")) { //! PRUSA Lang - lang_reset(); + } else if(code_seen("Lang")) { //! PRUSA Lang + lang_reset(); - } else if(code_seen("Lz")) { //! PRUSA Lz - EEPROM_save_B(EEPROM_BABYSTEP_Z,0); + } else if(code_seen("Lz")) { //! PRUSA Lz + EEPROM_save_B(EEPROM_BABYSTEP_Z,0); - } else if(code_seen("Beat")) { //! PRUSA Beat - // Kick farm link timer - kicktime = millis(); + } else if(code_seen("Beat")) { //! PRUSA Beat + // Kick farm link timer + kicktime = millis(); - } else if(code_seen("FR")) { //! PRUSA FR - // Factory full reset - factory_reset(0); - } - //else if (code_seen('Cal')) { - // lcd_calibration(); - // } + } else if(code_seen("FR")) { //! PRUSA FR + // Factory full reset + factory_reset(0); + } + //else if (code_seen('Cal')) { + // lcd_calibration(); + // } - } - else if (code_seen('^')) { - // nothing, this is a version line - } else if(code_seen('G')) - { - gcode_in_progress = (int)code_value(); -// printf_P(_N("BEGIN G-CODE=%u\n"), gcode_in_progress); - switch (gcode_in_progress) + } + else if (code_seen('^')) { + // nothing, this is a version line + } else if(code_seen('G')) { - case 0: // G0 -> G1 - case 1: // G1 - if(Stopped == false) { - - #ifdef FILAMENT_RUNOUT_SUPPORT - - if(READ(FR_SENS)){ - - int feedmultiplyBckp=feedmultiply; - float target[4]; - float lastpos[4]; - target[X_AXIS]=current_position[X_AXIS]; - target[Y_AXIS]=current_position[Y_AXIS]; - target[Z_AXIS]=current_position[Z_AXIS]; - target[E_AXIS]=current_position[E_AXIS]; - lastpos[X_AXIS]=current_position[X_AXIS]; - lastpos[Y_AXIS]=current_position[Y_AXIS]; - lastpos[Z_AXIS]=current_position[Z_AXIS]; - lastpos[E_AXIS]=current_position[E_AXIS]; - //retract by E - - target[E_AXIS]+= FILAMENTCHANGE_FIRSTRETRACT ; - - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder); - - - target[Z_AXIS]+= FILAMENTCHANGE_ZADD ; - - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 300, active_extruder); - - target[X_AXIS]= FILAMENTCHANGE_XPOS ; - - target[Y_AXIS]= FILAMENTCHANGE_YPOS ; - - - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 70, active_extruder); - - target[E_AXIS]+= FILAMENTCHANGE_FINALRETRACT ; - - - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 20, active_extruder); - - //finish moves - st_synchronize(); - //disable extruder steppers so filament can be removed - disable_e0(); - disable_e1(); - disable_e2(); - delay(100); - - //LCD_ALERTMESSAGEPGM(_T(MSG_FILAMENTCHANGE)); - uint8_t cnt=0; - int counterBeep = 0; - lcd_wait_interact(); - while(!lcd_clicked()){ - cnt++; - manage_heater(); - manage_inactivity(true); - //lcd_update(0); - if(cnt==0) - { - #if BEEPER > 0 - - if (counterBeep== 500){ - counterBeep = 0; - + gcode_in_progress = (int)code_value(); +// printf_P(_N("BEGIN G-CODE=%u\n"), gcode_in_progress); + switch (gcode_in_progress) + { + case 0: // G0 -> G1 + case 1: // G1 + if(Stopped == false) { + +#ifdef FILAMENT_RUNOUT_SUPPORT + + if(READ(FR_SENS)) { + + int feedmultiplyBckp=feedmultiply; + float target[4]; + float lastpos[4]; + target[X_AXIS]=current_position[X_AXIS]; + target[Y_AXIS]=current_position[Y_AXIS]; + target[Z_AXIS]=current_position[Z_AXIS]; + target[E_AXIS]=current_position[E_AXIS]; + lastpos[X_AXIS]=current_position[X_AXIS]; + lastpos[Y_AXIS]=current_position[Y_AXIS]; + lastpos[Z_AXIS]=current_position[Z_AXIS]; + lastpos[E_AXIS]=current_position[E_AXIS]; + //retract by E + + target[E_AXIS]+= FILAMENTCHANGE_FIRSTRETRACT ; + + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder); + + + target[Z_AXIS]+= FILAMENTCHANGE_ZADD ; + + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 300, active_extruder); + + target[X_AXIS]= FILAMENTCHANGE_XPOS ; + + target[Y_AXIS]= FILAMENTCHANGE_YPOS ; + + + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 70, active_extruder); + + target[E_AXIS]+= FILAMENTCHANGE_FINALRETRACT ; + + + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 20, active_extruder); + + //finish moves + st_synchronize(); + //disable extruder steppers so filament can be removed + disable_e0(); + disable_e1(); + disable_e2(); + delay(100); + + //LCD_ALERTMESSAGEPGM(_T(MSG_FILAMENTCHANGE)); + uint8_t cnt=0; + int counterBeep = 0; + lcd_wait_interact(); + while(!lcd_clicked()) { + cnt++; + manage_heater(); + manage_inactivity(true); + //lcd_update(0); + if(cnt==0) + { +#if BEEPER > 0 + + if (counterBeep== 500) { + counterBeep = 0; + } - - + + SET_OUTPUT(BEEPER); - if (counterBeep== 0){ -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - WRITE(BEEPER,HIGH); + if (counterBeep== 0) { + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + WRITE(BEEPER,HIGH); } - - if (counterBeep== 20){ - WRITE(BEEPER,LOW); + + if (counterBeep== 20) { + WRITE(BEEPER,LOW); } - - - - + + + + counterBeep++; - #else - #endif - } +#else +#endif } - - WRITE(BEEPER,LOW); - - target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 20, active_extruder); - - - target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); - - - - - + } + + WRITE(BEEPER,LOW); + + target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 20, active_extruder); + + + target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); + + + + + + lcd_change_fil_state = 0; + lcd_loading_filament(); + while ((lcd_change_fil_state == 0)||(lcd_change_fil_state != 1)) { + lcd_change_fil_state = 0; - lcd_loading_filament(); - while ((lcd_change_fil_state == 0)||(lcd_change_fil_state != 1)){ - - lcd_change_fil_state = 0; - lcd_alright(); - switch(lcd_change_fil_state){ - - case 2: - target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 20, active_extruder); - - - target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); - - - lcd_loading_filament(); - break; - case 3: - target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); - lcd_loading_color(); - break; - - default: - lcd_change_success(); - break; - } - + lcd_alright(); + switch(lcd_change_fil_state) { + + case 2: + target[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 20, active_extruder); + + + target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); + + + lcd_loading_filament(); + break; + case 3: + target[E_AXIS]+= FILAMENTCHANGE_FINALFEED ; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); + lcd_loading_color(); + break; + + default: + lcd_change_success(); + break; } - - - - target[E_AXIS]+= 5; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); - - target[E_AXIS]+= FILAMENTCHANGE_FIRSTRETRACT; - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder); - - - //current_position[E_AXIS]=target[E_AXIS]; //the long retract of L is compensated by manual filament feeding - //plan_set_e_position(current_position[E_AXIS]); - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 70, active_extruder); //should do nothing - plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], target[Z_AXIS], target[E_AXIS], 70, active_extruder); //move xy back - plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], target[E_AXIS], 200, active_extruder); //move z back - - - target[E_AXIS]= target[E_AXIS] - FILAMENTCHANGE_FIRSTRETRACT; - - - - plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], target[E_AXIS], 5, active_extruder); //final untretract - - - plan_set_e_position(lastpos[E_AXIS]); - - feedmultiply=feedmultiplyBckp; - - - - char cmd[9]; - - sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp); - enquecommand(cmd); - } + } + + + + target[E_AXIS]+= 5; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 2, active_extruder); + + target[E_AXIS]+= FILAMENTCHANGE_FIRSTRETRACT; + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 400, active_extruder); + + + //current_position[E_AXIS]=target[E_AXIS]; //the long retract of L is compensated by manual filament feeding + //plan_set_e_position(current_position[E_AXIS]); + plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], 70, active_extruder); //should do nothing + plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], target[Z_AXIS], target[E_AXIS], 70, active_extruder); //move xy back + plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], target[E_AXIS], 200, active_extruder); //move z back + + + target[E_AXIS]= target[E_AXIS] - FILAMENTCHANGE_FIRSTRETRACT; - #endif + plan_buffer_line(lastpos[X_AXIS], lastpos[Y_AXIS], lastpos[Z_AXIS], target[E_AXIS], 5, active_extruder); //final untretract - get_coordinates(); // For X Y Z E F - if (total_filament_used > ((current_position[E_AXIS] - destination[E_AXIS]) * 100)) { //protection against total_filament_used overflow - total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS]) * 100); - } - #ifdef FWRETRACT - if(cs.autoretract_enabled) - if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) { - float echange=destination[E_AXIS]-current_position[E_AXIS]; + plan_set_e_position(lastpos[E_AXIS]); - if((echange<-MIN_RETRACT && !retracted[active_extruder]) || (echange>MIN_RETRACT && retracted[active_extruder])) { //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[active_extruder]); - return; - } + feedmultiply=feedmultiplyBckp; + + char cmd[9]; + + sprintf_P(cmd, PSTR("M220 S%i"), feedmultiplyBckp); + enquecommand(cmd); + + } + + + +#endif + + + get_coordinates(); // For X Y Z E F + if (total_filament_used > ((current_position[E_AXIS] - destination[E_AXIS]) * 100)) { //protection against total_filament_used overflow + total_filament_used = total_filament_used + ((destination[E_AXIS] - current_position[E_AXIS]) * 100); + } +#ifdef FWRETRACT + if(cs.autoretract_enabled) + 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[active_extruder]) || (echange>MIN_RETRACT && retracted[active_extruder])) { //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[active_extruder]); + return; + } + + + } +#endif //FWRETRACT + prepare_move(); + //ClearToSend(); } - #endif //FWRETRACT - prepare_move(); - //ClearToSend(); - } - break; - case 2: // G2 - CW ARC - if(Stopped == false) { - get_arc_coordinates(); - prepare_arc_move(true); - } - break; - case 3: // G3 - CCW ARC - if(Stopped == false) { - get_arc_coordinates(); - prepare_arc_move(false); - } - break; - case 4: // G4 dwell - codenum = 0; - if(code_seen('P')) codenum = code_value(); // milliseconds to wait - if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait - if(codenum != 0) LCD_MESSAGERPGM(_i("Sleep..."));////MSG_DWELL c=0 r=0 - st_synchronize(); - codenum += millis(); // keep track of when we started waiting - previous_millis_cmd = millis(); - while(millis() < codenum) { - manage_heater(); - manage_inactivity(); - lcd_update(0); - } - break; - #ifdef FWRETRACT - case 10: // G10 retract - #if EXTRUDERS > 1 - retracted_swap[active_extruder]=(code_seen('S') && code_value_long() == 1); // checks for swap retract argument - retract(true,retracted_swap[active_extruder]); - #else - retract(true); - #endif - break; - case 11: // G11 retract_recover - #if EXTRUDERS > 1 - retract(false,retracted_swap[active_extruder]); - #else - retract(false); - #endif - break; - #endif //FWRETRACT - case 28: //G28 Home all Axis one at a time - { - long home_x_value = 0; - long home_y_value = 0; - long home_z_value = 0; - // Which axes should be homed? - bool home_x = code_seen(axis_codes[X_AXIS]); - home_x_value = code_value_long(); - bool home_y = code_seen(axis_codes[Y_AXIS]); - home_y_value = code_value_long(); - bool home_z = code_seen(axis_codes[Z_AXIS]); - home_z_value = code_value_long(); - bool without_mbl = code_seen('W'); - // calibrate? - bool calib = code_seen('C'); - gcode_G28(home_x, home_x_value, home_y, home_y_value, home_z, home_z_value, calib, without_mbl); - if ((home_x || home_y || without_mbl || home_z) == false) { - // Push the commands to the front of the message queue in the reverse order! - // There shall be always enough space reserved for these commands. - goto case_G80; - } - break; - } + break; + case 2: // G2 - CW ARC + if(Stopped == false) { + get_arc_coordinates(); + prepare_arc_move(true); + } + break; + case 3: // G3 - CCW ARC + if(Stopped == false) { + get_arc_coordinates(); + prepare_arc_move(false); + } + break; + case 4: // G4 dwell + codenum = 0; + if(code_seen('P')) codenum = code_value(); // milliseconds to wait + if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait + if(codenum != 0) LCD_MESSAGERPGM(_i("Sleep..."));////MSG_DWELL c=0 r=0 + st_synchronize(); + codenum += millis(); // keep track of when we started waiting + previous_millis_cmd = millis(); + while(millis() < codenum) { + manage_heater(); + manage_inactivity(); + lcd_update(0); + } + break; +#ifdef FWRETRACT + case 10: // G10 retract +#if EXTRUDERS > 1 + retracted_swap[active_extruder]=(code_seen('S') && code_value_long() == 1); // checks for swap retract argument + retract(true,retracted_swap[active_extruder]); +#else + retract(true); +#endif + break; + case 11: // G11 retract_recover +#if EXTRUDERS > 1 + retract(false,retracted_swap[active_extruder]); +#else + retract(false); +#endif + break; +#endif //FWRETRACT + case 28: //G28 Home all Axis one at a time + { + long home_x_value = 0; + long home_y_value = 0; + long home_z_value = 0; + // Which axes should be homed? + bool home_x = code_seen(axis_codes[X_AXIS]); + home_x_value = code_value_long(); + bool home_y = code_seen(axis_codes[Y_AXIS]); + home_y_value = code_value_long(); + bool home_z = code_seen(axis_codes[Z_AXIS]); + home_z_value = code_value_long(); + bool without_mbl = code_seen('W'); + // calibrate? + bool calib = code_seen('C'); + gcode_G28(home_x, home_x_value, home_y, home_y_value, home_z, home_z_value, calib, without_mbl); + if ((home_x || home_y || without_mbl || home_z) == false) { + // Push the commands to the front of the message queue in the reverse order! + // There shall be always enough space reserved for these commands. + goto case_G80; + } + break; + } #ifdef ENABLE_AUTO_BED_LEVELING - case 29: // G29 Detailed Z-Probe, probes the bed at 3 or more 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." - #endif +#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 // Prevent user from running a G29 without first homing in X and Y if (! (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) ) @@ -3854,44 +3904,44 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) 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 < AUTO_BED_LEVELING_GRID_POINTS; xCount++) - { - float z_before; - if (probePointCounter == 0) + int xProbe, xInc; + if (zig) { - // raise before probing - z_before = Z_RAISE_BEFORE_PROBING; - } else + xProbe = LEFT_PROBE_BED_POSITION; + //xEnd = RIGHT_PROBE_BED_POSITION; + xInc = xGridSpacing; + zig = false; + } else // zag { - // raise extruder - z_before = current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS; + xProbe = RIGHT_PROBE_BED_POSITION; + //xEnd = LEFT_PROBE_BED_POSITION; + xInc = -xGridSpacing; + zig = true; } - float measured_z = probe_pt(xProbe, yProbe, z_before); + for (int xCount=0; xCount < AUTO_BED_LEVELING_GRID_POINTS; xCount++) + { + float z_before; + if (probePointCounter == 0) + { + // raise before probing + z_before = Z_RAISE_BEFORE_PROBING; + } else + { + // raise extruder + z_before = current_position[Z_AXIS] + Z_RAISE_BETWEEN_PROBINGS; + } + + float measured_z = probe_pt(xProbe, yProbe, z_before); - eqnBVector[probePointCounter] = measured_z; + eqnBVector[probePointCounter] = measured_z; - 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; - } + 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; + } } clean_up_after_endstop_move(l_feedmultiply); @@ -3944,7 +3994,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) } break; #ifndef Z_PROBE_SLED - case 30: // G30 Single Z Probe + case 30: // G30 Single Z Probe { st_synchronize(); // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly @@ -3966,17 +4016,17 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) } break; #else - case 31: // dock the sled - dock_sled(true); - break; - case 32: // undock the sled - dock_sled(false); - break; + case 31: // dock the sled + dock_sled(true); + break; + case 32: // undock the sled + dock_sled(false); + break; #endif // Z_PROBE_SLED #endif // ENABLE_AUTO_BED_LEVELING - + #ifdef MESH_BED_LEVELING - case 30: // G30 Single Z Probe + case 30: // G30 Single Z Probe { st_synchronize(); // TODO: make sure the bed_level_rotation_matrix is identity or the planner will get set incorectly @@ -3986,649 +4036,664 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) find_bed_induction_sensor_point_z(-10.f, 3); - printf_P(_N("%S X: %.5f Y: %.5f Z: %.5f\n"), _T(MSG_BED), _x, _y, _z); + printf_P(_N("%S X: %.5f Y: %.5f Z: %.5f\n"), _T(MSG_BED), _x, _y, _z); clean_up_after_endstop_move(l_feedmultiply); } break; - - case 75: - { - for (int i = 40; i <= 110; i++) - printf_P(_N("%d %.2f"), i, temp_comp_interpolation(i)); - } - break; - case 76: //! G76 - PINDA probe temperature calibration - { + case 75: + { + for (int i = 40; i <= 110; i++) + printf_P(_N("%d %.2f"), i, temp_comp_interpolation(i)); + } + break; + + case 76: //! G76 - PINDA probe temperature calibration + { #ifdef PINDA_THERMISTOR - if (true) - { - - if (calibration_status() >= CALIBRATION_STATUS_XYZ_CALIBRATION) { - //we need to know accurate position of first calibration point - //if xyz calibration was not performed yet, interrupt temperature calibration and inform user that xyz cal. is needed - lcd_show_fullscreen_message_and_wait_P(_i("Please run XYZ calibration first.")); - break; - } - - if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) - { - // We don't know where we are! HOME! - // Push the commands to the front of the message queue in the reverse order! - // There shall be always enough space reserved for these commands. - repeatcommand_front(); // repeat G76 with all its parameters - enquecommand_front_P((PSTR("G28 W0"))); - break; - } - lcd_show_fullscreen_message_and_wait_P(_i("Stable ambient temperature 21-26C is needed a rigid stand is required."));////MSG_TEMP_CAL_WARNING c=20 r=4 - bool result = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false); - - if (result) - { - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[Z_AXIS] = 50; - current_position[Y_AXIS] = 180; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - lcd_show_fullscreen_message_and_wait_P(_T(MSG_REMOVE_STEEL_SHEET)); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + 1); - current_position[X_AXIS] = pgm_read_float(bed_ref_points_4); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - gcode_G28(false, false, true); - - } - if ((current_temperature_pinda > 35) && (farm_mode == false)) { - //waiting for PIDNA probe to cool down in case that we are not in farm mode - current_position[Z_AXIS] = 100; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - if (lcd_wait_for_pinda(35) == false) { //waiting for PINDA probe to cool, if this takes more then time expected, temp. cal. fails - lcd_temp_cal_show_result(false); - break; - } - } - lcd_update_enable(true); - KEEPALIVE_STATE(NOT_BUSY); //no need to print busy messages as we print current temperatures periodicaly - SERIAL_ECHOLNPGM("PINDA probe calibration start"); - - float zero_z; - int z_shift = 0; //unit: steps - float start_temp = 5 * (int)(current_temperature_pinda / 5); - if (start_temp < 35) start_temp = 35; - if (start_temp < current_temperature_pinda) start_temp += 5; - printf_P(_N("start temperature: %.1f\n"), start_temp); + if (true) + { -// setTargetHotend(200, 0); - setTargetBed(70 + (start_temp - 30)); - - custom_message_type = CUSTOM_MSG_TYPE_TEMCAL; - custom_message_state = 1; - lcd_setstatuspgm(_T(MSG_TEMP_CALIBRATION)); - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[X_AXIS] = PINDA_PREHEAT_X; - current_position[Y_AXIS] = PINDA_PREHEAT_Y; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[Z_AXIS] = PINDA_PREHEAT_Z; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - - while (current_temperature_pinda < start_temp) - { - delay_keep_alive(1000); - serialecho_temperatures(); - } - - eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); //invalidate temp. calibration in case that in will be aborted during the calibration process - - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[X_AXIS] = pgm_read_float(bed_ref_points_4); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + 1); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - - bool find_z_result = find_bed_induction_sensor_point_z(-1.f); - if (find_z_result == false) { - lcd_temp_cal_show_result(find_z_result); - break; - } - zero_z = current_position[Z_AXIS]; - - printf_P(_N("\nZERO: %.3f\n"), current_position[Z_AXIS]); - - int i = -1; for (; i < 5; i++) - { - float temp = (40 + i * 5); - printf_P(_N("\nStep: %d/6 (skipped)\nPINDA temperature: %d Z shift (mm):0\n"), i + 2, (40 + i*5)); - if (i >= 0) EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); - if (start_temp <= temp) break; - } - - for (i++; i < 5; i++) - { - float temp = (40 + i * 5); - printf_P(_N("\nStep: %d/6\n"), i + 2); - custom_message_state = i + 2; - setTargetBed(50 + 10 * (temp - 30) / 5); -// setTargetHotend(255, 0); - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[X_AXIS] = PINDA_PREHEAT_X; - current_position[Y_AXIS] = PINDA_PREHEAT_Y; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[Z_AXIS] = PINDA_PREHEAT_Z; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - while (current_temperature_pinda < temp) - { - delay_keep_alive(1000); - serialecho_temperatures(); - } - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[X_AXIS] = pgm_read_float(bed_ref_points_4); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + 1); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - find_z_result = find_bed_induction_sensor_point_z(-1.f); - if (find_z_result == false) { - lcd_temp_cal_show_result(find_z_result); - break; - } - z_shift = (int)((current_position[Z_AXIS] - zero_z)*cs.axis_steps_per_unit[Z_AXIS]); - - printf_P(_N("\nPINDA temperature: %.1f Z shift (mm): %.3f"), current_temperature_pinda, current_position[Z_AXIS] - zero_z); - - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); - - } - lcd_temp_cal_show_result(true); - - break; - } -#endif //PINDA_THERMISTOR + if (calibration_status() >= CALIBRATION_STATUS_XYZ_CALIBRATION) { + //we need to know accurate position of first calibration point + //if xyz calibration was not performed yet, interrupt temperature calibration and inform user that xyz cal. is needed + lcd_show_fullscreen_message_and_wait_P(_i("Please run XYZ calibration first.")); + break; + } - setTargetBed(PINDA_MIN_T); - float zero_z; - int z_shift = 0; //unit: steps - int t_c; // temperature - - if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { - // We don't know where we are! HOME! - // Push the commands to the front of the message queue in the reverse order! - // There shall be always enough space reserved for these commands. - repeatcommand_front(); // repeat G76 with all its parameters - enquecommand_front_P((PSTR("G28 W0"))); - break; - } - puts_P(_N("PINDA probe calibration start")); - custom_message_type = CUSTOM_MSG_TYPE_TEMCAL; - custom_message_state = 1; - lcd_setstatuspgm(_T(MSG_TEMP_CALIBRATION)); - current_position[X_AXIS] = PINDA_PREHEAT_X; - current_position[Y_AXIS] = PINDA_PREHEAT_Y; - current_position[Z_AXIS] = PINDA_PREHEAT_Z; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - - while (abs(degBed() - PINDA_MIN_T) > 1) { - delay_keep_alive(1000); - serialecho_temperatures(); - } - - //enquecommand_P(PSTR("M190 S50")); - for (int i = 0; i < PINDA_HEAT_T; i++) { - delay_keep_alive(1000); - serialecho_temperatures(); - } - eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); //invalidate temp. calibration in case that in will be aborted during the calibration process - - current_position[Z_AXIS] = 5; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) + { + // We don't know where we are! HOME! + // Push the commands to the front of the message queue in the reverse order! + // There shall be always enough space reserved for these commands. + repeatcommand_front(); // repeat G76 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); + break; + } + lcd_show_fullscreen_message_and_wait_P(_i("Stable ambient temperature 21-26C is needed a rigid stand is required."));////MSG_TEMP_CAL_WARNING c=20 r=4 + bool result = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false); - current_position[X_AXIS] = pgm_read_float(bed_ref_points); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - - find_bed_induction_sensor_point_z(-1.f); - zero_z = current_position[Z_AXIS]; - - printf_P(_N("\nZERO: %.3f\n"), current_position[Z_AXIS]); - - for (int i = 0; i<5; i++) { - printf_P(_N("\nStep: %d/6\n"), i + 2); - custom_message_state = i + 2; - t_c = 60 + i * 10; - - setTargetBed(t_c); - current_position[X_AXIS] = PINDA_PREHEAT_X; - current_position[Y_AXIS] = PINDA_PREHEAT_Y; - current_position[Z_AXIS] = PINDA_PREHEAT_Z; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - while (degBed() < t_c) { - delay_keep_alive(1000); - serialecho_temperatures(); - } - for (int i = 0; i < PINDA_HEAT_T; i++) { - delay_keep_alive(1000); - serialecho_temperatures(); - } - current_position[Z_AXIS] = 5; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - current_position[X_AXIS] = pgm_read_float(bed_ref_points); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - find_bed_induction_sensor_point_z(-1.f); - z_shift = (int)((current_position[Z_AXIS] - zero_z)*cs.axis_steps_per_unit[Z_AXIS]); - - printf_P(_N("\nTemperature: %d Z shift (mm): %.3f\n"), t_c, current_position[Z_AXIS] - zero_z); - - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i*2, &z_shift); - - - } - custom_message_type = CUSTOM_MSG_TYPE_STATUS; - - eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); - puts_P(_N("Temperature calibration done.")); - disable_x(); - disable_y(); - disable_z(); - disable_e0(); - disable_e1(); - disable_e2(); - setTargetBed(0); //set bed target temperature back to 0 - lcd_show_fullscreen_message_and_wait_P(_T(MSG_TEMP_CALIBRATION_DONE)); - temp_cal_active = true; - eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 1); - lcd_update_enable(true); - lcd_update(2); - - + if (result) + { + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[Z_AXIS] = 50; + current_position[Y_AXIS] = 180; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + lcd_show_fullscreen_message_and_wait_P(_T(MSG_REMOVE_STEEL_SHEET)); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + 1); + current_position[X_AXIS] = pgm_read_float(bed_ref_points_4); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + gcode_G28(false, false, true); - } - break; + } + if ((current_temperature_pinda > 35) && (farm_mode == false)) { + //waiting for PIDNA probe to cool down in case that we are not in farm mode + current_position[Z_AXIS] = 100; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + if (lcd_wait_for_pinda(35) == false) { //waiting for PINDA probe to cool, if this takes more then time expected, temp. cal. fails + lcd_temp_cal_show_result(false); + break; + } + } + lcd_update_enable(true); + KEEPALIVE_STATE(NOT_BUSY); //no need to print busy messages as we print current temperatures periodicaly + SERIAL_ECHOLNPGM("PINDA probe calibration start"); -#ifdef DIS - case 77: - { - //! G77 X200 Y150 XP100 YP15 XO10 Y015 - //! for 9 point mesh bed leveling G77 X203 Y196 XP3 YP3 XO0 YO0 - //! G77 X232 Y218 XP116 YP109 XO-11 YO0 - - float dimension_x = 40; - float dimension_y = 40; - int points_x = 40; - int points_y = 40; - float offset_x = 74; - float offset_y = 33; - - if (code_seen('X')) dimension_x = code_value(); - if (code_seen('Y')) dimension_y = code_value(); - if (code_seen("XP")) { strchr_pointer+=1; points_x = code_value(); } - if (code_seen("YP")) { strchr_pointer+=1; points_y = code_value(); } - if (code_seen("XO")) { strchr_pointer+=1; offset_x = code_value(); } - if (code_seen("YO")) { strchr_pointer+=1; offset_y = code_value(); } - - bed_analysis(dimension_x,dimension_y,points_x,points_y,offset_x,offset_y); - - } break; - -#endif - - case 79: { - for (int i = 255; i > 0; i = i - 5) { - fanSpeed = i; - //delay_keep_alive(2000); - for (int j = 0; j < 100; j++) { - delay_keep_alive(100); - - } - printf_P(_N("%d: %d\n"), i, fan_speed[1]); - } - }break; - - /** - * G80: Mesh-based Z probe, probes a grid and produces a - * mesh to compensate for variable bed height - * - * The S0 report the points as below - * @code{.unparsed} - * +----> X-axis - * | - * | - * v Y-axis - * @endcode - */ - - case 80: -#ifdef MK1BP - break; -#endif //MK1BP - case_G80: - { - mesh_bed_leveling_flag = true; - static bool run = false; + float zero_z; + int z_shift = 0; //unit: steps + float start_temp = 5 * (int)(current_temperature_pinda / 5); + if (start_temp < 35) start_temp = 35; + if (start_temp < current_temperature_pinda) start_temp += 5; + printf_P(_N("start temperature: %.1f\n"), start_temp); -#ifdef SUPPORT_VERBOSITY - int8_t verbosity_level = 0; - if (code_seen('V')) { - // Just 'V' without a number counts as V1. - char c = strchr_pointer[1]; - verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short(); - } -#endif //SUPPORT_VERBOSITY - // Firstly check if we know where we are - if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { - // We don't know where we are! HOME! - // Push the commands to the front of the message queue in the reverse order! - // There shall be always enough space reserved for these commands. - if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) { - repeatcommand_front(); // repeat G80 with all its parameters - enquecommand_front_P((PSTR("G28 W0"))); - } - else { - mesh_bed_leveling_flag = false; - } - break; - } - - - bool temp_comp_start = true; -#ifdef PINDA_THERMISTOR - temp_comp_start = false; -#endif //PINDA_THERMISTOR +// setTargetHotend(200, 0); + setTargetBed(70 + (start_temp - 30)); + + custom_message_type = CUSTOM_MSG_TYPE_TEMCAL; + custom_message_state = 1; + lcd_setstatuspgm(_T(MSG_TEMP_CALIBRATION)); + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + + while (current_temperature_pinda < start_temp) + { + delay_keep_alive(1000); + serialecho_temperatures(); + } - if (temp_comp_start) - if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { - if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) { - temp_compensation_start(); - run = true; - repeatcommand_front(); // repeat G80 with all its parameters - enquecommand_front_P((PSTR("G28 W0"))); - } - else { - mesh_bed_leveling_flag = false; - } - break; - } - run = false; - if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) { - mesh_bed_leveling_flag = false; - break; - } - // Save custom message state, set a new custom message state to display: Calibrating point 9. - unsigned int custom_message_type_old = custom_message_type; - unsigned int custom_message_state_old = custom_message_state; - custom_message_type = CUSTOM_MSG_TYPE_MESHBL; - custom_message_state = (MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) + 10; - lcd_update(1); - - mbl.reset(); //reset mesh bed leveling - - // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be - // consumed during the first movements following this statement. - babystep_undo(); - - // Cycle through all points and probe them - // First move up. During this first movement, the babystepping will be reverted. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - 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); - // The move to the first calibration point. - current_position[X_AXIS] = pgm_read_float(bed_ref_points); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); - - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 1) - { - bool clamped = world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - clamped ? SERIAL_PROTOCOLPGM("First calibration point clamped.\n") : SERIAL_PROTOCOLPGM("No clamping for first calibration point.\n"); - } - #endif //SUPPORT_VERBOSITY - // mbl.get_meas_xy(0, 0, current_position[X_AXIS], current_position[Y_AXIS], false); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[X_AXIS] / 30, active_extruder); - // Wait until the move is finished. - st_synchronize(); + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); //invalidate temp. calibration in case that in will be aborted during the calibration process - int mesh_point = 0; //index number of calibration point - - int ix = 0; - int iy = 0; - - int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20; - int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40; - bool has_z = is_bed_z_jitter_data_valid(); //checks if we have data from Z calibration (offsets of the Z heiths of the 8 calibration points from the first point) - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 1) { - has_z ? SERIAL_PROTOCOLPGM("Z jitter data from Z cal. valid.\n") : SERIAL_PROTOCOLPGM("Z jitter data from Z cal. not valid.\n"); - } - #endif // SUPPORT_VERBOSITY - int l_feedmultiply = setup_for_endstop_move(false); //save feedrate and feedmultiply, sets feedmultiply to 100 - const char *kill_message = NULL; - while (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { - // Get coords of a measuring point. - ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1 - iy = mesh_point / MESH_MEAS_NUM_X_POINTS; - if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag - float z0 = 0.f; - if (has_z && mesh_point > 0) { - uint16_t z_offset_u = eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + 2 * (ix + iy * 3 - 1))); - z0 = mbl.z_values[0][0] + *reinterpret_cast(&z_offset_u) * 0.01; - //#if 0 - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 1) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("Bed leveling, point: "); - MYSERIAL.print(mesh_point); - SERIAL_ECHOPGM(", calibration z: "); - MYSERIAL.print(z0, 5); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY - //#endif - } - - // Move Z up to MESH_HOME_Z_SEARCH. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); - st_synchronize(); - - // Move to XY position of the sensor point. - current_position[X_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point + 1); - - - - world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 1) { - - SERIAL_PROTOCOL(mesh_point); - clamped ? SERIAL_PROTOCOLPGM(": xy clamped.\n") : SERIAL_PROTOCOLPGM(": no xy clamping\n"); - } - #endif // SUPPORT_VERBOSITY - - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder); - st_synchronize(); - - // Go down until endstop is hit - const float Z_CALIBRATION_THRESHOLD = 1.f; - if (!find_bed_induction_sensor_point_z((has_z && mesh_point > 0) ? z0 - Z_CALIBRATION_THRESHOLD : -10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point - kill_message = _T(MSG_BED_LEVELING_FAILED_POINT_LOW); - break; - } - if (MESH_HOME_Z_SEARCH - current_position[Z_AXIS] < 0.1f) { - kill_message = _i("Bed leveling failed. Sensor disconnected or cable broken. Waiting for reset.");////MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED c=20 r=4 - break; - } - if (has_z && fabs(z0 - current_position[Z_AXIS]) > Z_CALIBRATION_THRESHOLD) { //if we have data from z calibration, max. allowed difference is 1mm for each point - kill_message = _i("Bed leveling failed. Sensor triggered too high. Waiting for reset.");////MSG_BED_LEVELING_FAILED_POINT_HIGH c=20 r=4 - break; - } - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) { - SERIAL_ECHOPGM("X: "); - MYSERIAL.print(current_position[X_AXIS], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("Y: "); - MYSERIAL.print(current_position[Y_AXIS], 5); - SERIAL_PROTOCOLPGM("\n"); - } - #endif // SUPPORT_VERBOSITY - float offset_z = 0; + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[X_AXIS] = pgm_read_float(bed_ref_points_4); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + 1); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); -#ifdef PINDA_THERMISTOR - offset_z = temp_compensation_pinda_thermistor_offset(current_temperature_pinda); -#endif //PINDA_THERMISTOR -// #ifdef SUPPORT_VERBOSITY -/* if (verbosity_level >= 1) - { - SERIAL_ECHOPGM("mesh bed leveling: "); - MYSERIAL.print(current_position[Z_AXIS], 5); - SERIAL_ECHOPGM(" offset: "); - MYSERIAL.print(offset_z, 5); - SERIAL_ECHOLNPGM(""); - }*/ -// #endif // SUPPORT_VERBOSITY - mbl.set_z(ix, iy, current_position[Z_AXIS] - offset_z); //store measured z values z_values[iy][ix] = z - offset_z; - - custom_message_state--; - mesh_point++; - lcd_update(1); - } - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM("Mesh bed leveling while loop finished."); - SERIAL_ECHOLNPGM("MESH_HOME_Z_SEARCH: "); - MYSERIAL.print(current_position[Z_AXIS], 5); - } - #endif // SUPPORT_VERBOSITY - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); - st_synchronize(); - if (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { - Sound_MakeSound(e_SOUND_TYPE_StandardAlert); - bool bState; - do { // repeat until Z-leveling o.k. - lcd_display_message_fullscreen_P(_i("Some problem encountered, Z-levelling enforced ...")); + bool find_z_result = find_bed_induction_sensor_point_z(-1.f); + if (find_z_result == false) { + lcd_temp_cal_show_result(find_z_result); + break; + } + zero_z = current_position[Z_AXIS]; + + printf_P(_N("\nZERO: %.3f\n"), current_position[Z_AXIS]); + + int i = -1; + for (; i < 5; i++) + { + float temp = (40 + i * 5); + printf_P(_N("\nStep: %d/6 (skipped)\nPINDA temperature: %d Z shift (mm):0\n"), i + 2, (40 + i*5)); + if (i >= 0) EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); + if (start_temp <= temp) break; + } + + for (i++; i < 5; i++) + { + float temp = (40 + i * 5); + printf_P(_N("\nStep: %d/6\n"), i + 2); + custom_message_state = i + 2; + setTargetBed(50 + 10 * (temp - 30) / 5); +// setTargetHotend(255, 0); + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + while (current_temperature_pinda < temp) + { + delay_keep_alive(1000); + serialecho_temperatures(); + } + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[X_AXIS] = pgm_read_float(bed_ref_points_4); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + 1); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + find_z_result = find_bed_induction_sensor_point_z(-1.f); + if (find_z_result == false) { + lcd_temp_cal_show_result(find_z_result); + break; + } + z_shift = (int)((current_position[Z_AXIS] - zero_z)*cs.axis_steps_per_unit[Z_AXIS]); + + printf_P(_N("\nPINDA temperature: %.1f Z shift (mm): %.3f"), current_temperature_pinda, current_position[Z_AXIS] - zero_z); + + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); + + } + lcd_temp_cal_show_result(true); + + break; + } +#endif //PINDA_THERMISTOR + + setTargetBed(PINDA_MIN_T); + float zero_z; + int z_shift = 0; //unit: steps + int t_c; // temperature + + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { + // We don't know where we are! HOME! + // Push the commands to the front of the message queue in the reverse order! + // There shall be always enough space reserved for these commands. + repeatcommand_front(); // repeat G76 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); + break; + } + puts_P(_N("PINDA probe calibration start")); + custom_message_type = CUSTOM_MSG_TYPE_TEMCAL; + custom_message_state = 1; + lcd_setstatuspgm(_T(MSG_TEMP_CALIBRATION)); + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + + while (abs(degBed() - PINDA_MIN_T) > 1) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + + //enquecommand_P(PSTR("M190 S50")); + for (int i = 0; i < PINDA_HEAT_T; i++) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); //invalidate temp. calibration in case that in will be aborted during the calibration process + + current_position[Z_AXIS] = 5; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + + current_position[X_AXIS] = pgm_read_float(bed_ref_points); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + + find_bed_induction_sensor_point_z(-1.f); + zero_z = current_position[Z_AXIS]; + + printf_P(_N("\nZERO: %.3f\n"), current_position[Z_AXIS]); + + for (int i = 0; i<5; i++) { + printf_P(_N("\nStep: %d/6\n"), i + 2); + custom_message_state = i + 2; + t_c = 60 + i * 10; + + setTargetBed(t_c); + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + while (degBed() < t_c) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + for (int i = 0; i < PINDA_HEAT_T; i++) { + delay_keep_alive(1000); + serialecho_temperatures(); + } + current_position[Z_AXIS] = 5; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + current_position[X_AXIS] = pgm_read_float(bed_ref_points); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + find_bed_induction_sensor_point_z(-1.f); + z_shift = (int)((current_position[Z_AXIS] - zero_z)*cs.axis_steps_per_unit[Z_AXIS]); + + printf_P(_N("\nTemperature: %d Z shift (mm): %.3f\n"), t_c, current_position[Z_AXIS] - zero_z); + + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i*2, &z_shift); + + + } + custom_message_type = CUSTOM_MSG_TYPE_STATUS; + + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); + puts_P(_N("Temperature calibration done.")); + disable_x(); + disable_y(); + disable_z(); + disable_e0(); + disable_e1(); + disable_e2(); + setTargetBed(0); //set bed target temperature back to 0 + lcd_show_fullscreen_message_and_wait_P(_T(MSG_TEMP_CALIBRATION_DONE)); + temp_cal_active = true; + eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 1); + lcd_update_enable(true); + lcd_update(2); + + + + } + break; + +#ifdef DIS + case 77: + { + //! G77 X200 Y150 XP100 YP15 XO10 Y015 + //! for 9 point mesh bed leveling G77 X203 Y196 XP3 YP3 XO0 YO0 + //! G77 X232 Y218 XP116 YP109 XO-11 YO0 + + float dimension_x = 40; + float dimension_y = 40; + int points_x = 40; + int points_y = 40; + float offset_x = 74; + float offset_y = 33; + + if (code_seen('X')) dimension_x = code_value(); + if (code_seen('Y')) dimension_y = code_value(); + if (code_seen("XP")) { + strchr_pointer+=1; + points_x = code_value(); + } + if (code_seen("YP")) { + strchr_pointer+=1; + points_y = code_value(); + } + if (code_seen("XO")) { + strchr_pointer+=1; + offset_x = code_value(); + } + if (code_seen("YO")) { + strchr_pointer+=1; + offset_y = code_value(); + } + + bed_analysis(dimension_x,dimension_y,points_x,points_y,offset_x,offset_y); + + } + break; + +#endif + + case 79: { + for (int i = 255; i > 0; i = i - 5) { + fanSpeed = i; + //delay_keep_alive(2000); + for (int j = 0; j < 100; j++) { + delay_keep_alive(100); + + } + printf_P(_N("%d: %d\n"), i, fan_speed[1]); + } + } + break; + + /** + * G80: Mesh-based Z probe, probes a grid and produces a + * mesh to compensate for variable bed height + * + * The S0 report the points as below + * @code{.unparsed} + * +----> X-axis + * | + * | + * v Y-axis + * @endcode + */ + + case 80: +#ifdef MK1BP + break; +#endif //MK1BP +case_G80: + { + mesh_bed_leveling_flag = true; + static bool run = false; + +#ifdef SUPPORT_VERBOSITY + int8_t verbosity_level = 0; + if (code_seen('V')) { + // Just 'V' without a number counts as V1. + char c = strchr_pointer[1]; + verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short(); + } +#endif //SUPPORT_VERBOSITY + // Firstly check if we know where we are + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { + // We don't know where we are! HOME! + // Push the commands to the front of the message queue in the reverse order! + // There shall be always enough space reserved for these commands. + if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) { + repeatcommand_front(); // repeat G80 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); + } + else { + mesh_bed_leveling_flag = false; + } + break; + } + + + bool temp_comp_start = true; +#ifdef PINDA_THERMISTOR + temp_comp_start = false; +#endif //PINDA_THERMISTOR + + if (temp_comp_start) + if (run == false && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { + if (lcd_commands_type != LCD_COMMAND_STOP_PRINT) { + temp_compensation_start(); + run = true; + repeatcommand_front(); // repeat G80 with all its parameters + enquecommand_front_P((PSTR("G28 W0"))); + } + else { + mesh_bed_leveling_flag = false; + } + break; + } + run = false; + if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) { + mesh_bed_leveling_flag = false; + break; + } + // Save custom message state, set a new custom message state to display: Calibrating point 9. + unsigned int custom_message_type_old = custom_message_type; + unsigned int custom_message_state_old = custom_message_state; + custom_message_type = CUSTOM_MSG_TYPE_MESHBL; + custom_message_state = (MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) + 10; + lcd_update(1); + + mbl.reset(); //reset mesh bed leveling + + // Reset baby stepping to zero, if the babystepping has already been loaded before. The babystepsTodo value will be + // consumed during the first movements following this statement. + babystep_undo(); + + // Cycle through all points and probe them + // First move up. During this first movement, the babystepping will be reverted. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + 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); + // The move to the first calibration point. + current_position[X_AXIS] = pgm_read_float(bed_ref_points); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 1); + +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 1) + { + bool clamped = world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); + clamped ? SERIAL_PROTOCOLPGM("First calibration point clamped.\n") : SERIAL_PROTOCOLPGM("No clamping for first calibration point.\n"); + } +#endif //SUPPORT_VERBOSITY + // mbl.get_meas_xy(0, 0, current_position[X_AXIS], current_position[Y_AXIS], false); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[X_AXIS] / 30, active_extruder); + // Wait until the move is finished. + st_synchronize(); + + int mesh_point = 0; //index number of calibration point + + int ix = 0; + int iy = 0; + + int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20; + int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40; + bool has_z = is_bed_z_jitter_data_valid(); //checks if we have data from Z calibration (offsets of the Z heiths of the 8 calibration points from the first point) +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 1) { + has_z ? SERIAL_PROTOCOLPGM("Z jitter data from Z cal. valid.\n") : SERIAL_PROTOCOLPGM("Z jitter data from Z cal. not valid.\n"); + } +#endif // SUPPORT_VERBOSITY + int l_feedmultiply = setup_for_endstop_move(false); //save feedrate and feedmultiply, sets feedmultiply to 100 + const char *kill_message = NULL; + while (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { + // Get coords of a measuring point. + ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1 + iy = mesh_point / MESH_MEAS_NUM_X_POINTS; + if (iy & 1) ix = (MESH_MEAS_NUM_X_POINTS - 1) - ix; // Zig zag + float z0 = 0.f; + if (has_z && mesh_point > 0) { + uint16_t z_offset_u = eeprom_read_word((uint16_t*)(EEPROM_BED_CALIBRATION_Z_JITTER + 2 * (ix + iy * 3 - 1))); + z0 = mbl.z_values[0][0] + *reinterpret_cast(&z_offset_u) * 0.01; + //#if 0 +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 1) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Bed leveling, point: "); + MYSERIAL.print(mesh_point); + SERIAL_ECHOPGM(", calibration z: "); + MYSERIAL.print(z0, 5); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY + //#endif + } + + // Move Z up to MESH_HOME_Z_SEARCH. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); + st_synchronize(); + + // Move to XY position of the sensor point. + current_position[X_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + 2 * mesh_point + 1); + + + + world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 1) { + + SERIAL_PROTOCOL(mesh_point); + clamped ? SERIAL_PROTOCOLPGM(": xy clamped.\n") : SERIAL_PROTOCOLPGM(": no xy clamping\n"); + } +#endif // SUPPORT_VERBOSITY + + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder); + st_synchronize(); + + // Go down until endstop is hit + const float Z_CALIBRATION_THRESHOLD = 1.f; + if (!find_bed_induction_sensor_point_z((has_z && mesh_point > 0) ? z0 - Z_CALIBRATION_THRESHOLD : -10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point + kill_message = _T(MSG_BED_LEVELING_FAILED_POINT_LOW); + break; + } + if (MESH_HOME_Z_SEARCH - current_position[Z_AXIS] < 0.1f) { + kill_message = _i("Bed leveling failed. Sensor disconnected or cable broken. Waiting for reset.");////MSG_BED_LEVELING_FAILED_PROBE_DISCONNECTED c=20 r=4 + break; + } + if (has_z && fabs(z0 - current_position[Z_AXIS]) > Z_CALIBRATION_THRESHOLD) { //if we have data from z calibration, max. allowed difference is 1mm for each point + kill_message = _i("Bed leveling failed. Sensor triggered too high. Waiting for reset.");////MSG_BED_LEVELING_FAILED_POINT_HIGH c=20 r=4 + break; + } +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) { + SERIAL_ECHOPGM("X: "); + MYSERIAL.print(current_position[X_AXIS], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Y: "); + MYSERIAL.print(current_position[Y_AXIS], 5); + SERIAL_PROTOCOLPGM("\n"); + } +#endif // SUPPORT_VERBOSITY + float offset_z = 0; + +#ifdef PINDA_THERMISTOR + offset_z = temp_compensation_pinda_thermistor_offset(current_temperature_pinda); +#endif //PINDA_THERMISTOR +// #ifdef SUPPORT_VERBOSITY + /* if (verbosity_level >= 1) + { + SERIAL_ECHOPGM("mesh bed leveling: "); + MYSERIAL.print(current_position[Z_AXIS], 5); + SERIAL_ECHOPGM(" offset: "); + MYSERIAL.print(offset_z, 5); + SERIAL_ECHOLNPGM(""); + }*/ +// #endif // SUPPORT_VERBOSITY + mbl.set_z(ix, iy, current_position[Z_AXIS] - offset_z); //store measured z values z_values[iy][ix] = z - offset_z; + + custom_message_state--; + mesh_point++; + lcd_update(1); + } + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("Mesh bed leveling while loop finished."); + SERIAL_ECHOLNPGM("MESH_HOME_Z_SEARCH: "); + MYSERIAL.print(current_position[Z_AXIS], 5); + } +#endif // SUPPORT_VERBOSITY + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); + st_synchronize(); + if (mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS) { + Sound_MakeSound(e_SOUND_TYPE_StandardAlert); + bool bState; + do { // repeat until Z-leveling o.k. + lcd_display_message_fullscreen_P(_i("Some problem encountered, Z-levelling enforced ...")); #ifdef TMC2130 - lcd_wait_for_click_delay(MSG_BED_LEVELING_FAILED_TIMEOUT); - calibrate_z_auto(); // Z-leveling (X-assembly stay up!!!) + lcd_wait_for_click_delay(MSG_BED_LEVELING_FAILED_TIMEOUT); + calibrate_z_auto(); // Z-leveling (X-assembly stay up!!!) #else // TMC2130 - lcd_wait_for_click_delay(0); // ~ no timeout - lcd_calibrate_z_end_stop_manual(true); // Z-leveling (X-assembly stay up!!!) + lcd_wait_for_click_delay(0); // ~ no timeout + lcd_calibrate_z_end_stop_manual(true); // Z-leveling (X-assembly stay up!!!) #endif // TMC2130 - // ~ Z-homing (can not be used "G28", because X & Y-homing would have been done before (Z-homing)) - bState=enable_z_endstop(true); - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); - st_synchronize(); - enable_z_endstop(bState); + // ~ Z-homing (can not be used "G28", because X & Y-homing would have been done before (Z-homing)) + bState=enable_z_endstop(true); + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); + st_synchronize(); + enable_z_endstop(bState); } while (st_get_position_mm(Z_AXIS) > MESH_HOME_Z_SEARCH); // i.e. Z-leveling not o.k. // plan_set_z_position(MESH_HOME_Z_SEARCH); // is not necessary ('do-while' loop always ends at the expected Z-position) - custom_message_type=CUSTOM_MSG_TYPE_STATUS; // display / status-line recovery - lcd_update_enable(true); // display / status-line recovery - gcode_G28(true, true, false); // X & Y-homing (must be after Z-homing (problem with spool-holder)!) - repeatcommand_front(); // re-run (i.e. of "G80") - break; - } - clean_up_after_endstop_move(l_feedmultiply); + custom_message_type=CUSTOM_MSG_TYPE_STATUS; // display / status-line recovery + lcd_update_enable(true); // display / status-line recovery + gcode_G28(true, true, false); // X & Y-homing (must be after Z-homing (problem with spool-holder)!) + repeatcommand_front(); // re-run (i.e. of "G80") + break; + } + clean_up_after_endstop_move(l_feedmultiply); // SERIAL_ECHOLNPGM("clean up finished "); - bool apply_temp_comp = true; + bool apply_temp_comp = true; #ifdef PINDA_THERMISTOR - apply_temp_comp = false; + apply_temp_comp = false; #endif - if (apply_temp_comp) - if(temp_cal_active == true && calibration_status_pinda() == true) temp_compensation_apply(); //apply PINDA temperature compensation - babystep_apply(); // Apply Z height correction aka baby stepping before mesh bed leveing gets activated. + if (apply_temp_comp) + if(temp_cal_active == true && calibration_status_pinda() == true) temp_compensation_apply(); //apply PINDA temperature compensation + babystep_apply(); // Apply Z height correction aka baby stepping before mesh bed leveing gets activated. // SERIAL_ECHOLNPGM("babystep applied"); - bool eeprom_bed_correction_valid = eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 1) { - eeprom_bed_correction_valid ? SERIAL_PROTOCOLPGM("Bed correction data valid\n") : SERIAL_PROTOCOLPGM("Bed correction data not valid\n"); - } - #endif // SUPPORT_VERBOSITY - - for (uint8_t i = 0; i < 4; ++i) { - unsigned char codes[4] = { 'L', 'R', 'F', 'B' }; - long correction = 0; - if (code_seen(codes[i])) - correction = code_value_long(); - else if (eeprom_bed_correction_valid) { - unsigned char *addr = (i < 2) ? - ((i == 0) ? (unsigned char*)EEPROM_BED_CORRECTION_LEFT : (unsigned char*)EEPROM_BED_CORRECTION_RIGHT) : - ((i == 2) ? (unsigned char*)EEPROM_BED_CORRECTION_FRONT : (unsigned char*)EEPROM_BED_CORRECTION_REAR); - correction = eeprom_read_int8(addr); - } - if (correction == 0) - continue; - float offset = float(correction) * 0.001f; - if (fabs(offset) > 0.101f) { - SERIAL_ERROR_START; - SERIAL_ECHOPGM("Excessive bed leveling correction: "); - SERIAL_ECHO(offset); - SERIAL_ECHOLNPGM(" microns"); - } - else { - switch (i) { - case 0: - for (uint8_t row = 0; row < 3; ++row) { - mbl.z_values[row][1] += 0.5f * offset; - mbl.z_values[row][0] += offset; - } - break; - case 1: - for (uint8_t row = 0; row < 3; ++row) { - mbl.z_values[row][1] += 0.5f * offset; - mbl.z_values[row][2] += offset; - } - break; - case 2: - for (uint8_t col = 0; col < 3; ++col) { - mbl.z_values[1][col] += 0.5f * offset; - mbl.z_values[0][col] += offset; - } - break; - case 3: - for (uint8_t col = 0; col < 3; ++col) { - mbl.z_values[1][col] += 0.5f * offset; - mbl.z_values[2][col] += offset; - } - break; - } - } - } + bool eeprom_bed_correction_valid = eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 1) { + eeprom_bed_correction_valid ? SERIAL_PROTOCOLPGM("Bed correction data valid\n") : SERIAL_PROTOCOLPGM("Bed correction data not valid\n"); + } +#endif // SUPPORT_VERBOSITY + + for (uint8_t i = 0; i < 4; ++i) { + unsigned char codes[4] = { 'L', 'R', 'F', 'B' }; + long correction = 0; + if (code_seen(codes[i])) + correction = code_value_long(); + else if (eeprom_bed_correction_valid) { + unsigned char *addr = (i < 2) ? + ((i == 0) ? (unsigned char*)EEPROM_BED_CORRECTION_LEFT : (unsigned char*)EEPROM_BED_CORRECTION_RIGHT) : + ((i == 2) ? (unsigned char*)EEPROM_BED_CORRECTION_FRONT : (unsigned char*)EEPROM_BED_CORRECTION_REAR); + correction = eeprom_read_int8(addr); + } + if (correction == 0) + continue; + float offset = float(correction) * 0.001f; + if (fabs(offset) > 0.101f) { + SERIAL_ERROR_START; + SERIAL_ECHOPGM("Excessive bed leveling correction: "); + SERIAL_ECHO(offset); + SERIAL_ECHOLNPGM(" microns"); + } + else { + switch (i) { + case 0: + for (uint8_t row = 0; row < 3; ++row) { + mbl.z_values[row][1] += 0.5f * offset; + mbl.z_values[row][0] += offset; + } + break; + case 1: + for (uint8_t row = 0; row < 3; ++row) { + mbl.z_values[row][1] += 0.5f * offset; + mbl.z_values[row][2] += offset; + } + break; + case 2: + for (uint8_t col = 0; col < 3; ++col) { + mbl.z_values[1][col] += 0.5f * offset; + mbl.z_values[0][col] += offset; + } + break; + case 3: + for (uint8_t col = 0; col < 3; ++col) { + mbl.z_values[1][col] += 0.5f * offset; + mbl.z_values[2][col] += offset; + } + break; + } + } + } // SERIAL_ECHOLNPGM("Bed leveling correction finished"); - mbl.upsample_3x3(); //bilinear interpolation from 3x3 to 7x7 points while using the same array z_values[iy][ix] for storing (just coppying measured data to new destination and interpolating between them) + mbl.upsample_3x3(); //bilinear interpolation from 3x3 to 7x7 points while using the same array z_values[iy][ix] for storing (just coppying measured data to new destination and interpolating between them) // SERIAL_ECHOLNPGM("Upsample finished"); - mbl.active = 1; //activate mesh bed leveling + mbl.active = 1; //activate mesh bed leveling // SERIAL_ECHOLNPGM("Mesh bed leveling activated"); - go_home_with_z_lift(); + go_home_with_z_lift(); // SERIAL_ECHOLNPGM("Go home finished"); - //unretract (after PINDA preheat retraction) - if (degHotend(active_extruder) > EXTRUDE_MINTEMP && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { - current_position[E_AXIS] += default_retraction; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); - } - KEEPALIVE_STATE(NOT_BUSY); - // Restore custom message state - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = custom_message_type_old; - custom_message_state = custom_message_state_old; - mesh_bed_leveling_flag = false; - mesh_bed_run_from_menu = false; - lcd_update(2); - - } - break; + //unretract (after PINDA preheat retraction) + if (degHotend(active_extruder) > EXTRUDE_MINTEMP && temp_cal_active == true && calibration_status_pinda() == true && target_temperature_bed >= 50) { + current_position[E_AXIS] += default_retraction; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); + } + KEEPALIVE_STATE(NOT_BUSY); + // Restore custom message state + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = custom_message_type_old; + custom_message_state = custom_message_state_old; + mesh_bed_leveling_flag = false; + mesh_bed_run_from_menu = false; + lcd_update(2); + + } + break; /** * G81: Print mesh bed leveling status and bed profile if activated @@ -4653,7 +4718,7 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) else SERIAL_PROTOCOLLNPGM("Mesh bed leveling not active."); break; - + #if 0 /** * G82: Single Z probe at current location @@ -4671,2418 +4736,2444 @@ if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) SERIAL_PROTOCOLPGM("\n"); break; - /** - * G83: Prusa3D specific: Babystep in Z and store to EEPROM - */ + /** + * G83: Prusa3D specific: Babystep in Z and store to EEPROM + */ case 83: { int babystepz = code_seen('S') ? code_value() : 0; int BabyPosition = code_seen('P') ? code_value() : 0; - + if (babystepz != 0) { //FIXME Vojtech: What shall be the index of the axis Z: 3 or 4? // Is the axis indexed starting with zero or one? if (BabyPosition > 4) { SERIAL_PROTOCOLLNPGM("Index out of bounds"); - }else{ + } else { // Save it to the eeprom babystepLoadZ = babystepz; EEPROM_save_B(EEPROM_BABYSTEP_Z0+(BabyPosition*2),&babystepLoadZ); // adjust the Z babystepsTodoZadd(babystepLoadZ); } - + } - + } break; - /** - * G84: Prusa3D specific: UNDO Babystep Z (move Z axis back) - */ + /** + * G84: Prusa3D specific: UNDO Babystep Z (move Z axis back) + */ case 84: babystepsTodoZsubtract(babystepLoadZ); // babystepLoadZ = 0; break; - - /** - * G85: Prusa3D specific: Pick best babystep - */ + + /** + * G85: Prusa3D specific: Pick best babystep + */ case 85: lcd_pick_babystep(); break; #endif - - /** - * G86: Prusa3D specific: Disable babystep correction after home. - * This G-code will be performed at the start of a calibration script. - */ + + /** + * G86: Prusa3D specific: Disable babystep correction after home. + * This G-code will be performed at the start of a calibration script. + */ case 86: calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST); break; - /** - * G87: Prusa3D specific: Enable babystep correction after home - * This G-code will be performed at the end of a calibration script. - */ + /** + * G87: Prusa3D specific: Enable babystep correction after home + * This G-code will be performed at the end of a calibration script. + */ case 87: - calibration_status_store(CALIBRATION_STATUS_CALIBRATED); + calibration_status_store(CALIBRATION_STATUS_CALIBRATED); break; - /** - * G88: Prusa3D specific: Don't know what it is for, it is in V2Calibration.gcode - */ - case 88: - break; + /** + * G88: Prusa3D specific: Don't know what it is for, it is in V2Calibration.gcode + */ + case 88: + break; #endif // ENABLE_MESH_BED_LEVELING - - - case 90: // G90 - relative_mode = false; - break; - case 91: // G91 - relative_mode = true; - break; - case 92: // G92 - if(!code_seen(axis_codes[E_AXIS])) - st_synchronize(); - for(int8_t i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) { - if(i == E_AXIS) { - current_position[i] = code_value(); - plan_set_e_position(current_position[E_AXIS]); - } - else { - current_position[i] = code_value()+cs.add_homing[i]; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - } - } - } - break; - - case 98: //! G98 (activate farm mode) - farm_mode = 1; - PingTime = millis(); - eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode); - EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no); - SilentModeMenu = SILENT_MODE_OFF; - eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu); - break; - - case 99: //! G99 (deactivate farm mode) - farm_mode = 0; - lcd_printer_connected(); - eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode); - lcd_update(2); - break; - default: - printf_P(PSTR("Unknown G code: %s \n"), cmdbuffer + bufindr + CMDHDRSIZE); - } -// printf_P(_N("END G-CODE=%u\n"), gcode_in_progress); - gcode_in_progress = 0; - } // end if(code_seen('G')) - - else if(code_seen('M')) - { - - int index; - for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++); - - /*for (++strchr_pointer; *strchr_pointer == ' ' || *strchr_pointer == '\t'; ++strchr_pointer);*/ - if (*(strchr_pointer+index) < '0' || *(strchr_pointer+index) > '9') { - printf_P(PSTR("Invalid M code: %s \n"), cmdbuffer + bufindr + CMDHDRSIZE); - - } else - { - mcode_in_progress = (int)code_value(); -// printf_P(_N("BEGIN M-CODE=%u\n"), mcode_in_progress); - switch(mcode_in_progress) - { - - case 0: // M0 - Unconditional stop - Wait for user button press on LCD - case 1: // M1 - Conditional stop - Wait for user button press on LCD - { - char *src = strchr_pointer + 2; - - codenum = 0; - - bool hasP = false, hasS = false; - if (code_seen('P')) { - codenum = code_value(); // milliseconds to wait - hasP = codenum > 0; - } - if (code_seen('S')) { - codenum = code_value() * 1000; // seconds to wait - hasS = codenum > 0; - } - starpos = strchr(src, '*'); - if (starpos != NULL) *(starpos) = '\0'; - while (*src == ' ') ++src; - if (!hasP && !hasS && *src != '\0') { - lcd_setstatus(src); - } else { - LCD_MESSAGERPGM(_i("Wait for user..."));////MSG_USERWAIT c=0 r=0 - } - - lcd_ignore_click(); //call lcd_ignore_click aslo for else ??? - st_synchronize(); - previous_millis_cmd = millis(); - if (codenum > 0){ - codenum += millis(); // keep track of when we started waiting - KEEPALIVE_STATE(PAUSED_FOR_USER); - while(millis() < codenum && !lcd_clicked()){ - manage_heater(); - manage_inactivity(true); - lcd_update(0); - } - KEEPALIVE_STATE(IN_HANDLER); - lcd_ignore_click(false); - }else{ - KEEPALIVE_STATE(PAUSED_FOR_USER); - while(!lcd_clicked()){ - manage_heater(); - manage_inactivity(true); - lcd_update(0); - } - KEEPALIVE_STATE(IN_HANDLER); - } - if (IS_SD_PRINTING) - LCD_MESSAGERPGM(_T(MSG_RESUMING_PRINT)); - else - LCD_MESSAGERPGM(_T(WELCOME_MSG)); - } - break; - case 17: - LCD_MESSAGERPGM(_i("No move."));////MSG_NO_MOVE c=0 r=0 - enable_x(); - enable_y(); - enable_z(); - enable_e0(); - enable_e1(); - enable_e2(); - break; - -#ifdef SDSUPPORT - case 20: // M20 - list SD card - SERIAL_PROTOCOLLNRPGM(_N("Begin file list"));////MSG_BEGIN_FILE_LIST c=0 r=0 - card.ls(); - SERIAL_PROTOCOLLNRPGM(_N("End file list"));////MSG_END_FILE_LIST c=0 r=0 - break; - case 21: // M21 - init SD card - - card.initsd(); - - break; - case 22: //M22 - release SD card - card.release(); - - break; - case 23: //M23 - Select file - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos!=NULL) - *(starpos)='\0'; - card.openFile(strchr_pointer + 4,true); - break; - case 24: //M24 - Start SD print - if (!card.paused) - failstats_reset_print(); - card.startFileprint(); - starttime=millis(); - break; - case 25: //M25 - Pause SD print - card.pauseSDPrint(); - break; - case 26: //M26 - Set SD index - if(card.cardOK && code_seen('S')) { - card.setIndex(code_value_long()); - } - break; - case 27: //M27 - Get SD status - card.getStatus(); - break; - case 28: //M28 - Start SD write - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - char* npos = strchr(CMDBUFFER_CURRENT_STRING, 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos) = '\0'; - } - card.openFile(strchr_pointer+4,false); - break; - case 29: //M29 - Stop SD write - //processed in write to file routine above - //card,saving = false; - break; - case 30: //M30 Delete File - if (card.cardOK){ - card.closefile(); - starpos = (strchr(strchr_pointer + 4,'*')); - if(starpos != NULL){ - char* npos = strchr(CMDBUFFER_CURRENT_STRING, 'N'); - strchr_pointer = strchr(npos,' ') + 1; - *(starpos) = '\0'; - } - card.removeFile(strchr_pointer + 4); - } - break; - case 32: //M32 - Select file and start SD print - { - if(card.sdprinting) { - st_synchronize(); - } - 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)='\0'; - - 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= 0 && pin_status <= 255) - pin_number = code_value(); - for(int8_t i = 0; i < (int8_t)(sizeof(sensitive_pins)/sizeof(int)); i++) - { - if (sensitive_pins[i] == pin_number) - { - pin_number = -1; + case 99: //! G99 (deactivate farm mode) + farm_mode = 0; + lcd_printer_connected(); + eeprom_update_byte((unsigned char *)EEPROM_FARM_MODE, farm_mode); + lcd_update(2); break; - } - } - #if defined(FAN_PIN) && FAN_PIN > -1 - if (pin_number == FAN_PIN) - fanSpeed = pin_status; - #endif - if (pin_number > -1) - { - pinMode(pin_number, OUTPUT); - digitalWrite(pin_number, pin_status); - analogWrite(pin_number, pin_status); + default: + printf_P(PSTR("Unknown G code: %s \n"), cmdbuffer + bufindr + CMDHDRSIZE); } - } - break; - case 44: //! M44: Prusa3D: Reset the bed skew and offset calibration. - - // Reset the baby step value and the baby step applied flag. - calibration_status_store(CALIBRATION_STATUS_ASSEMBLED); - eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0); - - // Reset the skew and offset in both RAM and EEPROM. - reset_bed_offset_and_skew(); - // Reset world2machine_rotation_and_skew and world2machine_shift, therefore - // the planner will not perform any adjustments in the XY plane. - // Wait for the motors to stop and update the current position with the absolute values. - world2machine_revert_to_uncorrected(); - break; +// printf_P(_N("END G-CODE=%u\n"), gcode_in_progress); + gcode_in_progress = 0; + } // end if(code_seen('G')) - case 45: //! M45: Prusa3D: bed skew and offset with manual Z up + else if(code_seen('M')) { - int8_t verbosity_level = 0; - bool only_Z = code_seen('Z'); - #ifdef SUPPORT_VERBOSITY - if (code_seen('V')) - { - // Just 'V' without a number counts as V1. - char c = strchr_pointer[1]; - verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short(); - } - #endif //SUPPORT_VERBOSITY - gcode_M45(only_Z, verbosity_level); - } - break; - - /* - case 46: - { - // M46: Prusa3D: Show the assigned IP address. - uint8_t ip[4]; - bool hasIP = card.ToshibaFlashAir_GetIP(ip); - if (hasIP) { - SERIAL_ECHOPGM("Toshiba FlashAir current IP: "); - SERIAL_ECHO(int(ip[0])); - SERIAL_ECHOPGM("."); - SERIAL_ECHO(int(ip[1])); - SERIAL_ECHOPGM("."); - SERIAL_ECHO(int(ip[2])); - SERIAL_ECHOPGM("."); - SERIAL_ECHO(int(ip[3])); - SERIAL_ECHOLNPGM(""); - } else { - SERIAL_ECHOLNPGM("Toshiba FlashAir GetIP failed"); - } - break; - } - */ - - case 47: - //! M47: Prusa3D: Show end stops dialog on the display. - KEEPALIVE_STATE(PAUSED_FOR_USER); - lcd_diag_show_end_stops(); - KEEPALIVE_STATE(IN_HANDLER); - break; -#if 0 - case 48: //! M48: scan the bed induction sensor points, print the sensor trigger coordinates to the serial line for visualization on the PC. - { - // Disable the default update procedure of the display. We will do a modal dialog. - lcd_update_enable(false); - // Let the planner use the uncorrected coordinates. - mbl.reset(); - // Reset world2machine_rotation_and_skew and world2machine_shift, therefore - // the planner will not perform any adjustments in the XY plane. - // Wait for the motors to stop and update the current position with the absolute values. - world2machine_revert_to_uncorrected(); - // Move the print head close to the bed. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder); - st_synchronize(); - // Home in the XY plane. - set_destination_to_current(); - int l_feedmultiply = setup_for_endstop_move(); - home_xy(); - int8_t verbosity_level = 0; - if (code_seen('V')) { - // Just 'V' without a number counts as V1. - char c = strchr_pointer[1]; - verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short(); - } - bool success = scan_bed_induction_points(verbosity_level); - clean_up_after_endstop_move(l_feedmultiply); - // Print head up. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS] , current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder); - st_synchronize(); - lcd_update_enable(true); - break; - } -#endif + int index; + for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++); + /*for (++strchr_pointer; *strchr_pointer == ' ' || *strchr_pointer == '\t'; ++strchr_pointer);*/ + if (*(strchr_pointer+index) < '0' || *(strchr_pointer+index) > '9') { + printf_P(PSTR("Invalid M code: %s \n"), cmdbuffer + bufindr + CMDHDRSIZE); -#ifdef ENABLE_AUTO_BED_LEVELING -#ifdef Z_PROBE_REPEATABILITY_TEST - //! M48 Z-Probe repeatability measurement function. - //! - //! Usage: M48 - //! - //! This function assumes the bed has been homed. Specificaly, that a G28 command - //! as been issued prior to invoking the M48 Z-Probe repeatability measurement function. - //! Any information generated by a prior G29 Bed leveling command will be lost and need to be - //! regenerated. - //! - //! The number of samples will default to 10 if not specified. You can use upper or lower case - //! letters for any of the options EXCEPT n. n must be in lower case because Marlin uses a capital - //! N for its communication protocol and will get horribly confused if you send it a capital N. - //! - case 48: // M48 Z-Probe repeatability + } else { - #if Z_MIN_PIN == -1 - #error "You must have a Z_MIN endstop in order to enable calculation of Z-Probe repeatability." - #endif - - double sum=0.0; - double mean=0.0; - double sigma=0.0; - double sample_set[50]; - int verbose_level=1, n=0, j, n_samples = 10, n_legs=0; - double X_current, Y_current, Z_current; - double X_probe_location, Y_probe_location, Z_start_location, ext_position; - - if (code_seen('V') || code_seen('v')) { - verbose_level = code_value(); - if (verbose_level<0 || verbose_level>4 ) { - SERIAL_PROTOCOLPGM("?Verbose Level not plausable.\n"); - goto Sigma_Exit; - } - } + mcode_in_progress = (int)code_value(); +// printf_P(_N("BEGIN M-CODE=%u\n"), mcode_in_progress); - if (verbose_level > 0) { - SERIAL_PROTOCOLPGM("M48 Z-Probe Repeatability test. Version 2.00\n"); - SERIAL_PROTOCOLPGM("Full support at: http://3dprintboard.com/forum.php\n"); - } + switch(mcode_in_progress) + { - if (code_seen('n')) { - n_samples = code_value(); - if (n_samples<4 || n_samples>50 ) { - SERIAL_PROTOCOLPGM("?Specified sample size not plausable.\n"); - goto Sigma_Exit; - } - } + case 0: // M0 - Unconditional stop - Wait for user button press on LCD + case 1: // M1 - Conditional stop - Wait for user button press on LCD + { + char *src = strchr_pointer + 2; - X_current = X_probe_location = st_get_position_mm(X_AXIS); - Y_current = Y_probe_location = st_get_position_mm(Y_AXIS); - Z_current = st_get_position_mm(Z_AXIS); - Z_start_location = st_get_position_mm(Z_AXIS) + Z_RAISE_BEFORE_PROBING; - ext_position = st_get_position_mm(E_AXIS); - - if (code_seen('X') || code_seen('x') ) { - X_probe_location = code_value() - X_PROBE_OFFSET_FROM_EXTRUDER; - if (X_probe_locationX_MAX_POS ) { - SERIAL_PROTOCOLPGM("?Specified X position out of range.\n"); - goto Sigma_Exit; - } - } + codenum = 0; - if (code_seen('Y') || code_seen('y') ) { - Y_probe_location = code_value() - Y_PROBE_OFFSET_FROM_EXTRUDER; - if (Y_probe_locationY_MAX_POS ) { - SERIAL_PROTOCOLPGM("?Specified Y position out of range.\n"); - goto Sigma_Exit; - } - } + bool hasP = false, hasS = false; + if (code_seen('P')) { + codenum = code_value(); // milliseconds to wait + hasP = codenum > 0; + } + if (code_seen('S')) { + codenum = code_value() * 1000; // seconds to wait + hasS = codenum > 0; + } + starpos = strchr(src, '*'); + if (starpos != NULL) *(starpos) = '\0'; + while (*src == ' ') ++src; + if (!hasP && !hasS && *src != '\0') { + lcd_setstatus(src); + } else { + LCD_MESSAGERPGM(_i("Wait for user..."));////MSG_USERWAIT c=0 r=0 + } - if (code_seen('L') || code_seen('l') ) { - n_legs = code_value(); - if ( n_legs==1 ) - n_legs = 2; - if ( n_legs<0 || n_legs>15 ) { - SERIAL_PROTOCOLPGM("?Specified number of legs in movement not plausable.\n"); - goto Sigma_Exit; - } - } + lcd_ignore_click(); //call lcd_ignore_click aslo for else ??? + st_synchronize(); + previous_millis_cmd = millis(); + if (codenum > 0) { + codenum += millis(); // keep track of when we started waiting + KEEPALIVE_STATE(PAUSED_FOR_USER); + while(millis() < codenum && !lcd_clicked()) { + manage_heater(); + manage_inactivity(true); + lcd_update(0); + } + KEEPALIVE_STATE(IN_HANDLER); + lcd_ignore_click(false); + } else { + KEEPALIVE_STATE(PAUSED_FOR_USER); + while(!lcd_clicked()) { + manage_heater(); + manage_inactivity(true); + lcd_update(0); + } + KEEPALIVE_STATE(IN_HANDLER); + } + if (IS_SD_PRINTING) + LCD_MESSAGERPGM(_T(MSG_RESUMING_PRINT)); + else + LCD_MESSAGERPGM(_T(WELCOME_MSG)); + } + break; + case 17: + LCD_MESSAGERPGM(_i("No move."));////MSG_NO_MOVE c=0 r=0 + enable_x(); + enable_y(); + enable_z(); + enable_e0(); + enable_e1(); + enable_e2(); + break; -// -// Do all the preliminary setup work. First raise the probe. -// +#ifdef SDSUPPORT + case 20: // M20 - list SD card + SERIAL_PROTOCOLLNRPGM(_N("Begin file list"));////MSG_BEGIN_FILE_LIST c=0 r=0 + card.ls(); + SERIAL_PROTOCOLLNRPGM(_N("End file list"));////MSG_END_FILE_LIST c=0 r=0 + break; + case 21: // M21 - init SD card - st_synchronize(); - plan_bed_level_matrix.set_to_identity(); - plan_buffer_line( X_current, Y_current, Z_start_location, - ext_position, - homing_feedrate[Z_AXIS]/60, - active_extruder); - st_synchronize(); + card.initsd(); -// + break; + case 22: //M22 - release SD card + card.release(); + + break; + case 23: //M23 - Select file + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos!=NULL) + *(starpos)='\0'; + card.openFile(strchr_pointer + 4,true); + break; + case 24: //M24 - Start SD print + if (!card.paused) + failstats_reset_print(); + card.startFileprint(); + starttime=millis(); + break; + case 25: //M25 - Pause SD print + card.pauseSDPrint(); + break; + case 26: //M26 - Set SD index + if(card.cardOK && code_seen('S')) { + card.setIndex(code_value_long()); + } + break; + case 27: //M27 - Get SD status + card.getStatus(); + break; + case 28: //M28 - Start SD write + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL) { + char* npos = strchr(CMDBUFFER_CURRENT_STRING, 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos) = '\0'; + } + card.openFile(strchr_pointer+4,false); + break; + case 29: //M29 - Stop SD write + //processed in write to file routine above + //card,saving = false; + break; + case 30: //M30 Delete File + if (card.cardOK) { + card.closefile(); + starpos = (strchr(strchr_pointer + 4,'*')); + if(starpos != NULL) { + char* npos = strchr(CMDBUFFER_CURRENT_STRING, 'N'); + strchr_pointer = strchr(npos,' ') + 1; + *(starpos) = '\0'; + } + card.removeFile(strchr_pointer + 4); + } + break; + case 32: //M32 - Select file and start SD print + { + if(card.sdprinting) { + st_synchronize(); + + } + 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)='\0'; + + 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= 0 && pin_status <= 255) + pin_number = code_value(); + for(int8_t i = 0; i < (int8_t)(sizeof(sensitive_pins)/sizeof(int)); i++) + { + if (sensitive_pins[i] == pin_number) + { + pin_number = -1; + break; + } + } +#if defined(FAN_PIN) && FAN_PIN > -1 + if (pin_number == FAN_PIN) + fanSpeed = pin_status; +#endif + if (pin_number > -1) + { + pinMode(pin_number, OUTPUT); + digitalWrite(pin_number, pin_status); + analogWrite(pin_number, pin_status); + } + } + break; + case 44: //! M44: Prusa3D: Reset the bed skew and offset calibration. + + // Reset the baby step value and the baby step applied flag. + calibration_status_store(CALIBRATION_STATUS_ASSEMBLED); + eeprom_update_word((uint16_t*)EEPROM_BABYSTEP_Z, 0); + + // Reset the skew and offset in both RAM and EEPROM. + reset_bed_offset_and_skew(); + // Reset world2machine_rotation_and_skew and world2machine_shift, therefore + // the planner will not perform any adjustments in the XY plane. + // Wait for the motors to stop and update the current position with the absolute values. + world2machine_revert_to_uncorrected(); + break; + + case 45: //! M45: Prusa3D: bed skew and offset with manual Z up + { + int8_t verbosity_level = 0; + bool only_Z = code_seen('Z'); +#ifdef SUPPORT_VERBOSITY + if (code_seen('V')) + { + // Just 'V' without a number counts as V1. + char c = strchr_pointer[1]; + verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short(); + } +#endif //SUPPORT_VERBOSITY + gcode_M45(only_Z, verbosity_level); + } + break; + + /* + case 46: + { + // M46: Prusa3D: Show the assigned IP address. + uint8_t ip[4]; + bool hasIP = card.ToshibaFlashAir_GetIP(ip); + if (hasIP) { + SERIAL_ECHOPGM("Toshiba FlashAir current IP: "); + SERIAL_ECHO(int(ip[0])); + SERIAL_ECHOPGM("."); + SERIAL_ECHO(int(ip[1])); + SERIAL_ECHOPGM("."); + SERIAL_ECHO(int(ip[2])); + SERIAL_ECHOPGM("."); + SERIAL_ECHO(int(ip[3])); + SERIAL_ECHOLNPGM(""); + } else { + SERIAL_ECHOLNPGM("Toshiba FlashAir GetIP failed"); + } + break; + } + */ + + case 47: + //! M47: Prusa3D: Show end stops dialog on the display. + KEEPALIVE_STATE(PAUSED_FOR_USER); + lcd_diag_show_end_stops(); + KEEPALIVE_STATE(IN_HANDLER); + break; + +#if 0 + case 48: //! M48: scan the bed induction sensor points, print the sensor trigger coordinates to the serial line for visualization on the PC. + { + // Disable the default update procedure of the display. We will do a modal dialog. + lcd_update_enable(false); + // Let the planner use the uncorrected coordinates. + mbl.reset(); + // Reset world2machine_rotation_and_skew and world2machine_shift, therefore + // the planner will not perform any adjustments in the XY plane. + // Wait for the motors to stop and update the current position with the absolute values. + world2machine_revert_to_uncorrected(); + // Move the print head close to the bed. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder); + st_synchronize(); + // Home in the XY plane. + set_destination_to_current(); + int l_feedmultiply = setup_for_endstop_move(); + home_xy(); + int8_t verbosity_level = 0; + if (code_seen('V')) { + // Just 'V' without a number counts as V1. + char c = strchr_pointer[1]; + verbosity_level = (c == ' ' || c == '\t' || c == 0) ? 1 : code_value_short(); + } + bool success = scan_bed_induction_points(verbosity_level); + clean_up_after_endstop_move(l_feedmultiply); + // Print head up. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS],current_position[Z_AXIS], current_position[E_AXIS], homing_feedrate[Z_AXIS]/40, active_extruder); + st_synchronize(); + lcd_update_enable(true); + break; + } +#endif + + +#ifdef ENABLE_AUTO_BED_LEVELING +#ifdef Z_PROBE_REPEATABILITY_TEST + //! M48 Z-Probe repeatability measurement function. + //! + //! Usage: M48 + //! + //! This function assumes the bed has been homed. Specificaly, that a G28 command + //! as been issued prior to invoking the M48 Z-Probe repeatability measurement function. + //! Any information generated by a prior G29 Bed leveling command will be lost and need to be + //! regenerated. + //! + //! The number of samples will default to 10 if not specified. You can use upper or lower case + //! letters for any of the options EXCEPT n. n must be in lower case because Marlin uses a capital + //! N for its communication protocol and will get horribly confused if you send it a capital N. + //! + case 48: // M48 Z-Probe repeatability + { +#if Z_MIN_PIN == -1 +#error "You must have a Z_MIN endstop in order to enable calculation of Z-Probe repeatability." +#endif + + double sum=0.0; + double mean=0.0; + double sigma=0.0; + double sample_set[50]; + int verbose_level=1, n=0, j, n_samples = 10, n_legs=0; + double X_current, Y_current, Z_current; + double X_probe_location, Y_probe_location, Z_start_location, ext_position; + + if (code_seen('V') || code_seen('v')) { + verbose_level = code_value(); + if (verbose_level<0 || verbose_level>4 ) { + SERIAL_PROTOCOLPGM("?Verbose Level not plausable.\n"); + goto Sigma_Exit; + } + } + + if (verbose_level > 0) { + SERIAL_PROTOCOLPGM("M48 Z-Probe Repeatability test. Version 2.00\n"); + SERIAL_PROTOCOLPGM("Full support at: http://3dprintboard.com/forum.php\n"); + } + + if (code_seen('n')) { + n_samples = code_value(); + if (n_samples<4 || n_samples>50 ) { + SERIAL_PROTOCOLPGM("?Specified sample size not plausable.\n"); + goto Sigma_Exit; + } + } + + X_current = X_probe_location = st_get_position_mm(X_AXIS); + Y_current = Y_probe_location = st_get_position_mm(Y_AXIS); + Z_current = st_get_position_mm(Z_AXIS); + Z_start_location = st_get_position_mm(Z_AXIS) + Z_RAISE_BEFORE_PROBING; + ext_position = st_get_position_mm(E_AXIS); + + if (code_seen('X') || code_seen('x') ) { + X_probe_location = code_value() - X_PROBE_OFFSET_FROM_EXTRUDER; + if (X_probe_locationX_MAX_POS ) { + SERIAL_PROTOCOLPGM("?Specified X position out of range.\n"); + goto Sigma_Exit; + } + } + + if (code_seen('Y') || code_seen('y') ) { + Y_probe_location = code_value() - Y_PROBE_OFFSET_FROM_EXTRUDER; + if (Y_probe_locationY_MAX_POS ) { + SERIAL_PROTOCOLPGM("?Specified Y position out of range.\n"); + goto Sigma_Exit; + } + } + + if (code_seen('L') || code_seen('l') ) { + n_legs = code_value(); + if ( n_legs==1 ) + n_legs = 2; + if ( n_legs<0 || n_legs>15 ) { + SERIAL_PROTOCOLPGM("?Specified number of legs in movement not plausable.\n"); + goto Sigma_Exit; + } + } + +// +// Do all the preliminary setup work. First raise the probe. +// + + st_synchronize(); + plan_bed_level_matrix.set_to_identity(); + plan_buffer_line( X_current, Y_current, Z_start_location, + ext_position, + homing_feedrate[Z_AXIS]/60, + active_extruder); + st_synchronize(); + +// // Now get everything to the specified probe point So we can safely do a probe to -// get us close to the bed. If the Z-Axis is far from the bed, we don't want to +// get us close to the bed. If the Z-Axis is far from the bed, we don't want to // use that as a starting point for each probe. // - if (verbose_level > 2) - SERIAL_PROTOCOL("Positioning probe for the test.\n"); + if (verbose_level > 2) + SERIAL_PROTOCOL("Positioning probe for the test.\n"); - plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location, - ext_position, - homing_feedrate[X_AXIS]/60, - active_extruder); - st_synchronize(); + plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location, + ext_position, + homing_feedrate[X_AXIS]/60, + active_extruder); + st_synchronize(); - current_position[X_AXIS] = X_current = st_get_position_mm(X_AXIS); - current_position[Y_AXIS] = Y_current = st_get_position_mm(Y_AXIS); - current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS); - current_position[E_AXIS] = ext_position = st_get_position_mm(E_AXIS); + current_position[X_AXIS] = X_current = st_get_position_mm(X_AXIS); + current_position[Y_AXIS] = Y_current = st_get_position_mm(Y_AXIS); + current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS); + current_position[E_AXIS] = ext_position = st_get_position_mm(E_AXIS); -// +// // OK, do the inital probe to get us close to the bed. // Then retrace the right amount and use that in subsequent probes // - int l_feedmultiply = setup_for_endstop_move(); - run_z_probe(); + int l_feedmultiply = setup_for_endstop_move(); + run_z_probe(); - current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS); - Z_start_location = st_get_position_mm(Z_AXIS) + Z_RAISE_BEFORE_PROBING; + current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS); + Z_start_location = st_get_position_mm(Z_AXIS) + Z_RAISE_BEFORE_PROBING; - plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location, - ext_position, - homing_feedrate[X_AXIS]/60, - active_extruder); - st_synchronize(); - current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS); + plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location, + ext_position, + homing_feedrate[X_AXIS]/60, + active_extruder); + st_synchronize(); + current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS); - for( n=0; nX_MAX_POS) - X_current = X_MAX_POS; - - if ( Y_currentY_MAX_POS) - Y_current = Y_MAX_POS; - - if (verbose_level>3 ) { - SERIAL_ECHOPAIR("x: ", X_current); - SERIAL_ECHOPAIR("y: ", Y_current); - SERIAL_PROTOCOLLNPGM(""); - } - - do_blocking_move_to( X_current, Y_current, Z_current ); - } - do_blocking_move_to( X_probe_location, Y_probe_location, Z_start_location); // Go back to the probe location - } - - int l_feedmultiply = setup_for_endstop_move(); - run_z_probe(); + for( l=0; lX_MAX_POS) + X_current = X_MAX_POS; + + if ( Y_currentY_MAX_POS) + Y_current = Y_MAX_POS; + + if (verbose_level>3 ) { + SERIAL_ECHOPAIR("x: ", X_current); + SERIAL_ECHOPAIR("y: ", Y_current); + SERIAL_PROTOCOLLNPGM(""); + } - sample_set[n] = current_position[Z_AXIS]; + do_blocking_move_to( X_current, Y_current, Z_current ); + } + do_blocking_move_to( X_probe_location, Y_probe_location, Z_start_location); // Go back to the probe location + } + + int l_feedmultiply = setup_for_endstop_move(); + run_z_probe(); + + sample_set[n] = current_position[Z_AXIS]; // // Get the current mean for the data points we have so far // - sum=0.0; - for( j=0; j<=n; j++) { - sum = sum + sample_set[j]; - } - mean = sum / (double (n+1)); + sum=0.0; + for( j=0; j<=n; j++) { + sum = sum + sample_set[j]; + } + mean = sum / (double (n+1)); // // Now, use that mean to calculate the standard deviation for the // data points we have so far // - sum=0.0; - for( j=0; j<=n; j++) { - sum = sum + (sample_set[j]-mean) * (sample_set[j]-mean); - } - sigma = sqrt( sum / (double (n+1)) ); - - if (verbose_level > 1) { - SERIAL_PROTOCOL(n+1); - SERIAL_PROTOCOL(" of "); - SERIAL_PROTOCOL(n_samples); - SERIAL_PROTOCOLPGM(" z: "); - SERIAL_PROTOCOL_F(current_position[Z_AXIS], 6); - } + sum=0.0; + for( j=0; j<=n; j++) { + sum = sum + (sample_set[j]-mean) * (sample_set[j]-mean); + } + sigma = sqrt( sum / (double (n+1)) ); + + if (verbose_level > 1) { + SERIAL_PROTOCOL(n+1); + SERIAL_PROTOCOL(" of "); + SERIAL_PROTOCOL(n_samples); + SERIAL_PROTOCOLPGM(" z: "); + SERIAL_PROTOCOL_F(current_position[Z_AXIS], 6); + } - if (verbose_level > 2) { - SERIAL_PROTOCOL(" mean: "); - SERIAL_PROTOCOL_F(mean,6); + if (verbose_level > 2) { + SERIAL_PROTOCOL(" mean: "); + SERIAL_PROTOCOL_F(mean,6); - SERIAL_PROTOCOL(" sigma: "); - SERIAL_PROTOCOL_F(sigma,6); - } + SERIAL_PROTOCOL(" sigma: "); + SERIAL_PROTOCOL_F(sigma,6); + } - if (verbose_level > 0) - SERIAL_PROTOCOLPGM("\n"); + if (verbose_level > 0) + SERIAL_PROTOCOLPGM("\n"); - plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location, - current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder); - st_synchronize(); + plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location, + current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder); + st_synchronize(); - } + } - delay(1000); + delay(1000); - clean_up_after_endstop_move(l_feedmultiply); + clean_up_after_endstop_move(l_feedmultiply); // enable_endstops(true); - if (verbose_level > 0) { - SERIAL_PROTOCOLPGM("Mean: "); - SERIAL_PROTOCOL_F(mean, 6); - SERIAL_PROTOCOLPGM("\n"); - } + if (verbose_level > 0) { + SERIAL_PROTOCOLPGM("Mean: "); + SERIAL_PROTOCOL_F(mean, 6); + SERIAL_PROTOCOLPGM("\n"); + } -SERIAL_PROTOCOLPGM("Standard Deviation: "); -SERIAL_PROTOCOL_F(sigma, 6); -SERIAL_PROTOCOLPGM("\n\n"); + SERIAL_PROTOCOLPGM("Standard Deviation: "); + SERIAL_PROTOCOL_F(sigma, 6); + SERIAL_PROTOCOLPGM("\n\n"); Sigma_Exit: - break; - } + break; + } #endif // Z_PROBE_REPEATABILITY_TEST #endif // ENABLE_AUTO_BED_LEVELING - case 73: //M73 show percent done and time remaining - if(code_seen('P')) print_percent_done_normal = code_value(); - if(code_seen('R')) print_time_remaining_normal = code_value(); - if(code_seen('Q')) print_percent_done_silent = code_value(); - if(code_seen('S')) print_time_remaining_silent = code_value(); - - { - const char* _msg_mode_done_remain = _N("%S MODE: Percent done: %d; print time remaining in mins: %d\n"); - printf_P(_msg_mode_done_remain, _N("NORMAL"), int(print_percent_done_normal), print_time_remaining_normal); - printf_P(_msg_mode_done_remain, _N("SILENT"), int(print_percent_done_silent), print_time_remaining_silent); - } - break; - - case 104: // M104 - { - uint8_t extruder; - if(setTargetedHotend(104,extruder)){ - break; - } - if (code_seen('S')) - { - setTargetHotendSafe(code_value(), extruder); - } - setWatch(); - break; - } - case 112: // M112 -Emergency Stop - kill(_n(""), 3); - break; - case 140: // M140 set bed temp - if (code_seen('S')) setTargetBed(code_value()); - break; - case 105 : // M105 - { - uint8_t extruder; - if(setTargetedHotend(105, extruder)){ - break; - } - #if defined(TEMP_0_PIN) && TEMP_0_PIN > -1 - SERIAL_PROTOCOLPGM("ok T:"); - SERIAL_PROTOCOL_F(degHotend(extruder),1); - SERIAL_PROTOCOLPGM(" /"); - SERIAL_PROTOCOL_F(degTargetHotend(extruder),1); - #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 - SERIAL_PROTOCOLPGM(" B:"); - SERIAL_PROTOCOL_F(degBed(),1); - SERIAL_PROTOCOLPGM(" /"); - SERIAL_PROTOCOL_F(degTargetBed(),1); - #endif //TEMP_BED_PIN - 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); - } - #else - SERIAL_ERROR_START; - SERIAL_ERRORLNRPGM(_i("No thermistors - no temperature"));////MSG_ERR_NO_THERMISTORS c=0 r=0 - #endif - - SERIAL_PROTOCOLPGM(" @:"); - #ifdef EXTRUDER_WATTS - SERIAL_PROTOCOL((EXTRUDER_WATTS * getHeaterPower(tmp_extruder))/127); - SERIAL_PROTOCOLPGM("W"); - #else - SERIAL_PROTOCOL(getHeaterPower(extruder)); - #endif - - SERIAL_PROTOCOLPGM(" B@:"); - #ifdef BED_WATTS - SERIAL_PROTOCOL((BED_WATTS * getHeaterPower(-1))/127); - SERIAL_PROTOCOLPGM("W"); - #else - SERIAL_PROTOCOL(getHeaterPower(-1)); - #endif + case 73: //M73 show percent done and time remaining + if(code_seen('P')) print_percent_done_normal = code_value(); + if(code_seen('R')) print_time_remaining_normal = code_value(); + if(code_seen('Q')) print_percent_done_silent = code_value(); + if(code_seen('S')) print_time_remaining_silent = code_value(); + + { + const char* _msg_mode_done_remain = _N("%S MODE: Percent done: %d; print time remaining in mins: %d\n"); + printf_P(_msg_mode_done_remain, _N("NORMAL"), int(print_percent_done_normal), print_time_remaining_normal); + printf_P(_msg_mode_done_remain, _N("SILENT"), int(print_percent_done_silent), print_time_remaining_silent); + } + break; + + case 104: // M104 + { + uint8_t extruder; + if(setTargetedHotend(104,extruder)) { + break; + } + if (code_seen('S')) + { + setTargetHotendSafe(code_value(), extruder); + } + setWatch(); + break; + } + case 112: // M112 -Emergency Stop + kill(_n(""), 3); + break; + case 140: // M140 set bed temp + if (code_seen('S')) setTargetBed(code_value()); + break; + case 105 : // M105 + { + uint8_t extruder; + if(setTargetedHotend(105, extruder)) { + break; + } +#if defined(TEMP_0_PIN) && TEMP_0_PIN > -1 + SERIAL_PROTOCOLPGM("ok T:"); + SERIAL_PROTOCOL_F(degHotend(extruder),1); + SERIAL_PROTOCOLPGM(" /"); + SERIAL_PROTOCOL_F(degTargetHotend(extruder),1); +#if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 + SERIAL_PROTOCOLPGM(" B:"); + SERIAL_PROTOCOL_F(degBed(),1); + SERIAL_PROTOCOLPGM(" /"); + SERIAL_PROTOCOL_F(degTargetBed(),1); +#endif //TEMP_BED_PIN + 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); + } +#else + SERIAL_ERROR_START; + SERIAL_ERRORLNRPGM(_i("No thermistors - no temperature"));////MSG_ERR_NO_THERMISTORS c=0 r=0 +#endif + + SERIAL_PROTOCOLPGM(" @:"); +#ifdef EXTRUDER_WATTS + SERIAL_PROTOCOL((EXTRUDER_WATTS * getHeaterPower(tmp_extruder))/127); + SERIAL_PROTOCOLPGM("W"); +#else + SERIAL_PROTOCOL(getHeaterPower(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 PINDA_THERMISTOR - SERIAL_PROTOCOLPGM(" P:"); - SERIAL_PROTOCOL_F(current_temperature_pinda,1); + SERIAL_PROTOCOLPGM(" P:"); + SERIAL_PROTOCOL_F(current_temperature_pinda,1); #endif //PINDA_THERMISTOR #ifdef AMBIENT_THERMISTOR - SERIAL_PROTOCOLPGM(" A:"); - SERIAL_PROTOCOL_F(current_temperature_ambient,1); + SERIAL_PROTOCOLPGM(" A:"); + SERIAL_PROTOCOL_F(current_temperature_ambient,1); #endif //AMBIENT_THERMISTOR - #ifdef SHOW_TEMP_ADC_VALUES - {float raw = 0.0; - - #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 - SERIAL_PROTOCOLPGM(" ADC B:"); - SERIAL_PROTOCOL_F(degBed(),1); - SERIAL_PROTOCOLPGM("C->"); - raw = rawBedTemp(); - SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5); - SERIAL_PROTOCOLPGM(" Rb->"); - SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5); - SERIAL_PROTOCOLPGM(" Rxb->"); - SERIAL_PROTOCOL_F(raw, 5); - #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->"); - raw = rawHotendTemp(cur_extruder); - SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5); - SERIAL_PROTOCOLPGM(" Rt"); - SERIAL_PROTOCOL(cur_extruder); - SERIAL_PROTOCOLPGM("->"); - SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5); - SERIAL_PROTOCOLPGM(" Rx"); - SERIAL_PROTOCOL(cur_extruder); - SERIAL_PROTOCOLPGM("->"); - SERIAL_PROTOCOL_F(raw, 5); - }} - #endif - SERIAL_PROTOCOLLN(""); - KEEPALIVE_STATE(NOT_BUSY); - return; - break; - } - case 109: - {// M109 - Wait for extruder heater to reach target. - uint8_t extruder; - if(setTargetedHotend(109, extruder)){ - break; - } - LCD_MESSAGERPGM(_T(MSG_HEATING)); - heating_status = 1; - if (farm_mode) { prusa_statistics(1); }; - -#ifdef AUTOTEMP - autotemp_enabled=false; - #endif - if (code_seen('S')) { - setTargetHotendSafe(code_value(), extruder); - CooldownNoWait = true; - } else if (code_seen('R')) { - setTargetHotendSafe(code_value(), extruder); - CooldownNoWait = false; - } - #ifdef AUTOTEMP - if (code_seen('S')) autotemp_min=code_value(); - if (code_seen('B')) autotemp_max=code_value(); - if (code_seen('F')) - { - autotemp_factor=code_value(); - autotemp_enabled=true; - } - #endif - - setWatch(); - codenum = millis(); - - /* See if we are heating up or cooling down */ - target_direction = isHeatingHotend(extruder); // true if heating, false if cooling - - KEEPALIVE_STATE(NOT_BUSY); - - cancel_heatup = false; - - wait_for_heater(codenum, extruder); //loops until target temperature is reached - - LCD_MESSAGERPGM(_T(MSG_HEATING_COMPLETE)); - KEEPALIVE_STATE(IN_HANDLER); - heating_status = 2; - if (farm_mode) { prusa_statistics(2); }; - - //starttime=millis(); - previous_millis_cmd = millis(); - } - break; - case 190: // M190 - Wait for bed heater to reach target. - #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 - LCD_MESSAGERPGM(_T(MSG_BED_HEATING)); - heating_status = 3; - if (farm_mode) { prusa_statistics(1); }; - if (code_seen('S')) - { - setTargetBed(code_value()); - CooldownNoWait = true; - } - else if (code_seen('R')) - { - setTargetBed(code_value()); - CooldownNoWait = false; - } - codenum = millis(); - - cancel_heatup = false; - target_direction = isHeatingBed(); // true if heating, false if cooling +#ifdef SHOW_TEMP_ADC_VALUES + { float raw = 0.0; - KEEPALIVE_STATE(NOT_BUSY); - while ( (target_direction)&&(!cancel_heatup) ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) ) - { - if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. - { - if (!farm_mode) { - float tt = degHotend(active_extruder); - SERIAL_PROTOCOLPGM("T:"); - SERIAL_PROTOCOL(tt); - SERIAL_PROTOCOLPGM(" E:"); - SERIAL_PROTOCOL((int)active_extruder); - SERIAL_PROTOCOLPGM(" B:"); - SERIAL_PROTOCOL_F(degBed(), 1); - SERIAL_PROTOCOLLN(""); - } - codenum = millis(); - - } - manage_heater(); - manage_inactivity(); - lcd_update(0); - } - LCD_MESSAGERPGM(_T(MSG_BED_DONE)); - KEEPALIVE_STATE(IN_HANDLER); - heating_status = 4; +#if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 + SERIAL_PROTOCOLPGM(" ADC B:"); + SERIAL_PROTOCOL_F(degBed(),1); + SERIAL_PROTOCOLPGM("C->"); + raw = rawBedTemp(); + SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5); + SERIAL_PROTOCOLPGM(" Rb->"); + SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5); + SERIAL_PROTOCOLPGM(" Rxb->"); + SERIAL_PROTOCOL_F(raw, 5); +#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->"); + raw = rawHotendTemp(cur_extruder); + SERIAL_PROTOCOL_F(raw/OVERSAMPLENR,5); + SERIAL_PROTOCOLPGM(" Rt"); + SERIAL_PROTOCOL(cur_extruder); + SERIAL_PROTOCOLPGM("->"); + SERIAL_PROTOCOL_F(100 * (1 + (PtA * (raw/OVERSAMPLENR)) + (PtB * sq((raw/OVERSAMPLENR)))), 5); + SERIAL_PROTOCOLPGM(" Rx"); + SERIAL_PROTOCOL(cur_extruder); + SERIAL_PROTOCOLPGM("->"); + SERIAL_PROTOCOL_F(raw, 5); + } + } +#endif + SERIAL_PROTOCOLLN(""); + KEEPALIVE_STATE(NOT_BUSY); + return; + break; + } + case 109: + { // M109 - Wait for extruder heater to reach target. + uint8_t extruder; + if(setTargetedHotend(109, extruder)) { + break; + } + LCD_MESSAGERPGM(_T(MSG_HEATING)); + heating_status = 1; + if (farm_mode) { + prusa_statistics(1); + }; - previous_millis_cmd = millis(); - #endif - break; +#ifdef AUTOTEMP + autotemp_enabled=false; +#endif + if (code_seen('S')) { + setTargetHotendSafe(code_value(), extruder); + CooldownNoWait = true; + } else if (code_seen('R')) { + setTargetHotendSafe(code_value(), extruder); + CooldownNoWait = false; + } +#ifdef AUTOTEMP + if (code_seen('S')) autotemp_min=code_value(); + if (code_seen('B')) autotemp_max=code_value(); + if (code_seen('F')) + { + autotemp_factor=code_value(); + autotemp_enabled=true; + } +#endif - #if defined(FAN_PIN) && FAN_PIN > -1 - case 106: //!M106 Sxxx Fan On S 0 .. 255 - if (code_seen('S')){ - fanSpeed=constrain(code_value(),0,255); - } - else { - fanSpeed=255; - } - break; - case 107: //M107 Fan Off - fanSpeed = 0; - break; - #endif //FAN_PIN - - #if defined(PS_ON_PIN) && PS_ON_PIN > -1 - 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 - - powersupply = true; - LCD_MESSAGERPGM(_T(WELCOME_MSG)); - lcd_update(0); - break; - #endif + setWatch(); + codenum = millis(); - case 81: // M81 - Turn off Power Supply - disable_heater(); - st_synchronize(); - disable_e0(); - disable_e1(); - disable_e2(); - finishAndDisableSteppers(); - fanSpeed = 0; - delay(1000); // Wait a little before to switch off - #if defined(SUICIDE_PIN) && SUICIDE_PIN > -1 - st_synchronize(); - suicide(); - #elif defined(PS_ON_PIN) && PS_ON_PIN > -1 - SET_OUTPUT(PS_ON_PIN); - WRITE(PS_ON_PIN, PS_ON_ASLEEP); - #endif - powersupply = false; - LCD_MESSAGERPGM(CAT4(CUSTOM_MENDEL_NAME,PSTR(" "),MSG_OFF,PSTR("."))); - lcd_update(0); - break; - - case 82: - axis_relative_modes[3] = false; - break; - case 83: - axis_relative_modes[3] = true; - break; - case 18: //compatibility - case 84: // M84 - if(code_seen('S')){ - stepper_inactive_time = code_value() * 1000; - } - else - { - 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(); - disable_e0(); - disable_e1(); - disable_e2(); - finishAndDisableSteppers(); - } - else - { - st_synchronize(); - if (code_seen('X')) disable_x(); - if (code_seen('Y')) disable_y(); - if (code_seen('Z')) disable_z(); -#if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS - if (code_seen('E')) { - disable_e0(); - disable_e1(); - disable_e2(); - } - #endif - } - } - //in the end of print set estimated time to end of print and extruders used during print to default values for next print - print_time_remaining_init(); - snmm_filaments_used = 0; - break; - case 85: // M85 - if(code_seen('S')) { - max_inactive_time = code_value() * 1000; - } - break; -#ifdef SAFETYTIMER - case 86: // M86 - set safety timer expiration time in seconds; M86 S0 will disable safety timer - //when safety timer expires heatbed and nozzle target temperatures are set to zero - if (code_seen('S')) { - safetytimer_inactive_time = code_value() * 1000; - safetyTimer.start(); - } - break; -#endif - case 92: // M92 - for(int8_t i=0; i < NUM_AXIS; i++) - { - if(code_seen(axis_codes[i])) - { - if(i == 3) { // E - float value = code_value(); - if(value < 20.0) { - float factor = cs.axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab. - cs.max_jerk[E_AXIS] *= factor; - max_feedrate[i] *= factor; - axis_steps_per_sqr_second[i] *= factor; - } - cs.axis_steps_per_unit[i] = value; - } - else { - cs.axis_steps_per_unit[i] = code_value(); - } - } - } - break; - case 110: //! M110 N - reset line pos - if (code_seen('N')) - gcode_LastN = code_value_long(); - break; -#ifdef HOST_KEEPALIVE_FEATURE - case 113: // M113 - Get or set Host Keepalive interval - if (code_seen('S')) { - host_keepalive_interval = (uint8_t)code_value_short(); -// NOMORE(host_keepalive_interval, 60); - } - else { - SERIAL_ECHO_START; - SERIAL_ECHOPAIR("M113 S", (unsigned long)host_keepalive_interval); - SERIAL_PROTOCOLLN(""); - } - break; -#endif - case 115: // M115 - if (code_seen('V')) { - // Report the Prusa version number. - SERIAL_PROTOCOLLNRPGM(FW_VERSION_STR_P()); - } else if (code_seen('U')) { - // Check the firmware version provided. If the firmware version provided by the U code is higher than the currently running firmware, - // pause the print and ask the user to upgrade the firmware. - show_upgrade_dialog_if_version_newer(++ strchr_pointer); - } else { - SERIAL_ECHOPGM("FIRMWARE_NAME:Prusa-Firmware "); - SERIAL_ECHORPGM(FW_VERSION_STR_P()); - SERIAL_ECHOPGM(" based on Marlin FIRMWARE_URL:https://github.com/prusa3d/Prusa-Firmware PROTOCOL_VERSION:"); - SERIAL_ECHOPGM(PROTOCOL_VERSION); - SERIAL_ECHOPGM(" MACHINE_TYPE:"); - SERIAL_ECHOPGM(CUSTOM_MENDEL_NAME); - SERIAL_ECHOPGM(" EXTRUDER_COUNT:"); - SERIAL_ECHOPGM(STRINGIFY(EXTRUDERS)); - SERIAL_ECHOPGM(" UUID:"); - SERIAL_ECHOLNPGM(MACHINE_UUID); - } - break; -/* case 117: // M117 display message - starpos = (strchr(strchr_pointer + 5,'*')); - if(starpos!=NULL) - *(starpos)='\0'; - lcd_setstatus(strchr_pointer + 5); - break;*/ - case 114: // M114 - gcode_M114(); - break; - case 120: //! M120 - Disable endstops - enable_endstops(false) ; - break; - case 121: //! M121 - Enable endstops - enable_endstops(true) ; - break; - case 119: // M119 - SERIAL_PROTOCOLRPGM(_N("Reporting endstop status"));////MSG_M119_REPORT c=0 r=0 - SERIAL_PROTOCOLLN(""); - #if defined(X_MIN_PIN) && X_MIN_PIN > -1 - SERIAL_PROTOCOLRPGM(_n("x_min: "));////MSG_X_MIN c=0 r=0 - if(READ(X_MIN_PIN)^X_MIN_ENDSTOP_INVERTING){ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); - }else{ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); - } - SERIAL_PROTOCOLLN(""); - #endif - #if defined(X_MAX_PIN) && X_MAX_PIN > -1 - SERIAL_PROTOCOLRPGM(_n("x_max: "));////MSG_X_MAX c=0 r=0 - if(READ(X_MAX_PIN)^X_MAX_ENDSTOP_INVERTING){ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); - }else{ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); - } - SERIAL_PROTOCOLLN(""); - #endif - #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 - SERIAL_PROTOCOLRPGM(_n("y_min: "));////MSG_Y_MIN c=0 r=0 - if(READ(Y_MIN_PIN)^Y_MIN_ENDSTOP_INVERTING){ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); - }else{ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); - } - SERIAL_PROTOCOLLN(""); - #endif - #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 - SERIAL_PROTOCOLRPGM(_n("y_max: "));////MSG_Y_MAX c=0 r=0 - if(READ(Y_MAX_PIN)^Y_MAX_ENDSTOP_INVERTING){ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); - }else{ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); - } - SERIAL_PROTOCOLLN(""); - #endif - #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 - SERIAL_PROTOCOLRPGM(MSG_Z_MIN); - if(READ(Z_MIN_PIN)^Z_MIN_ENDSTOP_INVERTING){ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); - }else{ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); - } - SERIAL_PROTOCOLLN(""); - #endif - #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 - SERIAL_PROTOCOLRPGM(MSG_Z_MAX); - if(READ(Z_MAX_PIN)^Z_MAX_ENDSTOP_INVERTING){ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); - }else{ - SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); - } - SERIAL_PROTOCOLLN(""); - #endif - break; - //TODO: update for all axis, use for loop - #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); - } - break; - #endif //BLINKM - case 200: // M200 D set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). - { - - uint8_t extruder = active_extruder; - if(code_seen('T')) { - extruder = code_value(); - if(extruder >= EXTRUDERS) { - SERIAL_ECHO_START; - SERIAL_ECHO(_i("M200 Invalid extruder "));////MSG_M200_INVALID_EXTRUDER c=0 r=0 - break; - } - } - if(code_seen('D')) { - float diameter = (float)code_value(); - if (diameter == 0.0) { - // setting any extruder filament size disables volumetric on the assumption that - // slicers either generate in extruder values as cubic mm or as as filament feeds - // for all extruders - cs.volumetric_enabled = false; - } else { - cs.filament_size[extruder] = (float)code_value(); - // make sure all extruders have some sane value for the filament size - cs.filament_size[0] = (cs.filament_size[0] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[0]); - #if EXTRUDERS > 1 - cs.filament_size[1] = (cs.filament_size[1] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[1]); - #if EXTRUDERS > 2 - cs.filament_size[2] = (cs.filament_size[2] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[2]); - #endif - #endif - cs.volumetric_enabled = true; - } - } else { - //reserved for setting filament diameter via UFID or filament measuring device - break; - } - calculate_extruder_multipliers(); - } - break; - case 201: // M201 - for (int8_t i = 0; i < NUM_AXIS; i++) - { - if (code_seen(axis_codes[i])) - { - unsigned long val = code_value(); -#ifdef TMC2130 - unsigned long val_silent = val; - if ((i == X_AXIS) || (i == Y_AXIS)) - { - if (val > NORMAL_MAX_ACCEL_XY) - val = NORMAL_MAX_ACCEL_XY; - if (val_silent > SILENT_MAX_ACCEL_XY) - val_silent = SILENT_MAX_ACCEL_XY; - } - cs.max_acceleration_units_per_sq_second_normal[i] = val; - cs.max_acceleration_units_per_sq_second_silent[i] = val_silent; -#else //TMC2130 - max_acceleration_units_per_sq_second[i] = val; -#endif //TMC2130 - } - } - // steps per sq second need to be updated to agree with the units per sq second (as they are what is used in the planner) - reset_acceleration_rates(); - break; - #if 0 // Not used for Sprinter/grbl gen6 - case 202: // M202 - for(int8_t i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * cs.axis_steps_per_unit[i]; - } - break; - #endif - case 203: // M203 max feedrate mm/sec - for (int8_t i = 0; i < NUM_AXIS; i++) - { - if (code_seen(axis_codes[i])) - { - float val = code_value(); -#ifdef TMC2130 - float val_silent = val; - if ((i == X_AXIS) || (i == Y_AXIS)) - { - if (val > NORMAL_MAX_FEEDRATE_XY) - val = NORMAL_MAX_FEEDRATE_XY; - if (val_silent > SILENT_MAX_FEEDRATE_XY) - val_silent = SILENT_MAX_FEEDRATE_XY; - } - cs.max_feedrate_normal[i] = val; - cs.max_feedrate_silent[i] = val_silent; -#else //TMC2130 - max_feedrate[i] = val; -#endif //TMC2130 - } - } - break; - case 204: - //! M204 acclereration settings. - //!@n Supporting old format: M204 S[normal moves] T[filmanent only moves] - //!@n and new format: M204 P[printing moves] R[filmanent only moves] T[travel moves] (as of now T is ignored) - { - if(code_seen('S')) { - // Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware, - // and it is also generated by Slic3r to control acceleration per extrusion type - // (there is a separate acceleration settings in Slicer for perimeter, first layer etc). - cs.acceleration = code_value(); - // Interpret the T value as retract acceleration in the old Marlin format. - if(code_seen('T')) - cs.retract_acceleration = code_value(); - } else { - // New acceleration format, compatible with the upstream Marlin. - if(code_seen('P')) - cs.acceleration = code_value(); - if(code_seen('R')) - cs.retract_acceleration = code_value(); - if(code_seen('T')) { - // Interpret the T value as the travel acceleration in the new Marlin format. - //FIXME Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value. - // travel_acceleration = code_value(); - } - } - } - break; - case 205: //M205 advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk - { - if(code_seen('S')) cs.minimumfeedrate = code_value(); - if(code_seen('T')) cs.mintravelfeedrate = code_value(); - if(code_seen('B')) cs.minsegmenttime = code_value() ; - if(code_seen('X')) cs.max_jerk[X_AXIS] = cs.max_jerk[Y_AXIS] = code_value(); - if(code_seen('Y')) cs.max_jerk[Y_AXIS] = code_value(); - if(code_seen('Z')) cs.max_jerk[Z_AXIS] = code_value(); - if(code_seen('E')) cs.max_jerk[E_AXIS] = code_value(); - if (cs.max_jerk[X_AXIS] > DEFAULT_XJERK) cs.max_jerk[X_AXIS] = DEFAULT_XJERK; - if (cs.max_jerk[Y_AXIS] > DEFAULT_YJERK) cs.max_jerk[Y_AXIS] = DEFAULT_YJERK; - } - break; - case 206: // M206 additional homing offset - for(int8_t i=0; i < 3; i++) - { - if(code_seen(axis_codes[i])) cs.add_homing[i] = code_value(); - } - break; - #ifdef FWRETRACT - case 207: //M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop] - { - if(code_seen('S')) - { - cs.retract_length = code_value() ; - } - if(code_seen('F')) - { - cs.retract_feedrate = code_value()/60 ; - } - if(code_seen('Z')) - { - cs.retract_zlift = code_value() ; - } - }break; - case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/min] - { - if(code_seen('S')) - { - cs.retract_recover_length = code_value() ; - } - if(code_seen('F')) - { - cs.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. - { - if(code_seen('S')) - { - int t= code_value() ; - switch(t) - { - case 0: - { - cs.autoretract_enabled=false; - retracted[0]=false; - #if EXTRUDERS > 1 - retracted[1]=false; - #endif - #if EXTRUDERS > 2 - retracted[2]=false; - #endif - }break; - case 1: - { - cs.autoretract_enabled=true; - retracted[0]=false; - #if EXTRUDERS > 1 - retracted[1]=false; - #endif - #if EXTRUDERS > 2 - retracted[2]=false; - #endif - }break; - default: - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); - SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); - SERIAL_ECHOLNPGM("\"(1)"); - } - } + /* See if we are heating up or cooling down */ + target_direction = isHeatingHotend(extruder); // true if heating, false if cooling - }break; - #endif // FWRETRACT - #if EXTRUDERS > 1 - case 218: // M218 - set hotend offset (in mm), T X Y - { - uint8_t extruder; - if(setTargetedHotend(218, extruder)){ - break; - } - if(code_seen('X')) - { - extruder_offset[X_AXIS][extruder] = code_value(); - } - if(code_seen('Y')) - { - extruder_offset[Y_AXIS][extruder] = code_value(); - } - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_HOTEND_OFFSET); - for(extruder = 0; extruder < EXTRUDERS; extruder++) - { - SERIAL_ECHO(" "); - SERIAL_ECHO(extruder_offset[X_AXIS][extruder]); - SERIAL_ECHO(","); - SERIAL_ECHO(extruder_offset[Y_AXIS][extruder]); - } - SERIAL_ECHOLN(""); - }break; - #endif - case 220: // M220 S- set speed factor override percentage - { - if(code_seen('S')) - { - feedmultiply = code_value() ; - } - } - break; - case 221: // M221 S- set extrude factor override percentage - { - if(code_seen('S')) - { - int tmp_code = code_value(); - if (code_seen('T')) - { - uint8_t extruder; - if(setTargetedHotend(221, extruder)){ - break; - } - extruder_multiply[extruder] = tmp_code; - } - else - { - extrudemultiply = tmp_code ; - } - } - calculate_extruder_multipliers(); - } - break; + KEEPALIVE_STATE(NOT_BUSY); - 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 + cancel_heatup = false; - if(code_seen('S')) pin_state = code_value(); // required pin state + wait_for_heater(codenum, extruder); //loops until target temperature is reached - if(pin_state >= -1 && pin_state <= 1){ + LCD_MESSAGERPGM(_T(MSG_HEATING_COMPLETE)); + KEEPALIVE_STATE(IN_HANDLER); + heating_status = 2; + if (farm_mode) { + prusa_statistics(2); + }; - for(int8_t i = 0; i < (int8_t)(sizeof(sensitive_pins)/sizeof(int)); i++) - { - if (sensitive_pins[i] == pin_number) - { - pin_number = -1; - break; + //starttime=millis(); + previous_millis_cmd = millis(); } - } + break; + case 190: // M190 - Wait for bed heater to reach target. +#if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 + LCD_MESSAGERPGM(_T(MSG_BED_HEATING)); + heating_status = 3; + if (farm_mode) { + prusa_statistics(1); + }; + if (code_seen('S')) + { + setTargetBed(code_value()); + CooldownNoWait = true; + } + else if (code_seen('R')) + { + setTargetBed(code_value()); + CooldownNoWait = false; + } + codenum = millis(); - if (pin_number > -1) - { - int target = LOW; + cancel_heatup = false; + target_direction = isHeatingBed(); // true if heating, false if cooling - st_synchronize(); + KEEPALIVE_STATE(NOT_BUSY); + while ( (target_direction)&&(!cancel_heatup) ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) ) + { + if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. + { + if (!farm_mode) { + float tt = degHotend(active_extruder); + SERIAL_PROTOCOLPGM("T:"); + SERIAL_PROTOCOL(tt); + SERIAL_PROTOCOLPGM(" E:"); + SERIAL_PROTOCOL((int)active_extruder); + SERIAL_PROTOCOLPGM(" B:"); + SERIAL_PROTOCOL_F(degBed(), 1); + SERIAL_PROTOCOLLN(""); + } + codenum = millis(); + + } + manage_heater(); + manage_inactivity(); + lcd_update(0); + } + LCD_MESSAGERPGM(_T(MSG_BED_DONE)); + KEEPALIVE_STATE(IN_HANDLER); + heating_status = 4; - pinMode(pin_number, INPUT); + previous_millis_cmd = millis(); +#endif + break; - switch(pin_state){ - case 1: - target = HIGH; - break; +#if defined(FAN_PIN) && FAN_PIN > -1 + case 106: //!M106 Sxxx Fan On S 0 .. 255 + if (code_seen('S')) { + fanSpeed=constrain(code_value(),0,255); + } + else { + fanSpeed=255; + } + break; + case 107: //M107 Fan Off + fanSpeed = 0; + break; +#endif //FAN_PIN + +#if defined(PS_ON_PIN) && PS_ON_PIN > -1 + 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 + + powersupply = true; + LCD_MESSAGERPGM(_T(WELCOME_MSG)); + lcd_update(0); + break; +#endif + + case 81: // M81 - Turn off Power Supply + disable_heater(); + st_synchronize(); + disable_e0(); + disable_e1(); + disable_e2(); + finishAndDisableSteppers(); + fanSpeed = 0; + delay(1000); // Wait a little before to switch off +#if defined(SUICIDE_PIN) && SUICIDE_PIN > -1 + st_synchronize(); + suicide(); +#elif defined(PS_ON_PIN) && PS_ON_PIN > -1 + SET_OUTPUT(PS_ON_PIN); + WRITE(PS_ON_PIN, PS_ON_ASLEEP); +#endif + powersupply = false; + LCD_MESSAGERPGM(CAT4(CUSTOM_MENDEL_NAME,PSTR(" "),MSG_OFF,PSTR("."))); + lcd_update(0); + break; + + case 82: + axis_relative_modes[3] = false; + break; + case 83: + axis_relative_modes[3] = true; + break; + case 18: //compatibility + case 84: // M84 + if(code_seen('S')) { + stepper_inactive_time = code_value() * 1000; + } + else + { + 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(); + disable_e0(); + disable_e1(); + disable_e2(); + finishAndDisableSteppers(); + } + else + { + st_synchronize(); + if (code_seen('X')) disable_x(); + if (code_seen('Y')) disable_y(); + if (code_seen('Z')) disable_z(); +#if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS + if (code_seen('E')) { + disable_e0(); + disable_e1(); + disable_e2(); + } +#endif + } + } + //in the end of print set estimated time to end of print and extruders used during print to default values for next print + print_time_remaining_init(); + snmm_filaments_used = 0; + break; + case 85: // M85 + if(code_seen('S')) { + max_inactive_time = code_value() * 1000; + } + break; +#ifdef SAFETYTIMER + case 86: // M86 - set safety timer expiration time in seconds; M86 S0 will disable safety timer + //when safety timer expires heatbed and nozzle target temperatures are set to zero + if (code_seen('S')) { + safetytimer_inactive_time = code_value() * 1000; + safetyTimer.start(); + } + break; +#endif + case 92: // M92 + for(int8_t i=0; i < NUM_AXIS; i++) + { + if(code_seen(axis_codes[i])) + { + if(i == 3) { // E + float value = code_value(); + if(value < 20.0) { + float factor = cs.axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab. + cs.max_jerk[E_AXIS] *= factor; + max_feedrate[i] *= factor; + axis_steps_per_sqr_second[i] *= factor; + } + cs.axis_steps_per_unit[i] = value; + } + else { + cs.axis_steps_per_unit[i] = code_value(); + } + } + } + break; + case 110: //! M110 N - reset line pos + if (code_seen('N')) + gcode_LastN = code_value_long(); + break; +#ifdef HOST_KEEPALIVE_FEATURE + case 113: // M113 - Get or set Host Keepalive interval + if (code_seen('S')) { + host_keepalive_interval = (uint8_t)code_value_short(); +// NOMORE(host_keepalive_interval, 60); + } + else { + SERIAL_ECHO_START; + SERIAL_ECHOPAIR("M113 S", (unsigned long)host_keepalive_interval); + SERIAL_PROTOCOLLN(""); + } + break; +#endif + case 115: // M115 + if (code_seen('V')) { + // Report the Prusa version number. + SERIAL_PROTOCOLLNRPGM(FW_VERSION_STR_P()); + } else if (code_seen('U')) { + // Check the firmware version provided. If the firmware version provided by the U code is higher than the currently running firmware, + // pause the print and ask the user to upgrade the firmware. + show_upgrade_dialog_if_version_newer(++ strchr_pointer); + } else { + SERIAL_ECHOPGM("FIRMWARE_NAME:Prusa-Firmware "); + SERIAL_ECHORPGM(FW_VERSION_STR_P()); + SERIAL_ECHOPGM(" based on Marlin FIRMWARE_URL:https://github.com/prusa3d/Prusa-Firmware PROTOCOL_VERSION:"); + SERIAL_ECHOPGM(PROTOCOL_VERSION); + SERIAL_ECHOPGM(" MACHINE_TYPE:"); + SERIAL_ECHOPGM(CUSTOM_MENDEL_NAME); + SERIAL_ECHOPGM(" EXTRUDER_COUNT:"); + SERIAL_ECHOPGM(STRINGIFY(EXTRUDERS)); + SERIAL_ECHOPGM(" UUID:"); + SERIAL_ECHOLNPGM(MACHINE_UUID); + } + break; + /* case 117: // M117 display message + starpos = (strchr(strchr_pointer + 5,'*')); + if(starpos!=NULL) + *(starpos)='\0'; + lcd_setstatus(strchr_pointer + 5); + break;*/ + case 114: // M114 + gcode_M114(); + break; + case 120: //! M120 - Disable endstops + enable_endstops(false) ; + break; + case 121: //! M121 - Enable endstops + enable_endstops(true) ; + break; + case 119: // M119 + SERIAL_PROTOCOLRPGM(_N("Reporting endstop status"));////MSG_M119_REPORT c=0 r=0 + SERIAL_PROTOCOLLN(""); +#if defined(X_MIN_PIN) && X_MIN_PIN > -1 + SERIAL_PROTOCOLRPGM(_n("x_min: "));////MSG_X_MIN c=0 r=0 + if(READ(X_MIN_PIN)^X_MIN_ENDSTOP_INVERTING) { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); + } else { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); + } + SERIAL_PROTOCOLLN(""); +#endif +#if defined(X_MAX_PIN) && X_MAX_PIN > -1 + SERIAL_PROTOCOLRPGM(_n("x_max: "));////MSG_X_MAX c=0 r=0 + if(READ(X_MAX_PIN)^X_MAX_ENDSTOP_INVERTING) { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); + } else { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); + } + SERIAL_PROTOCOLLN(""); +#endif +#if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 + SERIAL_PROTOCOLRPGM(_n("y_min: "));////MSG_Y_MIN c=0 r=0 + if(READ(Y_MIN_PIN)^Y_MIN_ENDSTOP_INVERTING) { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); + } else { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); + } + SERIAL_PROTOCOLLN(""); +#endif +#if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 + SERIAL_PROTOCOLRPGM(_n("y_max: "));////MSG_Y_MAX c=0 r=0 + if(READ(Y_MAX_PIN)^Y_MAX_ENDSTOP_INVERTING) { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); + } else { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); + } + SERIAL_PROTOCOLLN(""); +#endif +#if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 + SERIAL_PROTOCOLRPGM(MSG_Z_MIN); + if(READ(Z_MIN_PIN)^Z_MIN_ENDSTOP_INVERTING) { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); + } else { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); + } + SERIAL_PROTOCOLLN(""); +#endif +#if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 + SERIAL_PROTOCOLRPGM(MSG_Z_MAX); + if(READ(Z_MAX_PIN)^Z_MAX_ENDSTOP_INVERTING) { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_HIT)); + } else { + SERIAL_PROTOCOLRPGM(_T(MSG_ENDSTOP_OPEN)); + } + SERIAL_PROTOCOLLN(""); +#endif + break; + //TODO: update for all axis, use for loop +#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); + } + break; +#endif //BLINKM + case 200: // M200 D set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters). + { + + uint8_t extruder = active_extruder; + if(code_seen('T')) { + extruder = code_value(); + if(extruder >= EXTRUDERS) { + SERIAL_ECHO_START; + SERIAL_ECHO(_i("M200 Invalid extruder "));////MSG_M200_INVALID_EXTRUDER c=0 r=0 + break; + } + } + if(code_seen('D')) { + float diameter = (float)code_value(); + if (diameter == 0.0) { + // setting any extruder filament size disables volumetric on the assumption that + // slicers either generate in extruder values as cubic mm or as as filament feeds + // for all extruders + cs.volumetric_enabled = false; + } else { + cs.filament_size[extruder] = (float)code_value(); + // make sure all extruders have some sane value for the filament size + cs.filament_size[0] = (cs.filament_size[0] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[0]); +#if EXTRUDERS > 1 + cs.filament_size[1] = (cs.filament_size[1] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[1]); +#if EXTRUDERS > 2 + cs.filament_size[2] = (cs.filament_size[2] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : cs.filament_size[2]); +#endif +#endif + cs.volumetric_enabled = true; + } + } else { + //reserved for setting filament diameter via UFID or filament measuring device + break; + } + calculate_extruder_multipliers(); + } + break; + case 201: // M201 + for (int8_t i = 0; i < NUM_AXIS; i++) + { + if (code_seen(axis_codes[i])) + { + unsigned long val = code_value(); +#ifdef TMC2130 + unsigned long val_silent = val; + if ((i == X_AXIS) || (i == Y_AXIS)) + { + if (val > NORMAL_MAX_ACCEL_XY) + val = NORMAL_MAX_ACCEL_XY; + if (val_silent > SILENT_MAX_ACCEL_XY) + val_silent = SILENT_MAX_ACCEL_XY; + } + cs.max_acceleration_units_per_sq_second_normal[i] = val; + cs.max_acceleration_units_per_sq_second_silent[i] = val_silent; +#else //TMC2130 + max_acceleration_units_per_sq_second[i] = val; +#endif //TMC2130 + } + } + // steps per sq second need to be updated to agree with the units per sq second (as they are what is used in the planner) + reset_acceleration_rates(); + break; +#if 0 // Not used for Sprinter/grbl gen6 + case 202: // M202 + for(int8_t i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * cs.axis_steps_per_unit[i]; + } + break; +#endif + case 203: // M203 max feedrate mm/sec + for (int8_t i = 0; i < NUM_AXIS; i++) + { + if (code_seen(axis_codes[i])) + { + float val = code_value(); +#ifdef TMC2130 + float val_silent = val; + if ((i == X_AXIS) || (i == Y_AXIS)) + { + if (val > NORMAL_MAX_FEEDRATE_XY) + val = NORMAL_MAX_FEEDRATE_XY; + if (val_silent > SILENT_MAX_FEEDRATE_XY) + val_silent = SILENT_MAX_FEEDRATE_XY; + } + cs.max_feedrate_normal[i] = val; + cs.max_feedrate_silent[i] = val_silent; +#else //TMC2130 + max_feedrate[i] = val; +#endif //TMC2130 + } + } + break; + case 204: + //! M204 acclereration settings. + //!@n Supporting old format: M204 S[normal moves] T[filmanent only moves] + //!@n and new format: M204 P[printing moves] R[filmanent only moves] T[travel moves] (as of now T is ignored) + { + if(code_seen('S')) { + // Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware, + // and it is also generated by Slic3r to control acceleration per extrusion type + // (there is a separate acceleration settings in Slicer for perimeter, first layer etc). + cs.acceleration = code_value(); + // Interpret the T value as retract acceleration in the old Marlin format. + if(code_seen('T')) + cs.retract_acceleration = code_value(); + } else { + // New acceleration format, compatible with the upstream Marlin. + if(code_seen('P')) + cs.acceleration = code_value(); + if(code_seen('R')) + cs.retract_acceleration = code_value(); + if(code_seen('T')) { + // Interpret the T value as the travel acceleration in the new Marlin format. + //FIXME Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value. + // travel_acceleration = code_value(); + } + } + } + break; + case 205: //M205 advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk + { + if(code_seen('S')) cs.minimumfeedrate = code_value(); + if(code_seen('T')) cs.mintravelfeedrate = code_value(); + if(code_seen('B')) cs.minsegmenttime = code_value() ; + if(code_seen('X')) cs.max_jerk[X_AXIS] = cs.max_jerk[Y_AXIS] = code_value(); + if(code_seen('Y')) cs.max_jerk[Y_AXIS] = code_value(); + if(code_seen('Z')) cs.max_jerk[Z_AXIS] = code_value(); + if(code_seen('E')) cs.max_jerk[E_AXIS] = code_value(); + if (cs.max_jerk[X_AXIS] > DEFAULT_XJERK) cs.max_jerk[X_AXIS] = DEFAULT_XJERK; + if (cs.max_jerk[Y_AXIS] > DEFAULT_YJERK) cs.max_jerk[Y_AXIS] = DEFAULT_YJERK; + } + break; + case 206: // M206 additional homing offset + for(int8_t i=0; i < 3; i++) + { + if(code_seen(axis_codes[i])) cs.add_homing[i] = code_value(); + } + break; +#ifdef FWRETRACT + case 207: //M207 - set retract length S[positive mm] F[feedrate mm/min] Z[additional zlift/hop] + { + if(code_seen('S')) + { + cs.retract_length = code_value() ; + } + if(code_seen('F')) + { + cs.retract_feedrate = code_value()/60 ; + } + if(code_seen('Z')) + { + cs.retract_zlift = code_value() ; + } + } + break; + case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/min] + { + if(code_seen('S')) + { + cs.retract_recover_length = code_value() ; + } + if(code_seen('F')) + { + cs.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. + { + if(code_seen('S')) + { + int t= code_value() ; + switch(t) + { + case 0: + { + cs.autoretract_enabled=false; + retracted[0]=false; +#if EXTRUDERS > 1 + retracted[1]=false; +#endif +#if EXTRUDERS > 2 + retracted[2]=false; +#endif + } + break; + case 1: + { + cs.autoretract_enabled=true; + retracted[0]=false; +#if EXTRUDERS > 1 + retracted[1]=false; +#endif +#if EXTRUDERS > 2 + retracted[2]=false; +#endif + } + break; + default: + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); + SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); + SERIAL_ECHOLNPGM("\"(1)"); + } + } + + } + break; +#endif // FWRETRACT +#if EXTRUDERS > 1 + case 218: // M218 - set hotend offset (in mm), T X Y + { + uint8_t extruder; + if(setTargetedHotend(218, extruder)) { + break; + } + if(code_seen('X')) + { + extruder_offset[X_AXIS][extruder] = code_value(); + } + if(code_seen('Y')) + { + extruder_offset[Y_AXIS][extruder] = code_value(); + } + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_HOTEND_OFFSET); + for(extruder = 0; extruder < EXTRUDERS; extruder++) + { + SERIAL_ECHO(" "); + SERIAL_ECHO(extruder_offset[X_AXIS][extruder]); + SERIAL_ECHO(","); + SERIAL_ECHO(extruder_offset[Y_AXIS][extruder]); + } + SERIAL_ECHOLN(""); + } + break; +#endif + case 220: // M220 S- set speed factor override percentage + { + if(code_seen('S')) + { + feedmultiply = code_value() ; + } + } + break; + case 221: // M221 S- set extrude factor override percentage + { + if(code_seen('S')) + { + int tmp_code = code_value(); + if (code_seen('T')) + { + uint8_t extruder; + if(setTargetedHotend(221, extruder)) { + break; + } + extruder_multiply[extruder] = tmp_code; + } + else + { + extrudemultiply = tmp_code ; + } + } + calculate_extruder_multipliers(); + } + 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)/sizeof(int)); i++) + { + if (sensitive_pins[i] == pin_number) + { + pin_number = -1; + break; + } + } + + if (pin_number > -1) + { + int target = LOW; + + st_synchronize(); + + pinMode(pin_number, INPUT); + + 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(0); + } + } + } + } + } + break; + +#if NUM_SERVOS > 0 + case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds + { + int servo_index = -1; + int servo_position = 0; + if (code_seen('P')) + servo_index = code_value(); + 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; + SERIAL_ECHO("Servo "); + SERIAL_ECHO(servo_index); + SERIAL_ECHOLN(" out of range"); + } + } + else if (servo_index >= 0) { + SERIAL_PROTOCOL(_T(MSG_OK)); + SERIAL_PROTOCOL(" Servo "); + SERIAL_PROTOCOL(servo_index); + SERIAL_PROTOCOL(": "); + SERIAL_PROTOCOL(servos[servo_index].read()); + SERIAL_PROTOCOLLN(""); + } + } + break; +#endif // NUM_SERVOS > 0 + +#if (LARGE_FLASH == true && ( BEEPER > 0 || defined(ULTRALCD) || defined(LCD_USE_I2C_BUZZER))) + case 300: // M300 + { + int beepS = code_seen('S') ? code_value() : 110; + int beepP = code_seen('P') ? code_value() : 1000; + if (beepS > 0) + { +#if BEEPER > 0 + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + tone(BEEPER, beepS); + delay(beepP); + noTone(BEEPER); +#endif + } + else + { + delay(beepP); + } + } + break; +#endif // M300 + +#ifdef PIDTEMP + case 301: // M301 + { + if(code_seen('P')) cs.Kp = code_value(); + if(code_seen('I')) cs.Ki = scalePID_i(code_value()); + if(code_seen('D')) cs.Kd = scalePID_d(code_value()); + +#ifdef PID_ADD_EXTRUSION_RATE + if(code_seen('C')) Kc = code_value(); +#endif + + updatePID(); + SERIAL_PROTOCOLRPGM(_T(MSG_OK)); + SERIAL_PROTOCOL(" p:"); + SERIAL_PROTOCOL(cs.Kp); + SERIAL_PROTOCOL(" i:"); + SERIAL_PROTOCOL(unscalePID_i(cs.Ki)); + SERIAL_PROTOCOL(" d:"); + SERIAL_PROTOCOL(unscalePID_d(cs.Kd)); +#ifdef PID_ADD_EXTRUSION_RATE + SERIAL_PROTOCOL(" c:"); + //Kc does not have scaling applied above, or in resetting defaults + SERIAL_PROTOCOL(Kc); +#endif + SERIAL_PROTOCOLLN(""); + } + break; +#endif //PIDTEMP +#ifdef PIDTEMPBED + case 304: // M304 + { + if(code_seen('P')) cs.bedKp = code_value(); + if(code_seen('I')) cs.bedKi = scalePID_i(code_value()); + if(code_seen('D')) cs.bedKd = scalePID_d(code_value()); + + updatePID(); + SERIAL_PROTOCOLRPGM(_T(MSG_OK)); + SERIAL_PROTOCOL(" p:"); + SERIAL_PROTOCOL(cs.bedKp); + SERIAL_PROTOCOL(" i:"); + SERIAL_PROTOCOL(unscalePID_i(cs.bedKi)); + SERIAL_PROTOCOL(" d:"); + SERIAL_PROTOCOL(unscalePID_d(cs.bedKd)); + SERIAL_PROTOCOLLN(""); + } + break; +#endif //PIDTEMP + case 240: // M240 Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/ + { +#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); + } +#endif +#endif //chdk end if + } + break; +#ifdef PREVENT_DANGEROUS_EXTRUDE + case 302: // allow cold extrudes, or set the minimum extrude temperature + { + float temp = .0; + if (code_seen('S')) temp=code_value(); + set_extrude_min_temp(temp); + } + break; +#endif + case 303: // M303 PID autotune + { + float temp = 150.0; + int e=0; + int c=5; + if (code_seen('E')) e=code_value(); + if (e<0) + temp=70; + if (code_seen('S')) temp=code_value(); + if (code_seen('C')) c=code_value(); + PID_autotune(temp, e, c); + } + break; + case 400: // M400 finish all moves + { + st_synchronize(); + } + break; + + case 403: //! M403 set filament type (material) for particular extruder and send this information to mmu + { + //! currently three different materials are needed (default, flex and PVA) + //! add storing this information for different load/unload profiles etc. in the future + //!firmware does not wait for "ok" from mmu + if (mmu_enabled) + { + uint8_t extruder = 255; + uint8_t filament = FILAMENT_UNDEFINED; + if(code_seen('E')) extruder = code_value(); + if(code_seen('F')) filament = code_value(); + mmu_set_filament_type(extruder, filament); + } + } + break; + + case 500: // M500 Store settings in EEPROM + { + Config_StoreSettings(); + } + break; + case 501: // M501 Read settings from EEPROM + { + Config_RetrieveSettings(); + } + break; + case 502: // M502 Revert to default settings + { + Config_ResetDefault(); + } + break; + case 503: // M503 print settings currently in memory + { + Config_PrintSettings(); + } + break; + case 509: //M509 Force language selection + { + lang_reset(); + SERIAL_ECHO_START; + SERIAL_PROTOCOLPGM(("LANG SEL FORCED")); + } + break; +#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED + case 540: + { + if(code_seen('S')) abort_on_endstop_hit = code_value() > 0; + } + 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)) + { + cs.zprobe_zoffset = -value; // compare w/ line 278 of ConfigurationStore.cpp + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(CAT4(MSG_ZPROBE_ZOFFSET, " ", _T(MSG_OK),PSTR(""))); + SERIAL_PROTOCOLLN(""); + } + else + { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_ZPROBE_ZOFFSET); + SERIAL_ECHORPGM(MSG_Z_MIN); + SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MIN); + SERIAL_ECHORPGM(MSG_Z_MAX); + SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MAX); + SERIAL_PROTOCOLLN(""); + } + } + else + { + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(CAT2(MSG_ZPROBE_ZOFFSET, PSTR(" : "))); + SERIAL_ECHO(-cs.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] + { + st_synchronize(); + + float x_position = current_position[X_AXIS]; + float y_position = current_position[Y_AXIS]; + float z_shift = 0; + float e_shift_init = 0; + float e_shift_late = 0; + bool automatic = false; + + //Retract extruder + if(code_seen('E')) + { + e_shift_init = code_value(); + } + else + { +#ifdef FILAMENTCHANGE_FIRSTRETRACT + e_shift_init = FILAMENTCHANGE_FIRSTRETRACT ; +#endif + } + + //currently don't work as we are using the same unload sequence as in M702, needs re-work + if (code_seen('L')) + { + e_shift_late = code_value(); + } + else + { +#ifdef FILAMENTCHANGE_FINALRETRACT + e_shift_late = FILAMENTCHANGE_FINALRETRACT; +#endif + } + + //Lift Z + if(code_seen('Z')) + { + z_shift = code_value(); + } + else + { +#ifdef FILAMENTCHANGE_ZADD + z_shift= FILAMENTCHANGE_ZADD ; + if(current_position[Z_AXIS] < 25) z_shift+= 25 ; +#endif + } + //Move XY to side + if(code_seen('X')) + { + x_position = code_value(); + } + else + { +#ifdef FILAMENTCHANGE_XPOS + x_position = FILAMENTCHANGE_XPOS; +#endif + } + if(code_seen('Y')) + { + y_position = code_value(); + } + else + { +#ifdef FILAMENTCHANGE_YPOS + y_position = FILAMENTCHANGE_YPOS ; +#endif + } + + if (mmu_enabled && code_seen("AUTO")) + automatic = true; - case 0: - target = LOW; - break; + gcode_M600(automatic, x_position, y_position, z_shift, e_shift_init, e_shift_late); - case -1: - target = !digitalRead(pin_number); - break; } + break; +#endif //FILAMENTCHANGEENABLE + case 601: //! M601 - Pause print + { + lcd_pause_print(); + } + break; - while(digitalRead(pin_number) != target){ - manage_heater(); - manage_inactivity(); - lcd_update(0); + case 602: { //! M602 - Resume print + lcd_resume_print(); } - } - } - } - } - break; - - #if NUM_SERVOS > 0 - case 280: // M280 - set servo position absolute. P: servo index, S: angle or microseconds - { - int servo_index = -1; - int servo_position = 0; - if (code_seen('P')) - servo_index = code_value(); - 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; - SERIAL_ECHO("Servo "); - SERIAL_ECHO(servo_index); - SERIAL_ECHOLN(" out of range"); - } - } - else if (servo_index >= 0) { - SERIAL_PROTOCOL(_T(MSG_OK)); - SERIAL_PROTOCOL(" Servo "); - SERIAL_PROTOCOL(servo_index); - SERIAL_PROTOCOL(": "); - SERIAL_PROTOCOL(servos[servo_index].read()); - SERIAL_PROTOCOLLN(""); - } - } - break; - #endif // NUM_SERVOS > 0 + break; - #if (LARGE_FLASH == true && ( BEEPER > 0 || defined(ULTRALCD) || defined(LCD_USE_I2C_BUZZER))) - case 300: // M300 - { - int beepS = code_seen('S') ? code_value() : 110; - int beepP = code_seen('P') ? code_value() : 1000; - if (beepS > 0) - { - #if BEEPER > 0 -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - tone(BEEPER, beepS); - delay(beepP); - noTone(BEEPER); - #endif - } - else - { - delay(beepP); - } - } - break; - #endif // M300 - - #ifdef PIDTEMP - case 301: // M301 - { - if(code_seen('P')) cs.Kp = code_value(); - if(code_seen('I')) cs.Ki = scalePID_i(code_value()); - if(code_seen('D')) cs.Kd = scalePID_d(code_value()); - - #ifdef PID_ADD_EXTRUSION_RATE - if(code_seen('C')) Kc = code_value(); - #endif - - updatePID(); - SERIAL_PROTOCOLRPGM(_T(MSG_OK)); - SERIAL_PROTOCOL(" p:"); - SERIAL_PROTOCOL(cs.Kp); - SERIAL_PROTOCOL(" i:"); - SERIAL_PROTOCOL(unscalePID_i(cs.Ki)); - SERIAL_PROTOCOL(" d:"); - SERIAL_PROTOCOL(unscalePID_d(cs.Kd)); - #ifdef PID_ADD_EXTRUSION_RATE - SERIAL_PROTOCOL(" c:"); - //Kc does not have scaling applied above, or in resetting defaults - SERIAL_PROTOCOL(Kc); - #endif - SERIAL_PROTOCOLLN(""); - } - break; - #endif //PIDTEMP - #ifdef PIDTEMPBED - case 304: // M304 - { - if(code_seen('P')) cs.bedKp = code_value(); - if(code_seen('I')) cs.bedKi = scalePID_i(code_value()); - if(code_seen('D')) cs.bedKd = scalePID_d(code_value()); - - updatePID(); - SERIAL_PROTOCOLRPGM(_T(MSG_OK)); - SERIAL_PROTOCOL(" p:"); - SERIAL_PROTOCOL(cs.bedKp); - SERIAL_PROTOCOL(" i:"); - SERIAL_PROTOCOL(unscalePID_i(cs.bedKi)); - SERIAL_PROTOCOL(" d:"); - SERIAL_PROTOCOL(unscalePID_d(cs.bedKd)); - SERIAL_PROTOCOLLN(""); - } - break; - #endif //PIDTEMP - case 240: // M240 Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/ - { - #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); - } - #endif - #endif //chdk end if - } - break; - #ifdef PREVENT_DANGEROUS_EXTRUDE - case 302: // allow cold extrudes, or set the minimum extrude temperature - { - float temp = .0; - if (code_seen('S')) temp=code_value(); - set_extrude_min_temp(temp); - } - break; - #endif - case 303: // M303 PID autotune - { - float temp = 150.0; - int e=0; - int c=5; - if (code_seen('E')) e=code_value(); - if (e<0) - temp=70; - if (code_seen('S')) temp=code_value(); - if (code_seen('C')) c=code_value(); - PID_autotune(temp, e, c); - } - break; - case 400: // M400 finish all moves - { - st_synchronize(); - } - break; - - case 403: //! M403 set filament type (material) for particular extruder and send this information to mmu - { - //! currently three different materials are needed (default, flex and PVA) - //! add storing this information for different load/unload profiles etc. in the future - //!firmware does not wait for "ok" from mmu - if (mmu_enabled) - { - uint8_t extruder = 255; - uint8_t filament = FILAMENT_UNDEFINED; - if(code_seen('E')) extruder = code_value(); - if(code_seen('F')) filament = code_value(); - mmu_set_filament_type(extruder, filament); - } - } - break; +#ifdef PINDA_THERMISTOR + case 860: // M860 - Wait for PINDA thermistor to reach target temperature. + { + int set_target_pinda = 0; - case 500: // M500 Store settings in EEPROM - { - Config_StoreSettings(); - } - break; - case 501: // M501 Read settings from EEPROM - { - Config_RetrieveSettings(); - } - break; - case 502: // M502 Revert to default settings - { - Config_ResetDefault(); - } - break; - case 503: // M503 print settings currently in memory - { - Config_PrintSettings(); - } - break; - case 509: //M509 Force language selection - { - lang_reset(); - SERIAL_ECHO_START; - SERIAL_PROTOCOLPGM(("LANG SEL FORCED")); - } - break; - #ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED - case 540: - { - if(code_seen('S')) abort_on_endstop_hit = code_value() > 0; - } - break; - #endif + if (code_seen('S')) { + set_target_pinda = code_value(); + } + else { + break; + } - #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)) - { - cs.zprobe_zoffset = -value; // compare w/ line 278 of ConfigurationStore.cpp - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM(CAT4(MSG_ZPROBE_ZOFFSET, " ", _T(MSG_OK),PSTR(""))); - SERIAL_PROTOCOLLN(""); - } - else - { - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_ZPROBE_ZOFFSET); - SERIAL_ECHORPGM(MSG_Z_MIN); - SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MIN); - SERIAL_ECHORPGM(MSG_Z_MAX); - SERIAL_ECHO(Z_PROBE_OFFSET_RANGE_MAX); - SERIAL_PROTOCOLLN(""); - } - } - else - { - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM(CAT2(MSG_ZPROBE_ZOFFSET, PSTR(" : "))); - SERIAL_ECHO(-cs.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] - { - st_synchronize(); + LCD_MESSAGERPGM(_T(MSG_PLEASE_WAIT)); - float x_position = current_position[X_AXIS]; - float y_position = current_position[Y_AXIS]; - float z_shift = 0; - float e_shift_init = 0; - float e_shift_late = 0; - bool automatic = false; - - //Retract extruder - if(code_seen('E')) - { - e_shift_init = code_value(); - } - else - { - #ifdef FILAMENTCHANGE_FIRSTRETRACT - e_shift_init = FILAMENTCHANGE_FIRSTRETRACT ; - #endif - } + SERIAL_PROTOCOLPGM("Wait for PINDA target temperature:"); + SERIAL_PROTOCOL(set_target_pinda); + SERIAL_PROTOCOLLN(""); - //currently don't work as we are using the same unload sequence as in M702, needs re-work - if (code_seen('L')) - { - e_shift_late = code_value(); - } - else - { - #ifdef FILAMENTCHANGE_FINALRETRACT - e_shift_late = FILAMENTCHANGE_FINALRETRACT; - #endif - } - - //Lift Z - if(code_seen('Z')) - { - z_shift = code_value(); - } - else - { - #ifdef FILAMENTCHANGE_ZADD - z_shift= FILAMENTCHANGE_ZADD ; - if(current_position[Z_AXIS] < 25) z_shift+= 25 ; - #endif - } - //Move XY to side - if(code_seen('X')) - { - x_position = code_value(); - } - else - { - #ifdef FILAMENTCHANGE_XPOS - x_position = FILAMENTCHANGE_XPOS; - #endif - } - if(code_seen('Y')) - { - y_position = code_value(); - } - else - { - #ifdef FILAMENTCHANGE_YPOS - y_position = FILAMENTCHANGE_YPOS ; - #endif - } + codenum = millis(); + cancel_heatup = false; - if (mmu_enabled && code_seen("AUTO")) - automatic = true; + bool is_pinda_cooling = false; + if ((degTargetBed() == 0) && (degTargetHotend(0) == 0)) { + is_pinda_cooling = true; + } - gcode_M600(automatic, x_position, y_position, z_shift, e_shift_init, e_shift_late); - - } - break; - #endif //FILAMENTCHANGEENABLE - case 601: //! M601 - Pause print - { - lcd_pause_print(); - } - break; + while ( ((!is_pinda_cooling) && (!cancel_heatup) && (current_temperature_pinda < set_target_pinda)) || (is_pinda_cooling && (current_temperature_pinda > set_target_pinda)) ) { + if ((millis() - codenum) > 1000) //Print Temp Reading every 1 second while waiting. + { + SERIAL_PROTOCOLPGM("P:"); + SERIAL_PROTOCOL_F(current_temperature_pinda, 1); + SERIAL_PROTOCOLPGM("/"); + SERIAL_PROTOCOL(set_target_pinda); + SERIAL_PROTOCOLLN(""); + codenum = millis(); + } + manage_heater(); + manage_inactivity(); + lcd_update(0); + } + LCD_MESSAGERPGM(_T(MSG_OK)); - case 602: { //! M602 - Resume print - lcd_resume_print(); - } - break; + break; + } -#ifdef PINDA_THERMISTOR - case 860: // M860 - Wait for PINDA thermistor to reach target temperature. - { - int set_target_pinda = 0; - - if (code_seen('S')) { - set_target_pinda = code_value(); - } - else { - break; - } - - LCD_MESSAGERPGM(_T(MSG_PLEASE_WAIT)); - - SERIAL_PROTOCOLPGM("Wait for PINDA target temperature:"); - SERIAL_PROTOCOL(set_target_pinda); - SERIAL_PROTOCOLLN(""); - - codenum = millis(); - cancel_heatup = false; - - bool is_pinda_cooling = false; - if ((degTargetBed() == 0) && (degTargetHotend(0) == 0)) { - is_pinda_cooling = true; - } - - while ( ((!is_pinda_cooling) && (!cancel_heatup) && (current_temperature_pinda < set_target_pinda)) || (is_pinda_cooling && (current_temperature_pinda > set_target_pinda)) ) { - if ((millis() - codenum) > 1000) //Print Temp Reading every 1 second while waiting. - { - SERIAL_PROTOCOLPGM("P:"); - SERIAL_PROTOCOL_F(current_temperature_pinda, 1); - SERIAL_PROTOCOLPGM("/"); - SERIAL_PROTOCOL(set_target_pinda); - SERIAL_PROTOCOLLN(""); - codenum = millis(); - } - manage_heater(); - manage_inactivity(); - lcd_update(0); - } - LCD_MESSAGERPGM(_T(MSG_OK)); - - break; - } - - case 861: // M861 - Set/Read PINDA temperature compensation offsets - if (code_seen('?')) { // ? - Print out current EEPROM offset values - uint8_t cal_status = calibration_status_pinda(); - int16_t usteps = 0; - cal_status ? SERIAL_PROTOCOLLN("PINDA cal status: 1") : SERIAL_PROTOCOLLN("PINDA cal status: 0"); - SERIAL_PROTOCOLLN("index, temp, ustep, um"); - for (uint8_t i = 0; i < 6; i++) - { - if(i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i-1) * 2, &usteps); - float mm = ((float)usteps) / cs.axis_steps_per_unit[Z_AXIS]; - i == 0 ? SERIAL_PROTOCOLPGM("n/a") : SERIAL_PROTOCOL(i - 1); - SERIAL_PROTOCOLPGM(", "); - SERIAL_PROTOCOL(35 + (i * 5)); - SERIAL_PROTOCOLPGM(", "); - SERIAL_PROTOCOL(usteps); - SERIAL_PROTOCOLPGM(", "); - SERIAL_PROTOCOL(mm * 1000); - SERIAL_PROTOCOLLN(""); - } - } - else if (code_seen('!')) { // ! - Set factory default values - eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); - int16_t z_shift = 8; //40C - 20um - 8usteps - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT, &z_shift); - z_shift = 24; //45C - 60um - 24usteps - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 2, &z_shift); - z_shift = 48; //50C - 120um - 48usteps - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 4, &z_shift); - z_shift = 80; //55C - 200um - 80usteps - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 6, &z_shift); - z_shift = 120; //60C - 300um - 120usteps - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 8, &z_shift); - SERIAL_PROTOCOLLN("factory restored"); - } - else if (code_seen('Z')) { // Z - Set all values to 0 (effectively disabling PINDA temperature compensation) - eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); - int16_t z_shift = 0; - for (uint8_t i = 0; i < 5; i++) EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); - SERIAL_PROTOCOLLN("zerorized"); - } - else if (code_seen('S')) { // Sxxx Iyyy - Set compensation ustep value S for compensation table index I - int16_t usteps = code_value(); - if (code_seen('I')) { - uint8_t index = code_value(); - if (index < 5) { - EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + index * 2, &usteps); - SERIAL_PROTOCOLLN("OK"); - SERIAL_PROTOCOLLN("index, temp, ustep, um"); - for (uint8_t i = 0; i < 6; i++) - { - usteps = 0; - if (i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i - 1) * 2, &usteps); - float mm = ((float)usteps) / cs.axis_steps_per_unit[Z_AXIS]; - i == 0 ? SERIAL_PROTOCOLPGM("n/a") : SERIAL_PROTOCOL(i - 1); - SERIAL_PROTOCOLPGM(", "); - SERIAL_PROTOCOL(35 + (i * 5)); - SERIAL_PROTOCOLPGM(", "); - SERIAL_PROTOCOL(usteps); - SERIAL_PROTOCOLPGM(", "); - SERIAL_PROTOCOL(mm * 1000); - SERIAL_PROTOCOLLN(""); - } - } - } - } - else { - SERIAL_PROTOCOLPGM("no valid command"); - } - break; + case 861: // M861 - Set/Read PINDA temperature compensation offsets + if (code_seen('?')) { // ? - Print out current EEPROM offset values + uint8_t cal_status = calibration_status_pinda(); + int16_t usteps = 0; + cal_status ? SERIAL_PROTOCOLLN("PINDA cal status: 1") : SERIAL_PROTOCOLLN("PINDA cal status: 0"); + SERIAL_PROTOCOLLN("index, temp, ustep, um"); + for (uint8_t i = 0; i < 6; i++) + { + if(i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i-1) * 2, &usteps); + float mm = ((float)usteps) / cs.axis_steps_per_unit[Z_AXIS]; + i == 0 ? SERIAL_PROTOCOLPGM("n/a") : SERIAL_PROTOCOL(i - 1); + SERIAL_PROTOCOLPGM(", "); + SERIAL_PROTOCOL(35 + (i * 5)); + SERIAL_PROTOCOLPGM(", "); + SERIAL_PROTOCOL(usteps); + SERIAL_PROTOCOLPGM(", "); + SERIAL_PROTOCOL(mm * 1000); + SERIAL_PROTOCOLLN(""); + } + } + else if (code_seen('!')) { // ! - Set factory default values + eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); + int16_t z_shift = 8; //40C - 20um - 8usteps + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT, &z_shift); + z_shift = 24; //45C - 60um - 24usteps + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 2, &z_shift); + z_shift = 48; //50C - 120um - 48usteps + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 4, &z_shift); + z_shift = 80; //55C - 200um - 80usteps + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 6, &z_shift); + z_shift = 120; //60C - 300um - 120usteps + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + 8, &z_shift); + SERIAL_PROTOCOLLN("factory restored"); + } + else if (code_seen('Z')) { // Z - Set all values to 0 (effectively disabling PINDA temperature compensation) + eeprom_write_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); + int16_t z_shift = 0; + for (uint8_t i = 0; i < 5; i++) EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + i * 2, &z_shift); + SERIAL_PROTOCOLLN("zerorized"); + } + else if (code_seen('S')) { // Sxxx Iyyy - Set compensation ustep value S for compensation table index I + int16_t usteps = code_value(); + if (code_seen('I')) { + uint8_t index = code_value(); + if (index < 5) { + EEPROM_save_B(EEPROM_PROBE_TEMP_SHIFT + index * 2, &usteps); + SERIAL_PROTOCOLLN("OK"); + SERIAL_PROTOCOLLN("index, temp, ustep, um"); + for (uint8_t i = 0; i < 6; i++) + { + usteps = 0; + if (i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i - 1) * 2, &usteps); + float mm = ((float)usteps) / cs.axis_steps_per_unit[Z_AXIS]; + i == 0 ? SERIAL_PROTOCOLPGM("n/a") : SERIAL_PROTOCOL(i - 1); + SERIAL_PROTOCOLPGM(", "); + SERIAL_PROTOCOL(35 + (i * 5)); + SERIAL_PROTOCOLPGM(", "); + SERIAL_PROTOCOL(usteps); + SERIAL_PROTOCOLPGM(", "); + SERIAL_PROTOCOL(mm * 1000); + SERIAL_PROTOCOLLN(""); + } + } + } + } + else { + SERIAL_PROTOCOLPGM("no valid command"); + } + break; #endif //PINDA_THERMISTOR #ifdef LIN_ADVANCE - case 900: // M900: Set LIN_ADVANCE options. - gcode_M900(); - break; + case 900: // M900: Set LIN_ADVANCE options. + gcode_M900(); + break; #endif - case 907: // M907 Set digital trimpot motor current using axis codes. - { + case 907: // M907 Set digital trimpot motor current using axis codes. + { #ifdef TMC2130 - for (int i = 0; i < NUM_AXIS; i++) - if(code_seen(axis_codes[i])) - { - long cur_mA = code_value_long(); - uint8_t val = tmc2130_cur2val(cur_mA); - tmc2130_set_current_h(i, val); - tmc2130_set_current_r(i, val); - //if (i == E_AXIS) printf_P(PSTR("E-axis current=%ldmA\n"), cur_mA); - } + for (int i = 0; i < NUM_AXIS; i++) + if(code_seen(axis_codes[i])) + { + long cur_mA = code_value_long(); + uint8_t val = tmc2130_cur2val(cur_mA); + tmc2130_set_current_h(i, val); + tmc2130_set_current_r(i, val); + //if (i == E_AXIS) printf_P(PSTR("E-axis current=%ldmA\n"), cur_mA); + } #else //TMC2130 - #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 - for(int i=0;i -1 + for(int i=0; i -1 - uint8_t channel,current; - if(code_seen('P')) channel=code_value(); - if(code_seen('S')) current=code_value(); - digitalPotWrite(channel, current); - #endif - } - break; + } + break; + case 908: // M908 Control digital trimpot directly. + { +#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1 + uint8_t channel,current; + if(code_seen('P')) channel=code_value(); + if(code_seen('S')) current=code_value(); + digitalPotWrite(channel, current); +#endif + } + break; #ifdef TMC2130_SERVICE_CODES_M910_M918 - case 910: //! M910 - TMC2130 init - { - tmc2130_init(); - } - break; + case 910: //! M910 - TMC2130 init + { + tmc2130_init(); + } + break; - case 911: //! M911 - Set TMC2130 holding currents - { - if (code_seen('X')) tmc2130_set_current_h(0, code_value()); - if (code_seen('Y')) tmc2130_set_current_h(1, code_value()); - if (code_seen('Z')) tmc2130_set_current_h(2, code_value()); - if (code_seen('E')) tmc2130_set_current_h(3, code_value()); - } - break; + case 911: //! M911 - Set TMC2130 holding currents + { + if (code_seen('X')) tmc2130_set_current_h(0, code_value()); + if (code_seen('Y')) tmc2130_set_current_h(1, code_value()); + if (code_seen('Z')) tmc2130_set_current_h(2, code_value()); + if (code_seen('E')) tmc2130_set_current_h(3, code_value()); + } + break; - case 912: //! M912 - Set TMC2130 running currents - { - if (code_seen('X')) tmc2130_set_current_r(0, code_value()); - if (code_seen('Y')) tmc2130_set_current_r(1, code_value()); - if (code_seen('Z')) tmc2130_set_current_r(2, code_value()); - if (code_seen('E')) tmc2130_set_current_r(3, code_value()); - } - break; - case 913: //! M913 - Print TMC2130 currents - { - tmc2130_print_currents(); - } - break; + case 912: //! M912 - Set TMC2130 running currents + { + if (code_seen('X')) tmc2130_set_current_r(0, code_value()); + if (code_seen('Y')) tmc2130_set_current_r(1, code_value()); + if (code_seen('Z')) tmc2130_set_current_r(2, code_value()); + if (code_seen('E')) tmc2130_set_current_r(3, code_value()); + } + break; + case 913: //! M913 - Print TMC2130 currents + { + tmc2130_print_currents(); + } + break; - case 914: //! M914 - Set normal mode - { - tmc2130_mode = TMC2130_MODE_NORMAL; - update_mode_profile(); - tmc2130_init(); - } - break; + case 914: //! M914 - Set normal mode + { + tmc2130_mode = TMC2130_MODE_NORMAL; + update_mode_profile(); + tmc2130_init(); + } + break; - case 915: //! M915 - Set silent mode - { - tmc2130_mode = TMC2130_MODE_SILENT; - update_mode_profile(); - tmc2130_init(); - } - break; + case 915: //! M915 - Set silent mode + { + tmc2130_mode = TMC2130_MODE_SILENT; + update_mode_profile(); + tmc2130_init(); + } + break; - case 916: //! M916 - Set sg_thrs - { - if (code_seen('X')) tmc2130_sg_thr[X_AXIS] = code_value(); - if (code_seen('Y')) tmc2130_sg_thr[Y_AXIS] = code_value(); - if (code_seen('Z')) tmc2130_sg_thr[Z_AXIS] = code_value(); - if (code_seen('E')) tmc2130_sg_thr[E_AXIS] = code_value(); - for (uint8_t a = X_AXIS; a <= E_AXIS; a++) - printf_P(_N("tmc2130_sg_thr[%c]=%d\n"), "XYZE"[a], tmc2130_sg_thr[a]); - } - break; + case 916: //! M916 - Set sg_thrs + { + if (code_seen('X')) tmc2130_sg_thr[X_AXIS] = code_value(); + if (code_seen('Y')) tmc2130_sg_thr[Y_AXIS] = code_value(); + if (code_seen('Z')) tmc2130_sg_thr[Z_AXIS] = code_value(); + if (code_seen('E')) tmc2130_sg_thr[E_AXIS] = code_value(); + for (uint8_t a = X_AXIS; a <= E_AXIS; a++) + printf_P(_N("tmc2130_sg_thr[%c]=%d\n"), "XYZE"[a], tmc2130_sg_thr[a]); + } + break; - case 917: //! M917 - Set TMC2130 pwm_ampl - { - if (code_seen('X')) tmc2130_set_pwm_ampl(0, code_value()); - if (code_seen('Y')) tmc2130_set_pwm_ampl(1, code_value()); - if (code_seen('Z')) tmc2130_set_pwm_ampl(2, code_value()); - if (code_seen('E')) tmc2130_set_pwm_ampl(3, code_value()); - } - break; + case 917: //! M917 - Set TMC2130 pwm_ampl + { + if (code_seen('X')) tmc2130_set_pwm_ampl(0, code_value()); + if (code_seen('Y')) tmc2130_set_pwm_ampl(1, code_value()); + if (code_seen('Z')) tmc2130_set_pwm_ampl(2, code_value()); + if (code_seen('E')) tmc2130_set_pwm_ampl(3, code_value()); + } + break; - case 918: //! M918 - Set TMC2130 pwm_grad - { - if (code_seen('X')) tmc2130_set_pwm_grad(0, code_value()); - if (code_seen('Y')) tmc2130_set_pwm_grad(1, code_value()); - if (code_seen('Z')) tmc2130_set_pwm_grad(2, code_value()); - if (code_seen('E')) tmc2130_set_pwm_grad(3, code_value()); - } - break; + case 918: //! M918 - Set TMC2130 pwm_grad + { + if (code_seen('X')) tmc2130_set_pwm_grad(0, code_value()); + if (code_seen('Y')) tmc2130_set_pwm_grad(1, code_value()); + if (code_seen('Z')) tmc2130_set_pwm_grad(2, code_value()); + if (code_seen('E')) tmc2130_set_pwm_grad(3, code_value()); + } + break; #endif //TMC2130_SERVICE_CODES_M910_M918 - case 350: //! M350 - Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers. - { - #ifdef TMC2130 - if(code_seen('E')) - { - uint16_t res_new = code_value(); - if ((res_new == 8) || (res_new == 16) || (res_new == 32) || (res_new == 64) || (res_new == 128)) - { - st_synchronize(); - uint8_t axis = E_AXIS; - uint16_t res = tmc2130_get_res(axis); - tmc2130_set_res(axis, res_new); - if (res_new > res) - { - uint16_t fac = (res_new / res); - cs.axis_steps_per_unit[axis] *= fac; - position[E_AXIS] *= fac; - } - else - { - uint16_t fac = (res / res_new); - cs.axis_steps_per_unit[axis] /= fac; - position[E_AXIS] /= fac; - } - } - } - #else //TMC2130 - #if defined(X_MS1_PIN) && X_MS1_PIN > -1 - if(code_seen('S')) for(int i=0;i<=4;i++) microstep_mode(i,code_value()); - for(int i=0;i -1 - if(code_seen('S')) switch((int)code_value()) - { - case 1: - for(int i=0;i res) + { + uint16_t fac = (res_new / res); + cs.axis_steps_per_unit[axis] *= fac; + position[E_AXIS] *= fac; + } + else + { + uint16_t fac = (res / res_new); + cs.axis_steps_per_unit[axis] /= fac; + position[E_AXIS] /= fac; + } + } + } +#else //TMC2130 +#if defined(X_MS1_PIN) && X_MS1_PIN > -1 + if(code_seen('S')) for(int i=0; i<=4; i++) microstep_mode(i,code_value()); + for(int i=0; i -1 + if(code_seen('S')) switch((int)code_value()) + { + case 1: + for(int i=0; i - select extruder in case of multi extruder printer - //! select filament in case of MMU_V2 - //! if extruder is "?", open menu to let the user select extruder/filament - //! - //! For MMU_V2: - //! @n T Gcode to extrude must follow immediately to load to extruder wheels - //! @n T? Gcode to extrude doesn't have to follow, load to extruder wheels is done automatically - else if(code_seen('T')) - { - int index; - bool load_to_nozzle = false; - for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++); - - *(strchr_pointer + index) = tolower(*(strchr_pointer + index)); - - if ((*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '4') && *(strchr_pointer + index) != '?' && *(strchr_pointer + index) != 'x' && *(strchr_pointer + index) != 'c') { - SERIAL_ECHOLNPGM("Invalid T code."); - } - else if (*(strchr_pointer + index) == 'x'){ //load to bondtech gears; if mmu is not present do nothing - if (mmu_enabled) - { - tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_FILAMENT), _T(MSG_FILAMENT)); - st_synchronize(); - mmu_command(MMU_CMD_T0 + tmp_extruder); - manage_response(true, true); - } - } - else if (*(strchr_pointer + index) == 'c') { //load to from bondtech gears to nozzle (nozzle should be preheated) - if (mmu_enabled) - { - st_synchronize(); - delay(1500); - mmu_command(MMU_CMD_C0); - mmu_extruder = tmp_extruder; //filament change is finished - mmu_load_to_nozzle(); - } - } - else { - if (*(strchr_pointer + index) == '?') - { - if(mmu_enabled) - { - tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_FILAMENT), _T(MSG_FILAMENT)); - load_to_nozzle = true; - } else - { - tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_EXTRUDER), _T(MSG_EXTRUDER)); - } - } - else { - tmp_extruder = code_value(); - } - st_synchronize(); - snmm_filaments_used |= (1 << tmp_extruder); //for stop print - - if (mmu_enabled) - { - mmu_command(MMU_CMD_T0 + tmp_extruder); - - manage_response(true, true); - delay(1500); - mmu_command(MMU_CMD_C0); - mmu_extruder = tmp_extruder; //filament change is finished - - if (load_to_nozzle)// for single material usage with mmu - { - mmu_load_to_nozzle(); - } - } - else - { -#ifdef SNMM + mcode_in_progress = 0; + } + } + // end if(code_seen('M')) (end of M codes) + //! T - select extruder in case of multi extruder printer + //! select filament in case of MMU_V2 + //! if extruder is "?", open menu to let the user select extruder/filament + //! + //! For MMU_V2: + //! @n T Gcode to extrude must follow immediately to load to extruder wheels + //! @n T? Gcode to extrude doesn't have to follow, load to extruder wheels is done automatically + else if(code_seen('T')) + { + int index; + bool load_to_nozzle = false; + for (index = 1; *(strchr_pointer + index) == ' ' || *(strchr_pointer + index) == '\t'; index++); -#ifdef LIN_ADVANCE - if (mmu_extruder != tmp_extruder) - clear_current_adv_vars(); //Check if the selected extruder is not the active one and reset LIN_ADVANCE variables if so. -#endif + *(strchr_pointer + index) = tolower(*(strchr_pointer + index)); + + if ((*(strchr_pointer + index) < '0' || *(strchr_pointer + index) > '4') && *(strchr_pointer + index) != '?' && *(strchr_pointer + index) != 'x' && *(strchr_pointer + index) != 'c') { + SERIAL_ECHOLNPGM("Invalid T code."); + } + else if (*(strchr_pointer + index) == 'x') { //load to bondtech gears; if mmu is not present do nothing + if (mmu_enabled) + { + tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_FILAMENT), _T(MSG_FILAMENT)); + st_synchronize(); + mmu_command(MMU_CMD_T0 + tmp_extruder); + manage_response(true, true); + } + } + else if (*(strchr_pointer + index) == 'c') { //load to from bondtech gears to nozzle (nozzle should be preheated) + if (mmu_enabled) + { + st_synchronize(); + mmu_command(MMU_CMD_C0); + mmu_extruder = tmp_extruder; //filament change is finished + mmu_load_to_nozzle(); + } + } + else { + if (*(strchr_pointer + index) == '?') + { + if(mmu_enabled) + { + tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_FILAMENT), _T(MSG_FILAMENT)); + load_to_nozzle = true; + } else + { + tmp_extruder = choose_menu_P(_T(MSG_CHOOSE_EXTRUDER), _T(MSG_EXTRUDER)); + } + } + else { + tmp_extruder = code_value(); + } + st_synchronize(); + snmm_filaments_used |= (1 << tmp_extruder); //for stop print - mmu_extruder = tmp_extruder; + if (mmu_enabled) + { + mmu_command(MMU_CMD_T0 + tmp_extruder); + manage_response(true, true); + mmu_command(MMU_CMD_C0); + mmu_extruder = tmp_extruder; //filament change is finished - delay(100); + if (load_to_nozzle)// for single material usage with mmu + { + mmu_load_to_nozzle(); + } + } + else + { +#ifdef SNMM - disable_e0(); - disable_e1(); - disable_e2(); +#ifdef LIN_ADVANCE + if (mmu_extruder != tmp_extruder) + clear_current_adv_vars(); //Check if the selected extruder is not the active one and reset LIN_ADVANCE variables if so. +#endif - pinMode(E_MUX0_PIN, OUTPUT); - pinMode(E_MUX1_PIN, OUTPUT); + mmu_extruder = tmp_extruder; - delay(100); - SERIAL_ECHO_START; - SERIAL_ECHO("T:"); - SERIAL_ECHOLN((int)tmp_extruder); - switch (tmp_extruder) { - case 1: - WRITE(E_MUX0_PIN, HIGH); - WRITE(E_MUX1_PIN, LOW); - break; - case 2: - WRITE(E_MUX0_PIN, LOW); - WRITE(E_MUX1_PIN, HIGH); + delay(100); - break; - case 3: - WRITE(E_MUX0_PIN, HIGH); - WRITE(E_MUX1_PIN, HIGH); + disable_e0(); + disable_e1(); + disable_e2(); - break; - default: - WRITE(E_MUX0_PIN, LOW); - WRITE(E_MUX1_PIN, LOW); + pinMode(E_MUX0_PIN, OUTPUT); + pinMode(E_MUX1_PIN, OUTPUT); - break; - } - delay(100); + delay(100); + SERIAL_ECHO_START; + SERIAL_ECHO("T:"); + SERIAL_ECHOLN((int)tmp_extruder); + switch (tmp_extruder) { + case 1: + WRITE(E_MUX0_PIN, HIGH); + WRITE(E_MUX1_PIN, LOW); + + break; + case 2: + WRITE(E_MUX0_PIN, LOW); + WRITE(E_MUX1_PIN, HIGH); + + break; + case 3: + WRITE(E_MUX0_PIN, HIGH); + WRITE(E_MUX1_PIN, HIGH); + + break; + default: + WRITE(E_MUX0_PIN, LOW); + WRITE(E_MUX1_PIN, LOW); + + break; + } + delay(100); #else //SNMM - if (tmp_extruder >= EXTRUDERS) { - SERIAL_ECHO_START; - SERIAL_ECHOPGM("T"); - SERIAL_PROTOCOLLN((int)tmp_extruder); - SERIAL_ECHOLNRPGM(_n("Invalid extruder"));////MSG_INVALID_EXTRUDER c=0 r=0 - } - else { + if (tmp_extruder >= EXTRUDERS) { + SERIAL_ECHO_START; + SERIAL_ECHOPGM("T"); + SERIAL_PROTOCOLLN((int)tmp_extruder); + SERIAL_ECHOLNRPGM(_n("Invalid extruder"));////MSG_INVALID_EXTRUDER c=0 r=0 + } + else { #if EXTRUDERS > 1 - boolean make_move = false; + boolean make_move = false; #endif - if (code_seen('F')) { + if (code_seen('F')) { #if EXTRUDERS > 1 - make_move = true; + make_move = true; #endif - next_feedrate = code_value(); - if (next_feedrate > 0.0) { - feedrate = next_feedrate; - } - } + next_feedrate = code_value(); + if (next_feedrate > 0.0) { + feedrate = next_feedrate; + } + } #if EXTRUDERS > 1 - if (tmp_extruder != active_extruder) { - // Save current position to return to after applying extruder offset - memcpy(destination, current_position, sizeof(destination)); - // Offset extruder (only by XY) - int i; - for (i = 0; i < 2; i++) { - current_position[i] = current_position[i] - - extruder_offset[i][active_extruder] + - extruder_offset[i][tmp_extruder]; - } - // Set the new active extruder and position - active_extruder = tmp_extruder; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - // Move to the old position if 'F' was in the parameters - if (make_move && Stopped == false) { - prepare_move(); - } - } -#endif - SERIAL_ECHO_START; - SERIAL_ECHORPGM(_n("Active Extruder: "));////MSG_ACTIVE_EXTRUDER c=0 r=0 - SERIAL_PROTOCOLLN((int)active_extruder); - } + if (tmp_extruder != active_extruder) { + // Save current position to return to after applying extruder offset + memcpy(destination, current_position, sizeof(destination)); + // Offset extruder (only by XY) + int i; + for (i = 0; i < 2; i++) { + current_position[i] = current_position[i] - + extruder_offset[i][active_extruder] + + extruder_offset[i][tmp_extruder]; + } + // Set the new active extruder and position + active_extruder = tmp_extruder; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + // Move to the old position if 'F' was in the parameters + if (make_move && Stopped == false) { + prepare_move(); + } + } +#endif + SERIAL_ECHO_START; + SERIAL_ECHORPGM(_n("Active Extruder: "));////MSG_ACTIVE_EXTRUDER c=0 r=0 + SERIAL_PROTOCOLLN((int)active_extruder); + } #endif //SNMM - } - } - } // end if(code_seen('T')) (end of T codes) + } + } + } // end if(code_seen('T')) (end of T codes) - else if (code_seen('D')) // D codes (debug) - { - switch((int)code_value()) + else if (code_seen('D')) // D codes (debug) { + switch((int)code_value()) + { #ifdef DEBUG_DCODES - case -1: //! D-1 - Endless loop - dcode__1(); break; - case 0: //! D0 - Reset - dcode_0(); break; - case 1: //! D1 - Clear EEPROM - dcode_1(); break; - case 2: //! D2 - Read/Write RAM - dcode_2(); break; + case -1: //! D-1 - Endless loop + dcode__1(); + break; + case 0: //! D0 - Reset + dcode_0(); + break; + case 1: //! D1 - Clear EEPROM + dcode_1(); + break; + case 2: //! D2 - Read/Write RAM + dcode_2(); + break; #endif //DEBUG_DCODES #ifdef DEBUG_DCODE3 - case 3: //! D3 - Read/Write EEPROM - dcode_3(); break; + case 3: //! D3 - Read/Write EEPROM + dcode_3(); + break; #endif //DEBUG_DCODE3 #ifdef DEBUG_DCODES - case 4: //! D4 - Read/Write PIN - dcode_4(); break; + case 4: //! D4 - Read/Write PIN + dcode_4(); + break; #endif //DEBUG_DCODES #ifdef DEBUG_DCODE5 - case 5: // D5 - Read/Write FLASH - dcode_5(); break; - break; + case 5: // D5 - Read/Write FLASH + dcode_5(); + break; + break; #endif //DEBUG_DCODE5 #ifdef DEBUG_DCODES - case 6: // D6 - Read/Write external FLASH - dcode_6(); break; - case 7: //! D7 - Read/Write Bootloader - dcode_7(); break; - case 8: //! D8 - Read/Write PINDA - dcode_8(); break; - case 9: //! D9 - Read/Write ADC - dcode_9(); break; - - case 10: //! D10 - XYZ calibration = OK - dcode_10(); break; - + case 6: // D6 - Read/Write external FLASH + dcode_6(); + break; + case 7: //! D7 - Read/Write Bootloader + dcode_7(); + break; + case 8: //! D8 - Read/Write PINDA + dcode_8(); + break; + case 9: //! D9 - Read/Write ADC + dcode_9(); + break; + + case 10: //! D10 - XYZ calibration = OK + dcode_10(); + break; + #ifdef TMC2130 - case 2130: //! D2130 - TMC2130 - dcode_2130(); break; + case 2130: //! D2130 - TMC2130 + dcode_2130(); + break; #endif //TMC2130 #ifdef FILAMENT_SENSOR - case 9125: //! D9125 - FILAMENT_SENSOR - dcode_9125(); break; + case 9125: //! D9125 - FILAMENT_SENSOR + dcode_9125(); + break; #endif //FILAMENT_SENSOR -#endif //DEBUG_DCODES - } - } +#endif //DEBUG_DCODES + } + } - else - { - SERIAL_ECHO_START; - SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); - SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); - SERIAL_ECHOLNPGM("\"(2)"); - } - KEEPALIVE_STATE(NOT_BUSY); - ClearToSend(); + else + { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(MSG_UNKNOWN_COMMAND); + SERIAL_ECHO(CMDBUFFER_CURRENT_STRING); + SERIAL_ECHOLNPGM("\"(2)"); + } + KEEPALIVE_STATE(NOT_BUSY); + ClearToSend(); } void FlushSerialRequestResend() { - //char cmdbuffer[bufindr][100]="Resend:"; - MYSERIAL.flush(); - printf_P(_N("%S: %ld\n%S\n"), _i("Resend"), gcode_LastN + 1, _T(MSG_OK)); + //char cmdbuffer[bufindr][100]="Resend:"; + MYSERIAL.flush(); + printf_P(_N("%S: %ld\n%S\n"), _i("Resend"), gcode_LastN + 1, _T(MSG_OK)); } // Confirm the execution of a command, if sent from a serial line. @@ -7090,130 +7181,130 @@ void FlushSerialRequestResend() void ClearToSend() { previous_millis_cmd = millis(); - if ((CMDBUFFER_CURRENT_TYPE == CMDBUFFER_CURRENT_TYPE_USB) || (CMDBUFFER_CURRENT_TYPE == CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR)) - SERIAL_PROTOCOLLNRPGM(_T(MSG_OK)); + if ((CMDBUFFER_CURRENT_TYPE == CMDBUFFER_CURRENT_TYPE_USB) || (CMDBUFFER_CURRENT_TYPE == CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR)) + SERIAL_PROTOCOLLNRPGM(_T(MSG_OK)); } #if MOTHERBOARD == BOARD_RAMBO_MINI_1_0 || MOTHERBOARD == BOARD_RAMBO_MINI_1_3 void update_currents() { - float current_high[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; - float current_low[3] = DEFAULT_PWM_MOTOR_CURRENT; - float tmp_motor[3]; - - //SERIAL_ECHOLNPGM("Currents updated: "); - - if (destination[Z_AXIS] < Z_SILENT) { - //SERIAL_ECHOLNPGM("LOW"); - for (uint8_t i = 0; i < 3; i++) { - st_current_set(i, current_low[i]); - /*MYSERIAL.print(int(i)); - SERIAL_ECHOPGM(": "); - MYSERIAL.println(current_low[i]);*/ - } - } - else if (destination[Z_AXIS] > Z_HIGH_POWER) { - //SERIAL_ECHOLNPGM("HIGH"); - for (uint8_t i = 0; i < 3; i++) { - st_current_set(i, current_high[i]); - /*MYSERIAL.print(int(i)); - SERIAL_ECHOPGM(": "); - MYSERIAL.println(current_high[i]);*/ - } - } - else { - for (uint8_t i = 0; i < 3; i++) { - float q = current_low[i] - Z_SILENT*((current_high[i] - current_low[i]) / (Z_HIGH_POWER - Z_SILENT)); - tmp_motor[i] = ((current_high[i] - current_low[i]) / (Z_HIGH_POWER - Z_SILENT))*destination[Z_AXIS] + q; - st_current_set(i, tmp_motor[i]); - /*MYSERIAL.print(int(i)); - SERIAL_ECHOPGM(": "); - MYSERIAL.println(tmp_motor[i]);*/ - } - } + float current_high[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; + float current_low[3] = DEFAULT_PWM_MOTOR_CURRENT; + float tmp_motor[3]; + + //SERIAL_ECHOLNPGM("Currents updated: "); + + if (destination[Z_AXIS] < Z_SILENT) { + //SERIAL_ECHOLNPGM("LOW"); + for (uint8_t i = 0; i < 3; i++) { + st_current_set(i, current_low[i]); + /*MYSERIAL.print(int(i)); + SERIAL_ECHOPGM(": "); + MYSERIAL.println(current_low[i]);*/ + } + } + else if (destination[Z_AXIS] > Z_HIGH_POWER) { + //SERIAL_ECHOLNPGM("HIGH"); + for (uint8_t i = 0; i < 3; i++) { + st_current_set(i, current_high[i]); + /*MYSERIAL.print(int(i)); + SERIAL_ECHOPGM(": "); + MYSERIAL.println(current_high[i]);*/ + } + } + else { + for (uint8_t i = 0; i < 3; i++) { + float q = current_low[i] - Z_SILENT*((current_high[i] - current_low[i]) / (Z_HIGH_POWER - Z_SILENT)); + tmp_motor[i] = ((current_high[i] - current_low[i]) / (Z_HIGH_POWER - Z_SILENT))*destination[Z_AXIS] + q; + st_current_set(i, tmp_motor[i]); + /*MYSERIAL.print(int(i)); + SERIAL_ECHOPGM(": "); + MYSERIAL.println(tmp_motor[i]);*/ + } + } } #endif //MOTHERBOARD == BOARD_RAMBO_MINI_1_0 || MOTHERBOARD == BOARD_RAMBO_MINI_1_3 void get_coordinates() { - bool seen[4]={false,false,false,false}; - for(int8_t i=0; i < NUM_AXIS; i++) { - if(code_seen(axis_codes[i])) - { - bool relative = axis_relative_modes[i] || relative_mode; - destination[i] = (float)code_value(); - if (i == E_AXIS) { - float emult = extruder_multiplier[active_extruder]; - if (emult != 1.) { - if (! relative) { - destination[i] -= current_position[i]; - relative = true; - } - destination[i] *= emult; - } - } - if (relative) - destination[i] += current_position[i]; - seen[i]=true; + bool seen[4]= {false,false,false,false}; + for(int8_t i=0; i < NUM_AXIS; i++) { + if(code_seen(axis_codes[i])) + { + bool relative = axis_relative_modes[i] || relative_mode; + destination[i] = (float)code_value(); + if (i == E_AXIS) { + float emult = extruder_multiplier[active_extruder]; + if (emult != 1.) { + if (! relative) { + destination[i] -= current_position[i]; + relative = true; + } + destination[i] *= emult; + } + } + if (relative) + destination[i] += current_position[i]; + seen[i]=true; #if MOTHERBOARD == BOARD_RAMBO_MINI_1_0 || MOTHERBOARD == BOARD_RAMBO_MINI_1_3 - if (i == Z_AXIS && SilentModeMenu == SILENT_MODE_AUTO) update_currents(); + if (i == Z_AXIS && SilentModeMenu == SILENT_MODE_AUTO) update_currents(); #endif //MOTHERBOARD == BOARD_RAMBO_MINI_1_0 || MOTHERBOARD == BOARD_RAMBO_MINI_1_3 + } + else destination[i] = current_position[i]; //Are these else lines really needed? } - else destination[i] = current_position[i]; //Are these else lines really needed? - } - if(code_seen('F')) { - next_feedrate = code_value(); + if(code_seen('F')) { + next_feedrate = code_value(); #ifdef MAX_SILENT_FEEDRATE - if (tmc2130_mode == TMC2130_MODE_SILENT) - if (next_feedrate > MAX_SILENT_FEEDRATE) next_feedrate = MAX_SILENT_FEEDRATE; + if (tmc2130_mode == TMC2130_MODE_SILENT) + if (next_feedrate > MAX_SILENT_FEEDRATE) next_feedrate = MAX_SILENT_FEEDRATE; #endif //MAX_SILENT_FEEDRATE - if(next_feedrate > 0.0) feedrate = next_feedrate; - if (!seen[0] && !seen[1] && !seen[2] && seen[3]) - { -// float e_max_speed = + if(next_feedrate > 0.0) feedrate = next_feedrate; + if (!seen[0] && !seen[1] && !seen[2] && seen[3]) + { +// float e_max_speed = // printf_P(PSTR("E MOVE speed %7.3f\n"), feedrate / 60) - } - } + } + } } void get_arc_coordinates() { #ifdef SF_ARC_FIX - bool relative_mode_backup = relative_mode; - relative_mode = true; + bool relative_mode_backup = relative_mode; + relative_mode = true; #endif - get_coordinates(); + get_coordinates(); #ifdef SF_ARC_FIX - relative_mode=relative_mode_backup; -#endif - - if(code_seen('I')) { - offset[0] = code_value(); - } - else { - offset[0] = 0.0; - } - if(code_seen('J')) { - offset[1] = code_value(); - } - else { - offset[1] = 0.0; - } + relative_mode=relative_mode_backup; +#endif + + if(code_seen('I')) { + offset[0] = code_value(); + } + else { + offset[0] = 0.0; + } + if(code_seen('J')) { + offset[1] = code_value(); + } + else { + offset[1] = 0.0; + } } void clamp_to_software_endstops(float target[3]) { #ifdef DEBUG_DISABLE_SWLIMITS - return; + return; #endif //DEBUG_DISABLE_SWLIMITS world2machine_clamp(target[0], target[1]); // Clamp the Z coordinate. if (min_software_endstops) { float negative_z_offset = 0; - #ifdef ENABLE_AUTO_BED_LEVELING - if (Z_PROBE_OFFSET_FROM_EXTRUDER < 0) negative_z_offset = negative_z_offset + Z_PROBE_OFFSET_FROM_EXTRUDER; - if (cs.add_homing[Z_AXIS] < 0) negative_z_offset = negative_z_offset + cs.add_homing[Z_AXIS]; - #endif +#ifdef ENABLE_AUTO_BED_LEVELING + if (Z_PROBE_OFFSET_FROM_EXTRUDER < 0) negative_z_offset = negative_z_offset + Z_PROBE_OFFSET_FROM_EXTRUDER; + if (cs.add_homing[Z_AXIS] < 0) negative_z_offset = negative_z_offset + cs.add_homing[Z_AXIS]; +#endif if (target[Z_AXIS] < min_pos[Z_AXIS]+negative_z_offset) target[Z_AXIS] = min_pos[Z_AXIS]+negative_z_offset; } if (max_software_endstops) { @@ -7222,84 +7313,84 @@ void clamp_to_software_endstops(float target[3]) } #ifdef MESH_BED_LEVELING - void mesh_plan_buffer_line(const float &x, const float &y, const float &z, const float &e, const float &feed_rate, const uint8_t extruder) { - float dx = x - current_position[X_AXIS]; - float dy = y - current_position[Y_AXIS]; - float dz = z - current_position[Z_AXIS]; - int n_segments = 0; - - if (mbl.active) { - float len = abs(dx) + abs(dy); - if (len > 0) - // Split to 3cm segments or shorter. - n_segments = int(ceil(len / 30.f)); - } - - if (n_segments > 1) { - float de = e - current_position[E_AXIS]; - for (int i = 1; i < n_segments; ++ i) { - float t = float(i) / float(n_segments); - if (saved_printing || (mbl.active == false)) return; - plan_buffer_line( - current_position[X_AXIS] + t * dx, - current_position[Y_AXIS] + t * dy, - current_position[Z_AXIS] + t * dz, - current_position[E_AXIS] + t * de, - feed_rate, extruder); - } +void mesh_plan_buffer_line(const float &x, const float &y, const float &z, const float &e, const float &feed_rate, const uint8_t extruder) { + float dx = x - current_position[X_AXIS]; + float dy = y - current_position[Y_AXIS]; + float dz = z - current_position[Z_AXIS]; + int n_segments = 0; + + if (mbl.active) { + float len = abs(dx) + abs(dy); + if (len > 0) + // Split to 3cm segments or shorter. + n_segments = int(ceil(len / 30.f)); + } + + if (n_segments > 1) { + float de = e - current_position[E_AXIS]; + for (int i = 1; i < n_segments; ++ i) { + float t = float(i) / float(n_segments); + if (saved_printing || (mbl.active == false)) return; + plan_buffer_line( + current_position[X_AXIS] + t * dx, + current_position[Y_AXIS] + t * dy, + current_position[Z_AXIS] + t * dz, + current_position[E_AXIS] + t * de, + feed_rate, extruder); } - // The rest of the path. - plan_buffer_line(x, y, z, e, feed_rate, extruder); - current_position[X_AXIS] = x; - current_position[Y_AXIS] = y; - current_position[Z_AXIS] = z; - current_position[E_AXIS] = e; } + // The rest of the path. + plan_buffer_line(x, y, z, e, feed_rate, extruder); + current_position[X_AXIS] = x; + current_position[Y_AXIS] = y; + current_position[Z_AXIS] = z; + current_position[E_AXIS] = e; +} #endif // MESH_BED_LEVELING - + void prepare_move() { - clamp_to_software_endstops(destination); - previous_millis_cmd = millis(); + clamp_to_software_endstops(destination); + previous_millis_cmd = millis(); - // 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); - } - else { + // 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); + } + else { #ifdef MESH_BED_LEVELING - mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply*(1./(60.f*100.f)), active_extruder); + mesh_plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply*(1./(60.f*100.f)), active_extruder); #else - plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply*(1./(60.f*100.f)), active_extruder); + plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply*(1./(60.f*100.f)), active_extruder); #endif - } + } - for(int8_t i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } + for(int8_t i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } } void prepare_arc_move(char isclockwise) { - float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc + float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc - // Trace the arc - mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60/100.0, r, isclockwise, active_extruder); + // Trace the arc + mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60/100.0, r, isclockwise, active_extruder); - // As far as the parser is concerned, the position is now == target. In reality the - // motion control system might still be processing the action and the real tool position - // in any intermediate location. - for(int8_t i=0; i < NUM_AXIS; i++) { - current_position[i] = destination[i]; - } - previous_millis_cmd = millis(); + // As far as the parser is concerned, the position is now == target. In reality the + // motion control system might still be processing the action and the real tool position + // in any intermediate location. + for(int8_t i=0; i < NUM_AXIS; i++) { + current_position[i] = destination[i]; + } + previous_millis_cmd = millis(); } #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 #if defined(FAN_PIN) - #if CONTROLLERFAN_PIN == FAN_PIN - #error "You cannot set CONTROLLERFAN_PIN equal to FAN_PIN" - #endif +#if CONTROLLERFAN_PIN == FAN_PIN +#error "You cannot set CONTROLLERFAN_PIN equal to FAN_PIN" +#endif #endif unsigned long lastMotor = 0; //Save the time for when a motor was turned on last @@ -7307,37 +7398,37 @@ unsigned long lastMotorCheck = 0; void controllerFan() { - if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms - { - lastMotorCheck = millis(); - - 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 - #if EXTRUDER > 1 - #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 - || !READ(X2_ENABLE_PIN) - #endif - || !READ(E1_ENABLE_PIN) - #endif - || !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled... + if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms { - lastMotor = millis(); //... set time to NOW so the fan will turn on - } + lastMotorCheck = millis(); - 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); - } - else - { - // allows digital or PWM fan output to be used (see M42 handling) - digitalWrite(CONTROLLERFAN_PIN, CONTROLLERFAN_SPEED); - analogWrite(CONTROLLERFAN_PIN, CONTROLLERFAN_SPEED); + 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 +#if EXTRUDER > 1 +#if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 + || !READ(X2_ENABLE_PIN) +#endif + || !READ(E1_ENABLE_PIN) +#endif + || !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled... + { + 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... + { + 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); + } } - } } #endif @@ -7347,30 +7438,30 @@ 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; + 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 @@ -7409,260 +7500,262 @@ static void handleSafetyTimer() void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument set in Marlin.h { #ifdef FILAMENT_SENSOR - if (mmu_enabled == false) - { - if (mcode_in_progress != 600) //M600 not in progress - { - if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL) && !wizard_active) - { - if (fsensor_check_autoload()) - { - fsensor_autoload_check_stop(); - if (degHotend0() > EXTRUDE_MINTEMP) - { - if ((eSoundMode == e_SOUND_MODE_LOUD) || (eSoundMode == e_SOUND_MODE_ONCE)) - tone(BEEPER, 1000); - delay_keep_alive(50); - noTone(BEEPER); - loading_flag = true; - enquecommand_front_P((PSTR("M701"))); - } - else - { - lcd_update_enable(false); - show_preheat_nozzle_warning(); - lcd_update_enable(true); - } - } - } - else - { - fsensor_autoload_check_stop(); - fsensor_update(); - } - } - } else { - if ((lcd_commands_type != LCD_COMMAND_V2_CAL) && !wizard_active && mmuFSensorLoading) { + if (mmu_enabled == false) + { + if (mcode_in_progress != 600) //M600 not in progress + { + if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL) && !wizard_active) + { + if (fsensor_check_autoload()) + { + fsensor_autoload_check_stop(); + if (degHotend0() > EXTRUDE_MINTEMP) + { + if ((eSoundMode == e_SOUND_MODE_LOUD) || (eSoundMode == e_SOUND_MODE_ONCE)) + tone(BEEPER, 1000); + delay_keep_alive(50); + noTone(BEEPER); + loading_flag = true; + enquecommand_front_P((PSTR("M701"))); + } + else + { + lcd_update_enable(false); + show_preheat_nozzle_warning(); + lcd_update_enable(true); + } + } + } + else + { + fsensor_autoload_check_stop(); + fsensor_update(); + } + } + } else { + if (mmuFSensorLoading) { fsensor_check_autoload(); } - } + } #endif //FILAMENT_SENSOR #ifdef SAFETYTIMER - handleSafetyTimer(); + handleSafetyTimer(); #endif //SAFETYTIMER #if defined(KILL_PIN) && KILL_PIN > -1 - static int killCount = 0; // make the inactivity button a bit less responsive - const int KILL_DELAY = 10000; + static int killCount = 0; // make the inactivity button a bit less responsive + const int KILL_DELAY = 10000; #endif - - if(buflen < (BUFSIZE-1)){ + + if(buflen < (BUFSIZE-1)) { get_command(); } - if( (millis() - previous_millis_cmd) > max_inactive_time ) - if(max_inactive_time) - kill(_n(""), 4); - if(stepper_inactive_time) { - if( (millis() - previous_millis_cmd) > stepper_inactive_time ) - { - if(blocks_queued() == false && ignore_stepper_queue == false) { - disable_x(); - disable_y(); - disable_z(); - disable_e0(); - disable_e1(); - disable_e2(); - } + if( (millis() - previous_millis_cmd) > max_inactive_time ) + if(max_inactive_time) + kill(_n(""), 4); + if(stepper_inactive_time) { + if( (millis() - previous_millis_cmd) > stepper_inactive_time ) + { + if(blocks_queued() == false && ignore_stepper_queue == false) { + disable_x(); + disable_y(); + disable_z(); + disable_e0(); + disable_e1(); + disable_e2(); + } + } } - } - - #ifdef CHDK //Check if pin should be set to LOW after M240 set it to HIGH + +#ifdef CHDK //Check if pin should be set to LOW after M240 set it to HIGH if (chdkActive && (millis() - chdkHigh > CHDK_DELAY)) { - chdkActive = false; - WRITE(CHDK, LOW); + chdkActive = false; + WRITE(CHDK, LOW); } - #endif - - #if defined(KILL_PIN) && KILL_PIN > -1 - +#endif + +#if defined(KILL_PIN) && KILL_PIN > -1 + // Check if the kill button was pressed and wait just in case it was an accidental // key kill key press // ------------------------------------------------------------------------------- if( 0 == READ(KILL_PIN) ) { - killCount++; + killCount++; } else if (killCount > 0) { - killCount--; + killCount--; } // Exceeded threshold and we can confirm that it was not accidental // KILL the machine // ---------------------------------------------------------------- if ( killCount >= KILL_DELAY) { - kill("", 5); + kill("", 5); } - #endif - - #if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 +#endif + +#if defined(CONTROLLERFAN_PIN) && CONTROLLERFAN_PIN > -1 controllerFan(); //Check if fan should be turned on to cool stepper drivers down - #endif - #ifdef EXTRUDER_RUNOUT_PREVENT +#endif +#ifdef EXTRUDER_RUNOUT_PREVENT if( (millis() - previous_millis_cmd) > EXTRUDER_RUNOUT_SECONDS*1000 ) - if(degHotend(active_extruder)>EXTRUDER_RUNOUT_MINTEMP) - { - bool oldstatus=READ(E0_ENABLE_PIN); - 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/cs.axis_steps_per_unit[E_AXIS], - EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/cs.axis_steps_per_unit[E_AXIS], active_extruder); - 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); - } - #endif - #ifdef TEMP_STAT_LEDS - handle_status_leds(); - #endif - check_axes_activity(); - mmu_loop(); + if(degHotend(active_extruder)>EXTRUDER_RUNOUT_MINTEMP) + { + bool oldstatus=READ(E0_ENABLE_PIN); + 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/cs.axis_steps_per_unit[E_AXIS], + EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/cs.axis_steps_per_unit[E_AXIS], active_extruder); + 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); + } +#endif +#ifdef TEMP_STAT_LEDS + handle_status_leds(); +#endif + check_axes_activity(); + mmu_loop(); } void kill(const char *full_screen_message, unsigned char id) { - printf_P(_N("KILL: %d\n"), id); - //return; - cli(); // Stop interrupts - disable_heater(); + printf_P(_N("KILL: %d\n"), id); + //return; + cli(); // Stop interrupts + disable_heater(); - disable_x(); + disable_x(); // SERIAL_ECHOLNPGM("kill - disable Y"); - disable_y(); - disable_z(); - disable_e0(); - disable_e1(); - disable_e2(); + disable_y(); + disable_z(); + disable_e0(); + disable_e1(); + disable_e2(); #if defined(PS_ON_PIN) && PS_ON_PIN > -1 - pinMode(PS_ON_PIN,INPUT); -#endif - SERIAL_ERROR_START; - SERIAL_ERRORLNRPGM(_i("Printer halted. kill() called!"));////MSG_ERR_KILLED c=0 r=0 - if (full_screen_message != NULL) { - SERIAL_ERRORLNRPGM(full_screen_message); - lcd_display_message_fullscreen_P(full_screen_message); - } else { - LCD_ALERTMESSAGERPGM(_i("KILLED. "));////MSG_KILLED c=0 r=0 - } + pinMode(PS_ON_PIN,INPUT); +#endif + SERIAL_ERROR_START; + SERIAL_ERRORLNRPGM(_i("Printer halted. kill() called!"));////MSG_ERR_KILLED c=0 r=0 + if (full_screen_message != NULL) { + SERIAL_ERRORLNRPGM(full_screen_message); + lcd_display_message_fullscreen_P(full_screen_message); + } else { + LCD_ALERTMESSAGERPGM(_i("KILLED. "));////MSG_KILLED c=0 r=0 + } - // FMC small patch to update the LCD before ending - sei(); // enable interrupts - for ( int i=5; i--; lcd_update(0)) - { - delay(200); - } - cli(); // disable interrupts - suicide(); - while(1) - { + // FMC small patch to update the LCD before ending + sei(); // enable interrupts + for ( int i=5; i--; lcd_update(0)) + { + delay(200); + } + cli(); // disable interrupts + suicide(); + while(1) + { #ifdef WATCHDOG - wdt_reset(); + wdt_reset(); #endif //WATCHDOG - /* Intentionally left empty */ - - } // Wait for reset + /* Intentionally left empty */ + + } // Wait for reset } void Stop() { - disable_heater(); - if(Stopped == false) { - Stopped = true; - Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart - SERIAL_ERROR_START; - SERIAL_ERRORLNRPGM(_T(MSG_ERR_STOPPED)); - LCD_MESSAGERPGM(_T(MSG_STOPPED)); - } + disable_heater(); + if(Stopped == false) { + Stopped = true; + Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart + SERIAL_ERROR_START; + SERIAL_ERRORLNRPGM(_T(MSG_ERR_STOPPED)); + LCD_MESSAGERPGM(_T(MSG_STOPPED)); + } } -bool IsStopped() { return Stopped; }; +bool IsStopped() { + return Stopped; +}; #ifdef FAST_PWM_FAN void setPwmFrequency(uint8_t pin, int val) { - val &= 0x07; - switch(digitalPinToTimer(pin)) - { + val &= 0x07; + switch(digitalPinToTimer(pin)) + { - #if defined(TCCR0A) +#if defined(TCCR0A) case TIMER0A: case TIMER0B: // TCCR0B &= ~(_BV(CS00) | _BV(CS01) | _BV(CS02)); // TCCR0B |= val; - break; - #endif + break; +#endif - #if defined(TCCR1A) +#if defined(TCCR1A) case TIMER1A: case TIMER1B: // TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // TCCR1B |= val; - break; - #endif + break; +#endif - #if defined(TCCR2) +#if defined(TCCR2) case TIMER2: case TIMER2: - TCCR2 &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); - TCCR2 |= val; - break; - #endif + TCCR2 &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); + TCCR2 |= val; + break; +#endif - #if defined(TCCR2A) +#if defined(TCCR2A) case TIMER2A: case TIMER2B: - TCCR2B &= ~(_BV(CS20) | _BV(CS21) | _BV(CS22)); - TCCR2B |= val; - break; - #endif + TCCR2B &= ~(_BV(CS20) | _BV(CS21) | _BV(CS22)); + TCCR2B |= val; + break; +#endif - #if defined(TCCR3A) +#if defined(TCCR3A) case TIMER3A: case TIMER3B: case TIMER3C: - TCCR3B &= ~(_BV(CS30) | _BV(CS31) | _BV(CS32)); - TCCR3B |= val; - break; - #endif + TCCR3B &= ~(_BV(CS30) | _BV(CS31) | _BV(CS32)); + TCCR3B |= val; + break; +#endif - #if defined(TCCR4A) +#if defined(TCCR4A) case TIMER4A: case TIMER4B: case TIMER4C: - TCCR4B &= ~(_BV(CS40) | _BV(CS41) | _BV(CS42)); - TCCR4B |= val; - break; - #endif + TCCR4B &= ~(_BV(CS40) | _BV(CS41) | _BV(CS42)); + TCCR4B |= val; + break; +#endif - #if defined(TCCR5A) +#if defined(TCCR5A) case TIMER5A: case TIMER5B: case TIMER5C: - TCCR5B &= ~(_BV(CS50) | _BV(CS51) | _BV(CS52)); - TCCR5B |= val; - break; - #endif + TCCR5B &= ~(_BV(CS50) | _BV(CS51) | _BV(CS52)); + TCCR5B |= val; + break; +#endif - } + } } #endif //FAST_PWM_FAN @@ -7677,70 +7770,70 @@ void setPwmFrequency(uint8_t pin, int val) bool setTargetedHotend(int code, uint8_t &extruder) { - extruder = active_extruder; - if(code_seen('T')) { - extruder = code_value(); - if(extruder >= EXTRUDERS) { - SERIAL_ECHO_START; - switch(code){ - case 104: - SERIAL_ECHORPGM(_i("M104 Invalid extruder "));////MSG_M104_INVALID_EXTRUDER c=0 r=0 - break; - case 105: - SERIAL_ECHO(_i("M105 Invalid extruder "));////MSG_M105_INVALID_EXTRUDER c=0 r=0 - break; - case 109: - SERIAL_ECHO(_i("M109 Invalid extruder "));////MSG_M109_INVALID_EXTRUDER c=0 r=0 - break; - case 218: - SERIAL_ECHO(_i("M218 Invalid extruder "));////MSG_M218_INVALID_EXTRUDER c=0 r=0 - break; - case 221: - SERIAL_ECHO(_i("M221 Invalid extruder "));////MSG_M221_INVALID_EXTRUDER c=0 r=0 - break; - } - SERIAL_PROTOCOLLN((int)extruder); - return true; + extruder = active_extruder; + if(code_seen('T')) { + extruder = code_value(); + if(extruder >= EXTRUDERS) { + SERIAL_ECHO_START; + switch(code) { + case 104: + SERIAL_ECHORPGM(_i("M104 Invalid extruder "));////MSG_M104_INVALID_EXTRUDER c=0 r=0 + break; + case 105: + SERIAL_ECHO(_i("M105 Invalid extruder "));////MSG_M105_INVALID_EXTRUDER c=0 r=0 + break; + case 109: + SERIAL_ECHO(_i("M109 Invalid extruder "));////MSG_M109_INVALID_EXTRUDER c=0 r=0 + break; + case 218: + SERIAL_ECHO(_i("M218 Invalid extruder "));////MSG_M218_INVALID_EXTRUDER c=0 r=0 + break; + case 221: + SERIAL_ECHO(_i("M221 Invalid extruder "));////MSG_M221_INVALID_EXTRUDER c=0 r=0 + break; + } + SERIAL_PROTOCOLLN((int)extruder); + return true; + } } - } - return false; + return false; } void save_statistics(unsigned long _total_filament_used, unsigned long _total_print_time) //_total_filament_used unit: mm/100; print time in s { - if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255) - { - eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); - eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); - } + if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255) + { + eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); + eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); + } - unsigned long _previous_filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED); //_previous_filament unit: cm - unsigned long _previous_time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //_previous_time unit: min + unsigned long _previous_filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED); //_previous_filament unit: cm + unsigned long _previous_time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //_previous_time unit: min - eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, _previous_time + (_total_print_time/60)); //EEPROM_TOTALTIME unit: min - eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, _previous_filament + (_total_filament_used / 1000)); + eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, _previous_time + (_total_print_time/60)); //EEPROM_TOTALTIME unit: min + eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, _previous_filament + (_total_filament_used / 1000)); - total_filament_used = 0; + total_filament_used = 0; } float calculate_extruder_multiplier(float diameter) { - float out = 1.f; - if (cs.volumetric_enabled && diameter > 0.f) { - float area = M_PI * diameter * diameter * 0.25; - out = 1.f / area; - } - if (extrudemultiply != 100) - out *= float(extrudemultiply) * 0.01f; - return out; + float out = 1.f; + if (cs.volumetric_enabled && diameter > 0.f) { + float area = M_PI * diameter * diameter * 0.25; + out = 1.f / area; + } + if (extrudemultiply != 100) + out *= float(extrudemultiply) * 0.01f; + return out; } void calculate_extruder_multipliers() { - extruder_multiplier[0] = calculate_extruder_multiplier(cs.filament_size[0]); + extruder_multiplier[0] = calculate_extruder_multiplier(cs.filament_size[0]); #if EXTRUDERS > 1 - extruder_multiplier[1] = calculate_extruder_multiplier(cs.filament_size[1]); + extruder_multiplier[1] = calculate_extruder_multiplier(cs.filament_size[1]); #if EXTRUDERS > 2 - extruder_multiplier[2] = calculate_extruder_multiplier(cs.filament_size[2]); + extruder_multiplier[2] = calculate_extruder_multiplier(cs.filament_size[2]); #endif #endif } @@ -7761,510 +7854,510 @@ void delay_keep_alive(unsigned int ms) delay(ms); ms = 0; } - } -} - -static void wait_for_heater(long codenum, uint8_t extruder) { + } +} + +static void wait_for_heater(long codenum, uint8_t extruder) { + +#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 ((!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))) { +#endif //TEMP_RESIDENCY_TIME + if ((millis() - codenum) > 1000UL) + { //Print Temp Reading and remaining time every 1 second while heating up/cooling down + if (!farm_mode) { + SERIAL_PROTOCOLPGM("T:"); + SERIAL_PROTOCOL_F(degHotend(extruder), 1); + SERIAL_PROTOCOLPGM(" E:"); + SERIAL_PROTOCOL((int)extruder); + +#ifdef TEMP_RESIDENCY_TIME + SERIAL_PROTOCOLPGM(" W:"); + if (residencyStart > -1) + { + codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL; + SERIAL_PROTOCOLLN(codenum); + } + else + { + SERIAL_PROTOCOLLN("?"); + } + } +#else + SERIAL_PROTOCOLLN(""); +#endif + codenum = millis(); + } + manage_heater(); + manage_inactivity(true); //do not disable steppers + lcd_update(0); +#ifdef TEMP_RESIDENCY_TIME + /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time + or when current temp falls outside the hysteresis after target temp was reached */ + if ((residencyStart == -1 && target_direction && (degHotend(extruder) >= (degTargetHotend(extruder) - TEMP_WINDOW))) || + (residencyStart == -1 && !target_direction && (degHotend(extruder) <= (degTargetHotend(extruder) + TEMP_WINDOW))) || + (residencyStart > -1 && labs(degHotend(extruder) - degTargetHotend(extruder)) > TEMP_HYSTERESIS)) + { + residencyStart = millis(); + } +#endif //TEMP_RESIDENCY_TIME + } +} + +void check_babystep() +{ + int babystep_z; + EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystep_z); + if ((babystep_z < Z_BABYSTEP_MIN) || (babystep_z > Z_BABYSTEP_MAX)) { + babystep_z = 0; //if babystep value is out of min max range, set it to 0 + SERIAL_ECHOLNPGM("Z live adjust out of range. Setting to 0"); + EEPROM_save_B(EEPROM_BABYSTEP_Z, &babystep_z); + lcd_show_fullscreen_message_and_wait_P(PSTR("Z live adjust out of range. Setting to 0. Click to continue.")); + lcd_update_enable(true); + } +} +#ifdef DIS +void d_setup() +{ + pinMode(D_DATACLOCK, INPUT_PULLUP); + pinMode(D_DATA, INPUT_PULLUP); + pinMode(D_REQUIRE, OUTPUT); + digitalWrite(D_REQUIRE, HIGH); +} + + +float d_ReadData() +{ + int digit[13]; + String mergeOutput; + float output; + + digitalWrite(D_REQUIRE, HIGH); + for (int i = 0; i<13; i++) + { + for (int j = 0; j < 4; j++) + { + while (digitalRead(D_DATACLOCK) == LOW) {} + while (digitalRead(D_DATACLOCK) == HIGH) {} + bitWrite(digit[i], j, digitalRead(D_DATA)); + } + } + + digitalWrite(D_REQUIRE, LOW); + mergeOutput = ""; + output = 0; + for (int r = 5; r <= 10; r++) //Merge digits + { + mergeOutput += digit[r]; + } + output = mergeOutput.toFloat(); + + if (digit[4] == 8) //Handle sign + { + output *= -1; + } + + for (int i = digit[11]; i > 0; i--) //Handle floating point + { + output /= 10; + } + + return output; + +} + +void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y) { + int t1 = 0; + int t_delay = 0; + int digit[13]; + int m; + char str[3]; + //String mergeOutput; + char mergeOutput[15]; + float output; + + int mesh_point = 0; //index number of calibration point + float bed_zero_ref_x = (-22.f + X_PROBE_OFFSET_FROM_EXTRUDER); //shift between zero point on bed and target and between probe and nozzle + float bed_zero_ref_y = (-0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER); + + float mesh_home_z_search = 4; + float row[x_points_num]; + int ix = 0; + int iy = 0; + + const char* filename_wldsd = "wldsd.txt"; + char data_wldsd[70]; + char numb_wldsd[10]; + + d_setup(); + + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { + // We don't know where we are! HOME! + // Push the commands to the front of the message queue in the reverse order! + // There shall be always enough space reserved for these commands. + repeatcommand_front(); // repeat G80 with all its parameters + + enquecommand_front_P((PSTR("G28 W0"))); + enquecommand_front_P((PSTR("G1 Z5"))); + return; + } + unsigned int custom_message_type_old = custom_message_type; + unsigned int custom_message_state_old = custom_message_state; + custom_message_type = CUSTOM_MSG_TYPE_MESHBL; + custom_message_state = (x_points_num * y_points_num) + 10; + lcd_update(1); + + mbl.reset(); + babystep_undo(); + + card.openFile(filename_wldsd, false); + + current_position[Z_AXIS] = mesh_home_z_search; + 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); + + int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20; + int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40; + + int l_feedmultiply = setup_for_endstop_move(false); + + SERIAL_PROTOCOLPGM("Num X,Y: "); + SERIAL_PROTOCOL(x_points_num); + SERIAL_PROTOCOLPGM(","); + SERIAL_PROTOCOL(y_points_num); + SERIAL_PROTOCOLPGM("\nZ search height: "); + SERIAL_PROTOCOL(mesh_home_z_search); + SERIAL_PROTOCOLPGM("\nDimension X,Y: "); + SERIAL_PROTOCOL(x_dimension); + SERIAL_PROTOCOLPGM(","); + SERIAL_PROTOCOL(y_dimension); + SERIAL_PROTOCOLLNPGM("\nMeasured points:"); + + while (mesh_point != x_points_num * y_points_num) { + ix = mesh_point % x_points_num; // from 0 to MESH_NUM_X_POINTS - 1 + iy = mesh_point / x_points_num; + if (iy & 1) ix = (x_points_num - 1) - ix; // Zig zag + float z0 = 0.f; + current_position[Z_AXIS] = mesh_home_z_search; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); + st_synchronize(); + + + current_position[X_AXIS] = 13.f + ix * (x_dimension / (x_points_num - 1)) - bed_zero_ref_x + shift_x; + current_position[Y_AXIS] = 6.4f + iy * (y_dimension / (y_points_num - 1)) - bed_zero_ref_y + shift_y; + + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder); + st_synchronize(); + + if (!find_bed_induction_sensor_point_z(-10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point + break; + card.closefile(); + } + + + //memset(numb_wldsd, 0, sizeof(numb_wldsd)); + //dtostrf(d_ReadData(), 8, 5, numb_wldsd); + //strcat(data_wldsd, numb_wldsd); + + + + //MYSERIAL.println(data_wldsd); + //delay(1000); + //delay(3000); + //t1 = millis(); + + //while (digitalRead(D_DATACLOCK) == LOW) {} + //while (digitalRead(D_DATACLOCK) == HIGH) {} + memset(digit, 0, sizeof(digit)); + //cli(); + digitalWrite(D_REQUIRE, LOW); + + for (int i = 0; i<13; i++) + { + //t1 = millis(); + for (int j = 0; j < 4; j++) + { + while (digitalRead(D_DATACLOCK) == LOW) {} + while (digitalRead(D_DATACLOCK) == HIGH) {} + bitWrite(digit[i], j, digitalRead(D_DATA)); + } + //t_delay = (millis() - t1); + //SERIAL_PROTOCOLPGM(" "); + //SERIAL_PROTOCOL_F(t_delay, 5); + //SERIAL_PROTOCOLPGM(" "); + } + //sei(); + digitalWrite(D_REQUIRE, HIGH); + mergeOutput[0] = '\0'; + output = 0; + for (int r = 5; r <= 10; r++) //Merge digits + { + sprintf(str, "%d", digit[r]); + strcat(mergeOutput, str); + } -#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 ((!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))) { -#endif //TEMP_RESIDENCY_TIME - if ((millis() - codenum) > 1000UL) - { //Print Temp Reading and remaining time every 1 second while heating up/cooling down - if (!farm_mode) { - SERIAL_PROTOCOLPGM("T:"); - SERIAL_PROTOCOL_F(degHotend(extruder), 1); - SERIAL_PROTOCOLPGM(" E:"); - SERIAL_PROTOCOL((int)extruder); + output = atof(mergeOutput); -#ifdef TEMP_RESIDENCY_TIME - SERIAL_PROTOCOLPGM(" W:"); - if (residencyStart > -1) - { - codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL; - SERIAL_PROTOCOLLN(codenum); - } - else - { - SERIAL_PROTOCOLLN("?"); - } - } -#else - SERIAL_PROTOCOLLN(""); -#endif - codenum = millis(); - } - manage_heater(); - manage_inactivity(true); //do not disable steppers - lcd_update(0); -#ifdef TEMP_RESIDENCY_TIME - /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time - or when current temp falls outside the hysteresis after target temp was reached */ - if ((residencyStart == -1 && target_direction && (degHotend(extruder) >= (degTargetHotend(extruder) - TEMP_WINDOW))) || - (residencyStart == -1 && !target_direction && (degHotend(extruder) <= (degTargetHotend(extruder) + TEMP_WINDOW))) || - (residencyStart > -1 && labs(degHotend(extruder) - degTargetHotend(extruder)) > TEMP_HYSTERESIS)) - { - residencyStart = millis(); - } -#endif //TEMP_RESIDENCY_TIME - } -} + if (digit[4] == 8) //Handle sign + { + output *= -1; + } -void check_babystep() -{ - int babystep_z; - EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystep_z); - if ((babystep_z < Z_BABYSTEP_MIN) || (babystep_z > Z_BABYSTEP_MAX)) { - babystep_z = 0; //if babystep value is out of min max range, set it to 0 - SERIAL_ECHOLNPGM("Z live adjust out of range. Setting to 0"); - EEPROM_save_B(EEPROM_BABYSTEP_Z, &babystep_z); - lcd_show_fullscreen_message_and_wait_P(PSTR("Z live adjust out of range. Setting to 0. Click to continue.")); - lcd_update_enable(true); - } -} -#ifdef DIS -void d_setup() -{ - pinMode(D_DATACLOCK, INPUT_PULLUP); - pinMode(D_DATA, INPUT_PULLUP); - pinMode(D_REQUIRE, OUTPUT); - digitalWrite(D_REQUIRE, HIGH); -} + for (int i = digit[11]; i > 0; i--) //Handle floating point + { + output *= 0.1; + } -float d_ReadData() -{ - int digit[13]; - String mergeOutput; - float output; - - digitalWrite(D_REQUIRE, HIGH); - for (int i = 0; i<13; i++) - { - for (int j = 0; j < 4; j++) - { - while (digitalRead(D_DATACLOCK) == LOW) {} - while (digitalRead(D_DATACLOCK) == HIGH) {} - bitWrite(digit[i], j, digitalRead(D_DATA)); - } - } + //output = d_ReadData(); - digitalWrite(D_REQUIRE, LOW); - mergeOutput = ""; - output = 0; - for (int r = 5; r <= 10; r++) //Merge digits - { - mergeOutput += digit[r]; - } - output = mergeOutput.toFloat(); + //row[ix] = current_position[Z_AXIS]; - if (digit[4] == 8) //Handle sign - { - output *= -1; - } + memset(data_wldsd, 0, sizeof(data_wldsd)); - for (int i = digit[11]; i > 0; i--) //Handle floating point - { - output /= 10; - } + for (int i = 0; i <3; i++) { + memset(numb_wldsd, 0, sizeof(numb_wldsd)); + dtostrf(current_position[i], 8, 5, numb_wldsd); + strcat(data_wldsd, numb_wldsd); + strcat(data_wldsd, ";"); - return output; + } + memset(numb_wldsd, 0, sizeof(numb_wldsd)); + dtostrf(output, 8, 5, numb_wldsd); + strcat(data_wldsd, numb_wldsd); + //strcat(data_wldsd, ";"); + card.write_command(data_wldsd); -} -void bed_analysis(float x_dimension, float y_dimension, int x_points_num, int y_points_num, float shift_x, float shift_y) { - int t1 = 0; - int t_delay = 0; - int digit[13]; - int m; - char str[3]; - //String mergeOutput; - char mergeOutput[15]; - float output; - - int mesh_point = 0; //index number of calibration point - float bed_zero_ref_x = (-22.f + X_PROBE_OFFSET_FROM_EXTRUDER); //shift between zero point on bed and target and between probe and nozzle - float bed_zero_ref_y = (-0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER); - - float mesh_home_z_search = 4; - float row[x_points_num]; - int ix = 0; - int iy = 0; - - const char* filename_wldsd = "wldsd.txt"; - char data_wldsd[70]; - char numb_wldsd[10]; - - d_setup(); - - if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { - // We don't know where we are! HOME! - // Push the commands to the front of the message queue in the reverse order! - // There shall be always enough space reserved for these commands. - repeatcommand_front(); // repeat G80 with all its parameters - - enquecommand_front_P((PSTR("G28 W0"))); - enquecommand_front_P((PSTR("G1 Z5"))); - return; - } - unsigned int custom_message_type_old = custom_message_type; - unsigned int custom_message_state_old = custom_message_state; - custom_message_type = CUSTOM_MSG_TYPE_MESHBL; - custom_message_state = (x_points_num * y_points_num) + 10; - lcd_update(1); - - mbl.reset(); - babystep_undo(); - - card.openFile(filename_wldsd, false); - - current_position[Z_AXIS] = mesh_home_z_search; - 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); - - int XY_AXIS_FEEDRATE = homing_feedrate[X_AXIS] / 20; - int Z_LIFT_FEEDRATE = homing_feedrate[Z_AXIS] / 40; - - int l_feedmultiply = setup_for_endstop_move(false); - - SERIAL_PROTOCOLPGM("Num X,Y: "); - SERIAL_PROTOCOL(x_points_num); - SERIAL_PROTOCOLPGM(","); - SERIAL_PROTOCOL(y_points_num); - SERIAL_PROTOCOLPGM("\nZ search height: "); - SERIAL_PROTOCOL(mesh_home_z_search); - SERIAL_PROTOCOLPGM("\nDimension X,Y: "); - SERIAL_PROTOCOL(x_dimension); - SERIAL_PROTOCOLPGM(","); - SERIAL_PROTOCOL(y_dimension); - SERIAL_PROTOCOLLNPGM("\nMeasured points:"); - - while (mesh_point != x_points_num * y_points_num) { - ix = mesh_point % x_points_num; // from 0 to MESH_NUM_X_POINTS - 1 - iy = mesh_point / x_points_num; - if (iy & 1) ix = (x_points_num - 1) - ix; // Zig zag - float z0 = 0.f; - current_position[Z_AXIS] = mesh_home_z_search; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], Z_LIFT_FEEDRATE, active_extruder); - st_synchronize(); + //row[ix] = d_ReadData(); + row[ix] = output; // current_position[Z_AXIS]; - current_position[X_AXIS] = 13.f + ix * (x_dimension / (x_points_num - 1)) - bed_zero_ref_x + shift_x; - current_position[Y_AXIS] = 6.4f + iy * (y_dimension / (y_points_num - 1)) - bed_zero_ref_y + shift_y; + if (iy % 2 == 1 ? ix == 0 : ix == x_points_num - 1) { + for (int i = 0; i < x_points_num; i++) { + SERIAL_PROTOCOLPGM(" "); + SERIAL_PROTOCOL_F(row[i], 5); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], XY_AXIS_FEEDRATE, active_extruder); - st_synchronize(); - if (!find_bed_induction_sensor_point_z(-10.f)) { //if we have data from z calibration max allowed difference is 1mm for each point, if we dont have data max difference is 10mm from initial point - break; - card.closefile(); - } - - - //memset(numb_wldsd, 0, sizeof(numb_wldsd)); - //dtostrf(d_ReadData(), 8, 5, numb_wldsd); - //strcat(data_wldsd, numb_wldsd); - - - - //MYSERIAL.println(data_wldsd); - //delay(1000); - //delay(3000); - //t1 = millis(); - - //while (digitalRead(D_DATACLOCK) == LOW) {} - //while (digitalRead(D_DATACLOCK) == HIGH) {} - memset(digit, 0, sizeof(digit)); - //cli(); - digitalWrite(D_REQUIRE, LOW); - - for (int i = 0; i<13; i++) - { - //t1 = millis(); - for (int j = 0; j < 4; j++) - { - while (digitalRead(D_DATACLOCK) == LOW) {} - while (digitalRead(D_DATACLOCK) == HIGH) {} - bitWrite(digit[i], j, digitalRead(D_DATA)); - } - //t_delay = (millis() - t1); - //SERIAL_PROTOCOLPGM(" "); - //SERIAL_PROTOCOL_F(t_delay, 5); - //SERIAL_PROTOCOLPGM(" "); - } - //sei(); - digitalWrite(D_REQUIRE, HIGH); - mergeOutput[0] = '\0'; - output = 0; - for (int r = 5; r <= 10; r++) //Merge digits - { - sprintf(str, "%d", digit[r]); - strcat(mergeOutput, str); - } - - output = atof(mergeOutput); - - if (digit[4] == 8) //Handle sign - { - output *= -1; - } - - for (int i = digit[11]; i > 0; i--) //Handle floating point - { - output *= 0.1; - } - - - //output = d_ReadData(); - - //row[ix] = current_position[Z_AXIS]; - - memset(data_wldsd, 0, sizeof(data_wldsd)); - - for (int i = 0; i <3; i++) { - memset(numb_wldsd, 0, sizeof(numb_wldsd)); - dtostrf(current_position[i], 8, 5, numb_wldsd); - strcat(data_wldsd, numb_wldsd); - strcat(data_wldsd, ";"); - - } - memset(numb_wldsd, 0, sizeof(numb_wldsd)); - dtostrf(output, 8, 5, numb_wldsd); - strcat(data_wldsd, numb_wldsd); - //strcat(data_wldsd, ";"); - card.write_command(data_wldsd); - - - //row[ix] = d_ReadData(); - - row[ix] = output; // current_position[Z_AXIS]; - - if (iy % 2 == 1 ? ix == 0 : ix == x_points_num - 1) { - for (int i = 0; i < x_points_num; i++) { - SERIAL_PROTOCOLPGM(" "); - SERIAL_PROTOCOL_F(row[i], 5); - - - } - SERIAL_PROTOCOLPGM("\n"); - } - custom_message_state--; - mesh_point++; - lcd_update(1); + } + SERIAL_PROTOCOLPGM("\n"); + } + custom_message_state--; + mesh_point++; + lcd_update(1); - } - card.closefile(); - clean_up_after_endstop_move(l_feedmultiply); + } + card.closefile(); + clean_up_after_endstop_move(l_feedmultiply); } #endif void temp_compensation_start() { - - custom_message_type = CUSTOM_MSG_TYPE_TEMPRE; - custom_message_state = PINDA_HEAT_T + 1; - lcd_update(2); - if (degHotend(active_extruder) > EXTRUDE_MINTEMP) { - current_position[E_AXIS] -= default_retraction; - } - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); - - current_position[X_AXIS] = PINDA_PREHEAT_X; - current_position[Y_AXIS] = PINDA_PREHEAT_Y; - current_position[Z_AXIS] = PINDA_PREHEAT_Z; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); - st_synchronize(); - while (fabs(degBed() - target_temperature_bed) > 1) delay_keep_alive(1000); - - for (int i = 0; i < PINDA_HEAT_T; i++) { - delay_keep_alive(1000); - custom_message_state = PINDA_HEAT_T - i; - if (custom_message_state == 99 || custom_message_state == 9) lcd_update(2); //force whole display redraw if number of digits changed - else lcd_update(1); - } - custom_message_type = CUSTOM_MSG_TYPE_STATUS; - custom_message_state = 0; + + custom_message_type = CUSTOM_MSG_TYPE_TEMPRE; + custom_message_state = PINDA_HEAT_T + 1; + lcd_update(2); + if (degHotend(active_extruder) > EXTRUDE_MINTEMP) { + current_position[E_AXIS] -= default_retraction; + } + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); + + current_position[X_AXIS] = PINDA_PREHEAT_X; + current_position[Y_AXIS] = PINDA_PREHEAT_Y; + current_position[Z_AXIS] = PINDA_PREHEAT_Z; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + while (fabs(degBed() - target_temperature_bed) > 1) delay_keep_alive(1000); + + for (int i = 0; i < PINDA_HEAT_T; i++) { + delay_keep_alive(1000); + custom_message_state = PINDA_HEAT_T - i; + if (custom_message_state == 99 || custom_message_state == 9) lcd_update(2); //force whole display redraw if number of digits changed + else lcd_update(1); + } + custom_message_type = CUSTOM_MSG_TYPE_STATUS; + custom_message_state = 0; } void temp_compensation_apply() { - int i_add; - int z_shift = 0; - float z_shift_mm; - - if (calibration_status() == CALIBRATION_STATUS_CALIBRATED) { - if (target_temperature_bed % 10 == 0 && target_temperature_bed >= 60 && target_temperature_bed <= 100) { - i_add = (target_temperature_bed - 60) / 10; - EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + i_add * 2, &z_shift); - z_shift_mm = z_shift / cs.axis_steps_per_unit[Z_AXIS]; - }else { - //interpolation - z_shift_mm = temp_comp_interpolation(target_temperature_bed) / cs.axis_steps_per_unit[Z_AXIS]; - } - printf_P(_N("\nZ shift applied:%.3f\n"), z_shift_mm); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - z_shift_mm, current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); - st_synchronize(); - plan_set_z_position(current_position[Z_AXIS]); - } - else { - //we have no temp compensation data - } + int i_add; + int z_shift = 0; + float z_shift_mm; + + if (calibration_status() == CALIBRATION_STATUS_CALIBRATED) { + if (target_temperature_bed % 10 == 0 && target_temperature_bed >= 60 && target_temperature_bed <= 100) { + i_add = (target_temperature_bed - 60) / 10; + EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + i_add * 2, &z_shift); + z_shift_mm = z_shift / cs.axis_steps_per_unit[Z_AXIS]; + } else { + //interpolation + z_shift_mm = temp_comp_interpolation(target_temperature_bed) / cs.axis_steps_per_unit[Z_AXIS]; + } + printf_P(_N("\nZ shift applied:%.3f\n"), z_shift_mm); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] - z_shift_mm, current_position[E_AXIS], homing_feedrate[Z_AXIS] / 40, active_extruder); + st_synchronize(); + plan_set_z_position(current_position[Z_AXIS]); + } + else { + //we have no temp compensation data + } } float temp_comp_interpolation(float inp_temperature) { - //cubic spline interpolation + //cubic spline interpolation - int n, i, j; - float h[10], a, b, c, d, sum, s[10] = { 0 }, x[10], F[10], f[10], m[10][10] = { 0 }, temp; - int shift[10]; - int temp_C[10]; + int n, i, j; + float h[10], a, b, c, d, sum, s[10] = { 0 }, x[10], F[10], f[10], m[10][10] = { 0 }, temp; + int shift[10]; + int temp_C[10]; - n = 6; //number of measured points + n = 6; //number of measured points - shift[0] = 0; - for (i = 0; i < n; i++) { - if (i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i-1) * 2, &shift[i]); //read shift in steps from EEPROM - temp_C[i] = 50 + i * 10; //temperature in C + shift[0] = 0; + for (i = 0; i < n; i++) { + if (i>0) EEPROM_read_B(EEPROM_PROBE_TEMP_SHIFT + (i-1) * 2, &shift[i]); //read shift in steps from EEPROM + temp_C[i] = 50 + i * 10; //temperature in C #ifdef PINDA_THERMISTOR - temp_C[i] = 35 + i * 5; //temperature in C + temp_C[i] = 35 + i * 5; //temperature in C #else - temp_C[i] = 50 + i * 10; //temperature in C + temp_C[i] = 50 + i * 10; //temperature in C #endif - x[i] = (float)temp_C[i]; - f[i] = (float)shift[i]; - } - if (inp_temperature < x[0]) return 0; + x[i] = (float)temp_C[i]; + f[i] = (float)shift[i]; + } + if (inp_temperature < x[0]) return 0; - for (i = n - 1; i>0; i--) { - F[i] = (f[i] - f[i - 1]) / (x[i] - x[i - 1]); - h[i - 1] = x[i] - x[i - 1]; - } - //*********** formation of h, s , f matrix ************** - for (i = 1; i0; i--) { - sum = 0; - for (j = i; j <= n - 2; j++) - sum += m[i][j] * s[j]; - s[i] = (m[i][n - 1] - sum) / m[i][i]; - } + for (i = n - 1; i>0; i--) { + F[i] = (f[i] - f[i - 1]) / (x[i] - x[i - 1]); + h[i - 1] = x[i] - x[i - 1]; + } + //*********** formation of h, s , f matrix ************** + for (i = 1; i0; i--) { + sum = 0; + for (j = i; j <= n - 2; j++) + sum += m[i][j] * s[j]; + s[i] = (m[i][n - 1] - sum) / m[i][i]; + } - for (i = 0; i x[i + 1])) { - a = (s[i + 1] - s[i]) / (6 * h[i]); - b = s[i] / 2; - c = (f[i + 1] - f[i]) / h[i] - (2 * h[i] * s[i] + s[i + 1] * h[i]) / 6; - d = f[i]; - sum = a*pow((inp_temperature - x[i]), 3) + b*pow((inp_temperature - x[i]), 2) + c*(inp_temperature - x[i]) + d; - } + for (i = 0; i x[i + 1])) { + a = (s[i + 1] - s[i]) / (6 * h[i]); + b = s[i] / 2; + c = (f[i + 1] - f[i]) / h[i] - (2 * h[i] * s[i] + s[i + 1] * h[i]) / 6; + d = f[i]; + sum = a*pow((inp_temperature - x[i]), 3) + b*pow((inp_temperature - x[i]), 2) + c*(inp_temperature - x[i]) + d; + } - return sum; + return sum; } #ifdef PINDA_THERMISTOR float temp_compensation_pinda_thermistor_offset(float temperature_pinda) { - if (!temp_cal_active) return 0; - if (!calibration_status_pinda()) return 0; - return temp_comp_interpolation(temperature_pinda) / cs.axis_steps_per_unit[Z_AXIS]; + if (!temp_cal_active) return 0; + if (!calibration_status_pinda()) return 0; + return temp_comp_interpolation(temperature_pinda) / cs.axis_steps_per_unit[Z_AXIS]; } #endif //PINDA_THERMISTOR void long_pause() //long pause print { - st_synchronize(); - - start_pause_print = millis(); + st_synchronize(); + + start_pause_print = millis(); - //retract - current_position[E_AXIS] -= default_retraction; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); + //retract + current_position[E_AXIS] -= default_retraction; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); - //lift z - current_position[Z_AXIS] += Z_PAUSE_LIFT; - if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder); + //lift z + current_position[Z_AXIS] += Z_PAUSE_LIFT; + if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder); - //Move XY to side - current_position[X_AXIS] = X_PAUSE_POS; - current_position[Y_AXIS] = Y_PAUSE_POS; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); + //Move XY to side + current_position[X_AXIS] = X_PAUSE_POS; + current_position[Y_AXIS] = Y_PAUSE_POS; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); - // Turn off the print fan - fanSpeed = 0; + // Turn off the print fan + fanSpeed = 0; - st_synchronize(); + st_synchronize(); } void serialecho_temperatures() { - float tt = degHotend(active_extruder); - SERIAL_PROTOCOLPGM("T:"); - SERIAL_PROTOCOL(tt); - SERIAL_PROTOCOLPGM(" E:"); - SERIAL_PROTOCOL((int)active_extruder); - SERIAL_PROTOCOLPGM(" B:"); - SERIAL_PROTOCOL_F(degBed(), 1); - SERIAL_PROTOCOLLN(""); + float tt = degHotend(active_extruder); + SERIAL_PROTOCOLPGM("T:"); + SERIAL_PROTOCOL(tt); + SERIAL_PROTOCOLPGM(" E:"); + SERIAL_PROTOCOL((int)active_extruder); + SERIAL_PROTOCOLPGM(" B:"); + SERIAL_PROTOCOL_F(degBed(), 1); + SERIAL_PROTOCOLLN(""); } extern uint32_t sdpos_atomic; #ifdef UVLO_SUPPORT -void uvlo_() +void uvlo_() { - unsigned long time_start = millis(); - bool sd_print = card.sdprinting; + unsigned long time_start = millis(); + bool sd_print = card.sdprinting; // Conserve power as soon as possible. disable_x(); disable_y(); - + #ifdef TMC2130 - tmc2130_set_current_h(Z_AXIS, 20); - tmc2130_set_current_r(Z_AXIS, 20); - tmc2130_set_current_h(E_AXIS, 20); - tmc2130_set_current_r(E_AXIS, 20); + tmc2130_set_current_h(Z_AXIS, 20); + tmc2130_set_current_r(Z_AXIS, 20); + tmc2130_set_current_h(E_AXIS, 20); + tmc2130_set_current_r(E_AXIS, 20); #endif //TMC2130 // Indicate that the interrupt has been triggered. - // SERIAL_ECHOLNPGM("UVLO"); + // SERIAL_ECHOLNPGM("UVLO"); // Read out the current Z motor microstep counter. This will be later used // for reaching the zero full step before powering off. uint16_t z_microsteps = 0; #ifdef TMC2130 - z_microsteps = tmc2130_rd_MSCNT(Z_TMC2130_CS); + z_microsteps = tmc2130_rd_MSCNT(Z_TMC2130_CS); #endif //TMC2130 // Calculate the file position, from which to resume this print. long sd_position = sdpos_atomic; //atomic sd position of last command added in queue { - uint16_t sdlen_planner = planner_calc_sd_length(); //length of sd commands in planner - sd_position -= sdlen_planner; - uint16_t sdlen_cmdqueue = cmdqueue_calc_sd_length(); //length of sd commands in cmdqueue - sd_position -= sdlen_cmdqueue; - if (sd_position < 0) sd_position = 0; + uint16_t sdlen_planner = planner_calc_sd_length(); //length of sd commands in planner + sd_position -= sdlen_planner; + uint16_t sdlen_cmdqueue = cmdqueue_calc_sd_length(); //length of sd commands in cmdqueue + sd_position -= sdlen_cmdqueue; + if (sd_position < 0) sd_position = 0; } // Backup the feedrate in mm/min. @@ -8277,7 +8370,7 @@ void uvlo_() // Store the current extruder position. eeprom_update_float((float*)(EEPROM_UVLO_CURRENT_POSITION_E), st_get_position_mm(E_AXIS)); - eeprom_update_byte((uint8_t*)EEPROM_UVLO_E_ABS, axis_relative_modes[3]?0:1); + eeprom_update_byte((uint8_t*)EEPROM_UVLO_E_ABS, axis_relative_modes[3]?0:1); // Clean the input command queue. cmdqueue_reset(); @@ -8288,47 +8381,47 @@ void uvlo_() // This should be fine as the planner and command queues are empty and the SD card printing is disabled. //FIXME one may want to disable serial lines at this point of time to avoid interfering with the command queue, // though it should not happen that the command queue is touched as the plan_buffer_line always succeed without blocking. - sei(); - plan_buffer_line( - current_position[X_AXIS], - current_position[Y_AXIS], - current_position[Z_AXIS], - current_position[E_AXIS] - default_retraction, - 95, active_extruder); - - st_synchronize(); - disable_e0(); - - plan_buffer_line( - current_position[X_AXIS], - current_position[Y_AXIS], - current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS], - current_position[E_AXIS] - default_retraction, - 40, active_extruder); - + sei(); + plan_buffer_line( + current_position[X_AXIS], + current_position[Y_AXIS], + current_position[Z_AXIS], + current_position[E_AXIS] - default_retraction, + 95, active_extruder); + + st_synchronize(); + disable_e0(); + + plan_buffer_line( + current_position[X_AXIS], + current_position[Y_AXIS], + current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS], + current_position[E_AXIS] - default_retraction, + 40, active_extruder); + st_synchronize(); disable_e0(); - + plan_buffer_line( - current_position[X_AXIS], - current_position[Y_AXIS], - current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS], - current_position[E_AXIS] - default_retraction, - 40, active_extruder); + current_position[X_AXIS], + current_position[Y_AXIS], + current_position[Z_AXIS] + UVLO_Z_AXIS_SHIFT + float((1024 - z_microsteps + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS], + current_position[E_AXIS] - default_retraction, + 40, active_extruder); st_synchronize(); disable_e0(); disable_z(); - + // Move Z up to the next 0th full step. // Write the file position. eeprom_update_dword((uint32_t*)(EEPROM_FILE_POSITION), sd_position); // Store the mesh bed leveling offsets. This is 2*9=18 bytes, which takes 18*3.4us=52us in worst case. for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { - uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1 - uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS; - // Scale the z value to 1u resolution. - int16_t v = mbl.active ? int16_t(floor(mbl.z_values[iy*3][ix*3] * 1000.f + 0.5f)) : 0; - eeprom_update_word((uint16_t*)(EEPROM_UVLO_MESH_BED_LEVELING+2*mesh_point), *reinterpret_cast(&v)); + uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1 + uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS; + // Scale the z value to 1u resolution. + int16_t v = mbl.active ? int16_t(floor(mbl.z_values[iy*3][ix*3] * 1000.f + 0.5f)) : 0; + eeprom_update_word((uint16_t*)(EEPROM_UVLO_MESH_BED_LEVELING+2*mesh_point), *reinterpret_cast(&v)); } // Read out the current Z motor microstep counter. This will be later used // for reaching the zero full step before powering off. @@ -8342,89 +8435,89 @@ void uvlo_() eeprom_update_byte((uint8_t*)EEPROM_UVLO_TARGET_HOTEND, target_temperature[active_extruder]); eeprom_update_byte((uint8_t*)EEPROM_UVLO_TARGET_BED, target_temperature_bed); eeprom_update_byte((uint8_t*)EEPROM_UVLO_FAN_SPEED, fanSpeed); - eeprom_update_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_0), extruder_multiplier[0]); + eeprom_update_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_0), extruder_multiplier[0]); #if EXTRUDERS > 1 - eeprom_update_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_1), extruder_multiplier[1]); + eeprom_update_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_1), extruder_multiplier[1]); #if EXTRUDERS > 2 - eeprom_update_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_2), extruder_multiplier[2]); + eeprom_update_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_2), extruder_multiplier[2]); #endif #endif - eeprom_update_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY), (uint16_t)extrudemultiply); + eeprom_update_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY), (uint16_t)extrudemultiply); // Finaly store the "power outage" flag. - if(sd_print) eeprom_update_byte((uint8_t*)EEPROM_UVLO, 1); + if(sd_print) eeprom_update_byte((uint8_t*)EEPROM_UVLO, 1); st_synchronize(); printf_P(_N("stps%d\n"), tmc2130_rd_MSCNT(Z_AXIS)); disable_z(); - + // Increment power failure counter - eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) + 1); - eeprom_update_word((uint16_t*)EEPROM_POWER_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) + 1); - - printf_P(_N("UVLO - end %d\n"), millis() - time_start); - + eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) + 1); + eeprom_update_word((uint16_t*)EEPROM_POWER_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) + 1); + + printf_P(_N("UVLO - end %d\n"), millis() - time_start); + #if 0 // Move the print head to the side of the print until all the power stored in the power supply capacitors is depleted. current_position[X_AXIS] = (current_position[X_AXIS] < 0.5f * (X_MIN_POS + X_MAX_POS)) ? X_MIN_POS : X_MAX_POS; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); st_synchronize(); #endif - -wdt_enable(WDTO_500MS); -WRITE(BEEPER,HIGH); -while(1) - ; + + wdt_enable(WDTO_500MS); + WRITE(BEEPER,HIGH); + while(1) + ; } void uvlo_tiny() { -uint16_t z_microsteps=0; + uint16_t z_microsteps=0; // Conserve power as soon as possible. -disable_x(); -disable_y(); -disable_e0(); - + disable_x(); + disable_y(); + disable_e0(); + #ifdef TMC2130 -tmc2130_set_current_h(Z_AXIS, 20); -tmc2130_set_current_r(Z_AXIS, 20); + tmc2130_set_current_h(Z_AXIS, 20); + tmc2130_set_current_r(Z_AXIS, 20); #endif //TMC2130 // Read out the current Z motor microstep counter #ifdef TMC2130 -z_microsteps=tmc2130_rd_MSCNT(Z_TMC2130_CS); + z_microsteps=tmc2130_rd_MSCNT(Z_TMC2130_CS); #endif //TMC2130 -planner_abort_hard(); -sei(); -plan_buffer_line( - current_position[X_AXIS], - current_position[Y_AXIS], -// current_position[Z_AXIS]+float((1024-z_microsteps+7)>>4)/axis_steps_per_unit[Z_AXIS], - current_position[Z_AXIS]+UVLO_Z_AXIS_SHIFT+float((1024-z_microsteps+7)>>4)/cs.axis_steps_per_unit[Z_AXIS], - current_position[E_AXIS], - 40, active_extruder); -st_synchronize(); -disable_z(); + planner_abort_hard(); + sei(); + plan_buffer_line( + current_position[X_AXIS], + current_position[Y_AXIS], +// current_position[Z_AXIS]+float((1024-z_microsteps+7)>>4)/axis_steps_per_unit[Z_AXIS], + current_position[Z_AXIS]+UVLO_Z_AXIS_SHIFT+float((1024-z_microsteps+7)>>4)/cs.axis_steps_per_unit[Z_AXIS], + current_position[E_AXIS], + 40, active_extruder); + st_synchronize(); + disable_z(); // Finaly store the "power outage" flag. //if(sd_print) - eeprom_update_byte((uint8_t*)EEPROM_UVLO,2); + eeprom_update_byte((uint8_t*)EEPROM_UVLO,2); -eeprom_update_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS),z_microsteps); -eeprom_update_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z), current_position[Z_AXIS]); + eeprom_update_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS),z_microsteps); + eeprom_update_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z), current_position[Z_AXIS]); // Increment power failure counter -eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) + 1); -eeprom_update_word((uint16_t*)EEPROM_POWER_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) + 1); + eeprom_update_byte((uint8_t*)EEPROM_POWER_COUNT, eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT) + 1); + eeprom_update_word((uint16_t*)EEPROM_POWER_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT) + 1); -wdt_enable(WDTO_500MS); -WRITE(BEEPER,HIGH); -while(1) - ; + wdt_enable(WDTO_500MS); + WRITE(BEEPER,HIGH); + while(1) + ; } #endif //UVLO_SUPPORT @@ -8432,237 +8525,243 @@ while(1) void setup_fan_interrupt() { //INT7 - DDRE &= ~(1 << 7); //input pin - PORTE &= ~(1 << 7); //no internal pull-up + DDRE &= ~(1 << 7); //input pin + PORTE &= ~(1 << 7); //no internal pull-up - //start with sensing rising edge - EICRB &= ~(1 << 6); - EICRB |= (1 << 7); + //start with sensing rising edge + EICRB &= ~(1 << 6); + EICRB |= (1 << 7); - //enable INT7 interrupt - EIMSK |= (1 << 7); + //enable INT7 interrupt + EIMSK |= (1 << 7); } // The fan interrupt is triggered at maximum 325Hz (may be a bit more due to component tollerances), // and it takes 4.24 us to process (the interrupt invocation overhead not taken into account). ISR(INT7_vect) { - //measuring speed now works for fanSpeed > 18 (approximately), which is sufficient because MIN_PRINT_FAN_SPEED is higher + //measuring speed now works for fanSpeed > 18 (approximately), which is sufficient because MIN_PRINT_FAN_SPEED is higher - if (fanSpeed < MIN_PRINT_FAN_SPEED) return; - if ((1 << 6) & EICRB) { //interrupt was triggered by rising edge - t_fan_rising_edge = millis_nc(); - } - else { //interrupt was triggered by falling edge - if ((millis_nc() - t_fan_rising_edge) >= FAN_PULSE_WIDTH_LIMIT) {//this pulse was from sensor and not from pwm - fan_edge_counter[1] += 2; //we are currently counting all edges so lets count two edges for one pulse - } - } - EICRB ^= (1 << 6); //change edge + if (fanSpeed < MIN_PRINT_FAN_SPEED) return; + if ((1 << 6) & EICRB) { //interrupt was triggered by rising edge + t_fan_rising_edge = millis_nc(); + } + else { //interrupt was triggered by falling edge + if ((millis_nc() - t_fan_rising_edge) >= FAN_PULSE_WIDTH_LIMIT) {//this pulse was from sensor and not from pwm + fan_edge_counter[1] += 2; //we are currently counting all edges so lets count two edges for one pulse + } + } + EICRB ^= (1 << 6); //change edge } #endif #ifdef UVLO_SUPPORT void setup_uvlo_interrupt() { - DDRE &= ~(1 << 4); //input pin - PORTE &= ~(1 << 4); //no internal pull-up + DDRE &= ~(1 << 4); //input pin + PORTE &= ~(1 << 4); //no internal pull-up - //sensing falling edge - EICRB |= (1 << 0); - EICRB &= ~(1 << 1); + //sensing falling edge + EICRB |= (1 << 0); + EICRB &= ~(1 << 1); - //enable INT4 interrupt - EIMSK |= (1 << 4); + //enable INT4 interrupt + EIMSK |= (1 << 4); } ISR(INT4_vect) { - EIMSK &= ~(1 << 4); //disable INT4 interrupt to make sure that this code will be executed just once - SERIAL_ECHOLNPGM("INT4"); - if(IS_SD_PRINTING && (!(eeprom_read_byte((uint8_t*)EEPROM_UVLO))) ) uvlo_(); - if(eeprom_read_byte((uint8_t*)EEPROM_UVLO)) uvlo_tiny(); + EIMSK &= ~(1 << 4); //disable INT4 interrupt to make sure that this code will be executed just once + SERIAL_ECHOLNPGM("INT4"); + if(IS_SD_PRINTING && (!(eeprom_read_byte((uint8_t*)EEPROM_UVLO))) ) uvlo_(); + if(eeprom_read_byte((uint8_t*)EEPROM_UVLO)) uvlo_tiny(); } void recover_print(uint8_t automatic) { - char cmd[30]; - lcd_update_enable(true); - lcd_update(2); - lcd_setstatuspgm(_i("Recovering print "));////MSG_RECOVERING_PRINT c=20 r=1 - - bool bTiny=(eeprom_read_byte((uint8_t*)EEPROM_UVLO)==2); - recover_machine_state_after_power_panic(bTiny); //recover position, temperatures and extrude_multipliers - - // Lift the print head, so one may remove the excess priming material. - if(!bTiny&&(current_position[Z_AXIS]<25)) - enquecommand_P(PSTR("G1 Z25 F800")); - // Home X and Y axes. Homing just X and Y shall not touch the babystep and the world2machine transformation status. - enquecommand_P(PSTR("G28 X Y")); - // Set the target bed and nozzle temperatures and wait. - sprintf_P(cmd, PSTR("M109 S%d"), target_temperature[active_extruder]); - enquecommand(cmd); - sprintf_P(cmd, PSTR("M190 S%d"), target_temperature_bed); - enquecommand(cmd); - enquecommand_P(PSTR("M83")); //E axis relative mode - //enquecommand_P(PSTR("G1 E5 F120")); //Extrude some filament to stabilize pessure - // If not automatically recoreverd (long power loss), extrude extra filament to stabilize - if(automatic == 0){ - enquecommand_P(PSTR("G1 E5 F120")); //Extrude some filament to stabilize pessure - } - enquecommand_P(PSTR("G1 E" STRINGIFY(-default_retraction)" F480")); - - printf_P(_N("After waiting for temp:\nCurrent pos X_AXIS:%.3f\nCurrent pos Y_AXIS:%.3f\n"), current_position[X_AXIS], current_position[Y_AXIS]); - - // Restart the print. - restore_print_from_eeprom(); - - printf_P(_N("Current pos Z_AXIS:%.3f\nCurrent pos E_AXIS:%.3f\n"), current_position[Z_AXIS], current_position[E_AXIS]); + char cmd[30]; + lcd_update_enable(true); + lcd_update(2); + lcd_setstatuspgm(_i("Recovering print "));////MSG_RECOVERING_PRINT c=20 r=1 + + bool bTiny=(eeprom_read_byte((uint8_t*)EEPROM_UVLO)==2); + recover_machine_state_after_power_panic(bTiny); //recover position, temperatures and extrude_multipliers + + // Lift the print head, so one may remove the excess priming material. + if(!bTiny&&(current_position[Z_AXIS]<25)) + enquecommand_P(PSTR("G1 Z25 F800")); + // Home X and Y axes. Homing just X and Y shall not touch the babystep and the world2machine transformation status. + enquecommand_P(PSTR("G28 X Y")); + // Set the target bed and nozzle temperatures and wait. + sprintf_P(cmd, PSTR("M109 S%d"), target_temperature[active_extruder]); + enquecommand(cmd); + sprintf_P(cmd, PSTR("M190 S%d"), target_temperature_bed); + enquecommand(cmd); + enquecommand_P(PSTR("M83")); //E axis relative mode + //enquecommand_P(PSTR("G1 E5 F120")); //Extrude some filament to stabilize pessure + // If not automatically recoreverd (long power loss), extrude extra filament to stabilize + if(automatic == 0) { + enquecommand_P(PSTR("G1 E5 F120")); //Extrude some filament to stabilize pessure + } + enquecommand_P(PSTR("G1 E" STRINGIFY(-default_retraction)" F480")); + + printf_P(_N("After waiting for temp:\nCurrent pos X_AXIS:%.3f\nCurrent pos Y_AXIS:%.3f\n"), current_position[X_AXIS], current_position[Y_AXIS]); + + // Restart the print. + restore_print_from_eeprom(); + + printf_P(_N("Current pos Z_AXIS:%.3f\nCurrent pos E_AXIS:%.3f\n"), current_position[Z_AXIS], current_position[E_AXIS]); } void recover_machine_state_after_power_panic(bool bTiny) { - char cmd[30]; - // 1) Recover the logical cordinates at the time of the power panic. - // The logical XY coordinates are needed to recover the machine Z coordinate corrected by the mesh bed leveling. - current_position[X_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0)); - current_position[Y_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4)); - // Recover the logical coordinate of the Z axis at the time of the power panic. - // The current position after power panic is moved to the next closest 0th full step. - if(bTiny) - current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z)) + - UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS)) + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS]; - else - current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z)) + - UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_Z_MICROSTEPS)) + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS]; - if (eeprom_read_byte((uint8_t*)EEPROM_UVLO_E_ABS)) { - current_position[E_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_E)); - sprintf_P(cmd, PSTR("G92 E")); - dtostrf(current_position[E_AXIS], 6, 3, cmd + strlen(cmd)); - enquecommand(cmd); - } + char cmd[30]; + // 1) Recover the logical cordinates at the time of the power panic. + // The logical XY coordinates are needed to recover the machine Z coordinate corrected by the mesh bed leveling. + current_position[X_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0)); + current_position[Y_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4)); + // Recover the logical coordinate of the Z axis at the time of the power panic. + // The current position after power panic is moved to the next closest 0th full step. + if(bTiny) + current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_TINY_CURRENT_POSITION_Z)) + + UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_TINY_Z_MICROSTEPS)) + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS]; + else + current_position[Z_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z)) + + UVLO_Z_AXIS_SHIFT + float((1024 - eeprom_read_word((uint16_t*)(EEPROM_UVLO_Z_MICROSTEPS)) + 7) >> 4) / cs.axis_steps_per_unit[Z_AXIS]; + if (eeprom_read_byte((uint8_t*)EEPROM_UVLO_E_ABS)) { + current_position[E_AXIS] = eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_E)); + sprintf_P(cmd, PSTR("G92 E")); + dtostrf(current_position[E_AXIS], 6, 3, cmd + strlen(cmd)); + enquecommand(cmd); + } - memcpy(destination, current_position, sizeof(destination)); - - SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial "); - print_world_coordinates(); - - // 2) Initialize the logical to physical coordinate system transformation. - world2machine_initialize(); - - // 3) Restore the mesh bed leveling offsets. This is 2*9=18 bytes, which takes 18*3.4us=52us in worst case. - mbl.active = false; - for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { - uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1 - uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS; - // Scale the z value to 10u resolution. - int16_t v; - eeprom_read_block(&v, (void*)(EEPROM_UVLO_MESH_BED_LEVELING+2*mesh_point), 2); - if (v != 0) - mbl.active = true; - mbl.z_values[iy][ix] = float(v) * 0.001f; - } - if (mbl.active) - mbl.upsample_3x3(); + memcpy(destination, current_position, sizeof(destination)); + + SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial "); + print_world_coordinates(); + + // 2) Initialize the logical to physical coordinate system transformation. + world2machine_initialize(); + + // 3) Restore the mesh bed leveling offsets. This is 2*9=18 bytes, which takes 18*3.4us=52us in worst case. + mbl.active = false; + for (int8_t mesh_point = 0; mesh_point < 9; ++ mesh_point) { + uint8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; // from 0 to MESH_NUM_X_POINTS - 1 + uint8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS; + // Scale the z value to 10u resolution. + int16_t v; + eeprom_read_block(&v, (void*)(EEPROM_UVLO_MESH_BED_LEVELING+2*mesh_point), 2); + if (v != 0) + mbl.active = true; + mbl.z_values[iy][ix] = float(v) * 0.001f; + } + if (mbl.active) + mbl.upsample_3x3(); // SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial "); // print_mesh_bed_leveling_table(); - // 4) Load the baby stepping value, which is expected to be active at the time of power panic. - // The baby stepping value is used to reset the physical Z axis when rehoming the Z axis. - babystep_load(); + // 4) Load the baby stepping value, which is expected to be active at the time of power panic. + // The baby stepping value is used to reset the physical Z axis when rehoming the Z axis. + babystep_load(); - // 5) Set the physical positions from the logical positions using the world2machine transformation and the active bed leveling. - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + // 5) Set the physical positions from the logical positions using the world2machine transformation and the active bed leveling. + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - // 6) Power up the motors, mark their positions as known. - //FIXME Verfiy, whether the X and Y axes should be powered up here, as they will later be re-homed anyway. - axis_known_position[X_AXIS] = true; enable_x(); - axis_known_position[Y_AXIS] = true; enable_y(); - axis_known_position[Z_AXIS] = true; enable_z(); + // 6) Power up the motors, mark their positions as known. + //FIXME Verfiy, whether the X and Y axes should be powered up here, as they will later be re-homed anyway. + axis_known_position[X_AXIS] = true; + enable_x(); + axis_known_position[Y_AXIS] = true; + enable_y(); + axis_known_position[Z_AXIS] = true; + enable_z(); - SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial "); - print_physical_coordinates(); + SERIAL_ECHOPGM("recover_machine_state_after_power_panic, initial "); + print_physical_coordinates(); - // 7) Recover the target temperatures. - target_temperature[active_extruder] = eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_HOTEND); - target_temperature_bed = eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED); + // 7) Recover the target temperatures. + target_temperature[active_extruder] = eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_HOTEND); + target_temperature_bed = eeprom_read_byte((uint8_t*)EEPROM_UVLO_TARGET_BED); - // 8) Recover extruder multipilers - extruder_multiplier[0] = eeprom_read_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_0)); + // 8) Recover extruder multipilers + extruder_multiplier[0] = eeprom_read_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_0)); #if EXTRUDERS > 1 - extruder_multiplier[1] = eeprom_read_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_1)); + extruder_multiplier[1] = eeprom_read_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_1)); #if EXTRUDERS > 2 - extruder_multiplier[2] = eeprom_read_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_2)); + extruder_multiplier[2] = eeprom_read_float((float*)(EEPROM_EXTRUDER_MULTIPLIER_2)); #endif #endif - extrudemultiply = (int)eeprom_read_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY)); + extrudemultiply = (int)eeprom_read_word((uint16_t*)(EEPROM_EXTRUDEMULTIPLY)); } void restore_print_from_eeprom() { - int feedrate_rec; - uint8_t fan_speed_rec; - char cmd[30]; - char filename[13]; - uint8_t depth = 0; - char dir_name[9]; - - fan_speed_rec = eeprom_read_byte((uint8_t*)EEPROM_UVLO_FAN_SPEED); - EEPROM_read_B(EEPROM_UVLO_FEEDRATE, &feedrate_rec); - SERIAL_ECHOPGM("Feedrate:"); - MYSERIAL.println(feedrate_rec); - - depth = eeprom_read_byte((uint8_t*)EEPROM_DIR_DEPTH); - - MYSERIAL.println(int(depth)); - for (int i = 0; i < depth; i++) { - for (int j = 0; j < 8; j++) { - dir_name[j] = eeprom_read_byte((uint8_t*)EEPROM_DIRS + j + 8 * i); - } - dir_name[8] = '\0'; - MYSERIAL.println(dir_name); - strcpy(dir_names[i], dir_name); - card.chdir(dir_name); - } + int feedrate_rec; + uint8_t fan_speed_rec; + char cmd[30]; + char filename[13]; + uint8_t depth = 0; + char dir_name[9]; + + fan_speed_rec = eeprom_read_byte((uint8_t*)EEPROM_UVLO_FAN_SPEED); + EEPROM_read_B(EEPROM_UVLO_FEEDRATE, &feedrate_rec); + SERIAL_ECHOPGM("Feedrate:"); + MYSERIAL.println(feedrate_rec); + + depth = eeprom_read_byte((uint8_t*)EEPROM_DIR_DEPTH); + + MYSERIAL.println(int(depth)); + for (int i = 0; i < depth; i++) { + for (int j = 0; j < 8; j++) { + dir_name[j] = eeprom_read_byte((uint8_t*)EEPROM_DIRS + j + 8 * i); + } + dir_name[8] = '\0'; + MYSERIAL.println(dir_name); + strcpy(dir_names[i], dir_name); + card.chdir(dir_name); + } - for (int i = 0; i < 8; i++) { - filename[i] = eeprom_read_byte((uint8_t*)EEPROM_FILENAME + i); - } - filename[8] = '\0'; - - MYSERIAL.print(filename); - strcat_P(filename, PSTR(".gco")); - sprintf_P(cmd, PSTR("M23 %s"), filename); - enquecommand(cmd); - uint32_t position = eeprom_read_dword((uint32_t*)(EEPROM_FILE_POSITION)); - SERIAL_ECHOPGM("Position read from eeprom:"); - MYSERIAL.println(position); - - // E axis relative mode. - enquecommand_P(PSTR("M83")); - // Move to the XY print position in logical coordinates, where the print has been killed. - strcpy_P(cmd, PSTR("G1 X")); strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0)))); - strcat_P(cmd, PSTR(" Y")); strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4)))); - strcat_P(cmd, PSTR(" F2000")); - enquecommand(cmd); - // Move the Z axis down to the print, in logical coordinates. - strcpy_P(cmd, PSTR("G1 Z")); strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z)))); - enquecommand(cmd); - // Unretract. - enquecommand_P(PSTR("G1 E" STRINGIFY(2*default_retraction)" F480")); - // Set the feedrate saved at the power panic. - sprintf_P(cmd, PSTR("G1 F%d"), feedrate_rec); - enquecommand(cmd); - if (eeprom_read_byte((uint8_t*)EEPROM_UVLO_E_ABS)) - { - enquecommand_P(PSTR("M82")); //E axis abslute mode - } - // Set the fan speed saved at the power panic. - strcpy_P(cmd, PSTR("M106 S")); - strcat(cmd, itostr3(int(fan_speed_rec))); - enquecommand(cmd); - - // Set a position in the file. - sprintf_P(cmd, PSTR("M26 S%lu"), position); - enquecommand(cmd); - enquecommand_P(PSTR("G4 S0")); - enquecommand_P(PSTR("PRUSA uvlo")); + for (int i = 0; i < 8; i++) { + filename[i] = eeprom_read_byte((uint8_t*)EEPROM_FILENAME + i); + } + filename[8] = '\0'; + + MYSERIAL.print(filename); + strcat_P(filename, PSTR(".gco")); + sprintf_P(cmd, PSTR("M23 %s"), filename); + enquecommand(cmd); + uint32_t position = eeprom_read_dword((uint32_t*)(EEPROM_FILE_POSITION)); + SERIAL_ECHOPGM("Position read from eeprom:"); + MYSERIAL.println(position); + + // E axis relative mode. + enquecommand_P(PSTR("M83")); + // Move to the XY print position in logical coordinates, where the print has been killed. + strcpy_P(cmd, PSTR("G1 X")); + strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 0)))); + strcat_P(cmd, PSTR(" Y")); + strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION + 4)))); + strcat_P(cmd, PSTR(" F2000")); + enquecommand(cmd); + // Move the Z axis down to the print, in logical coordinates. + strcpy_P(cmd, PSTR("G1 Z")); + strcat(cmd, ftostr32(eeprom_read_float((float*)(EEPROM_UVLO_CURRENT_POSITION_Z)))); + enquecommand(cmd); + // Unretract. + enquecommand_P(PSTR("G1 E" STRINGIFY(2*default_retraction)" F480")); + // Set the feedrate saved at the power panic. + sprintf_P(cmd, PSTR("G1 F%d"), feedrate_rec); + enquecommand(cmd); + if (eeprom_read_byte((uint8_t*)EEPROM_UVLO_E_ABS)) + { + enquecommand_P(PSTR("M82")); //E axis abslute mode + } + // Set the fan speed saved at the power panic. + strcpy_P(cmd, PSTR("M106 S")); + strcat(cmd, itostr3(int(fan_speed_rec))); + enquecommand(cmd); + + // Set a position in the file. + sprintf_P(cmd, PSTR("M26 S%lu"), position); + enquecommand(cmd); + enquecommand_P(PSTR("G4 S0")); + enquecommand_P(PSTR("PRUSA uvlo")); } #endif //UVLO_SUPPORT @@ -8677,186 +8776,192 @@ void restore_print_from_eeprom() { //! @param e_move void stop_and_save_print_to_ram(float z_move, float e_move) { - if (saved_printing) return; + if (saved_printing) return; #if 0 - unsigned char nplanner_blocks; + unsigned char nplanner_blocks; #endif - unsigned char nlines; - uint16_t sdlen_planner; - uint16_t sdlen_cmdqueue; - + unsigned char nlines; + uint16_t sdlen_planner; + uint16_t sdlen_cmdqueue; - cli(); - if (card.sdprinting) { + + cli(); + if (card.sdprinting) { #if 0 - nplanner_blocks = number_of_blocks(); + nplanner_blocks = number_of_blocks(); #endif - saved_sdpos = sdpos_atomic; //atomic sd position of last command added in queue - sdlen_planner = planner_calc_sd_length(); //length of sd commands in planner - saved_sdpos -= sdlen_planner; - sdlen_cmdqueue = cmdqueue_calc_sd_length(); //length of sd commands in cmdqueue - saved_sdpos -= sdlen_cmdqueue; - saved_printing_type = PRINTING_TYPE_SD; + saved_sdpos = sdpos_atomic; //atomic sd position of last command added in queue + sdlen_planner = planner_calc_sd_length(); //length of sd commands in planner + saved_sdpos -= sdlen_planner; + sdlen_cmdqueue = cmdqueue_calc_sd_length(); //length of sd commands in cmdqueue + saved_sdpos -= sdlen_cmdqueue; + saved_printing_type = PRINTING_TYPE_SD; - } - else if (is_usb_printing) { //reuse saved_sdpos for storing line number - saved_sdpos = gcode_LastN; //start with line number of command added recently to cmd queue - //reuse planner_calc_sd_length function for getting number of lines of commands in planner: - nlines = planner_calc_sd_length(); //number of lines of commands in planner - saved_sdpos -= nlines; - saved_sdpos -= buflen; //number of blocks in cmd buffer - saved_printing_type = PRINTING_TYPE_USB; - } - else { - //not sd printing nor usb printing - } + } + else if (is_usb_printing) { //reuse saved_sdpos for storing line number + saved_sdpos = gcode_LastN; //start with line number of command added recently to cmd queue + //reuse planner_calc_sd_length function for getting number of lines of commands in planner: + nlines = planner_calc_sd_length(); //number of lines of commands in planner + saved_sdpos -= nlines; + saved_sdpos -= buflen; //number of blocks in cmd buffer + saved_printing_type = PRINTING_TYPE_USB; + } + else { + //not sd printing nor usb printing + } #if 0 - SERIAL_ECHOPGM("SDPOS_ATOMIC="); MYSERIAL.println(sdpos_atomic, DEC); - SERIAL_ECHOPGM("SDPOS="); MYSERIAL.println(card.get_sdpos(), DEC); - SERIAL_ECHOPGM("SDLEN_PLAN="); MYSERIAL.println(sdlen_planner, DEC); - SERIAL_ECHOPGM("SDLEN_CMDQ="); MYSERIAL.println(sdlen_cmdqueue, DEC); - SERIAL_ECHOPGM("PLANNERBLOCKS="); MYSERIAL.println(int(nplanner_blocks), DEC); - SERIAL_ECHOPGM("SDSAVED="); MYSERIAL.println(saved_sdpos, DEC); - //SERIAL_ECHOPGM("SDFILELEN="); MYSERIAL.println(card.fileSize(), DEC); - - - { - card.setIndex(saved_sdpos); - SERIAL_ECHOLNPGM("Content of planner buffer: "); - for (unsigned int idx = 0; idx < sdlen_planner; ++ idx) - MYSERIAL.print(char(card.get())); - SERIAL_ECHOLNPGM("Content of command buffer: "); - for (unsigned int idx = 0; idx < sdlen_cmdqueue; ++ idx) - MYSERIAL.print(char(card.get())); - SERIAL_ECHOLNPGM("End of command buffer"); - } - { - // Print the content of the planner buffer, line by line: - card.setIndex(saved_sdpos); - int8_t iline = 0; - for (unsigned char idx = block_buffer_tail; idx != block_buffer_head; idx = (idx + 1) & (BLOCK_BUFFER_SIZE - 1), ++ iline) { - SERIAL_ECHOPGM("Planner line (from file): "); - MYSERIAL.print(int(iline), DEC); - SERIAL_ECHOPGM(", length: "); - MYSERIAL.print(block_buffer[idx].sdlen, DEC); - SERIAL_ECHOPGM(", steps: ("); - MYSERIAL.print(block_buffer[idx].steps_x, DEC); - SERIAL_ECHOPGM(","); - MYSERIAL.print(block_buffer[idx].steps_y, DEC); - SERIAL_ECHOPGM(","); - MYSERIAL.print(block_buffer[idx].steps_z, DEC); - SERIAL_ECHOPGM(","); - MYSERIAL.print(block_buffer[idx].steps_e, DEC); - SERIAL_ECHOPGM("), events: "); - MYSERIAL.println(block_buffer[idx].step_event_count, DEC); - for (int len = block_buffer[idx].sdlen; len > 0; -- len) - MYSERIAL.print(char(card.get())); + SERIAL_ECHOPGM("SDPOS_ATOMIC="); + MYSERIAL.println(sdpos_atomic, DEC); + SERIAL_ECHOPGM("SDPOS="); + MYSERIAL.println(card.get_sdpos(), DEC); + SERIAL_ECHOPGM("SDLEN_PLAN="); + MYSERIAL.println(sdlen_planner, DEC); + SERIAL_ECHOPGM("SDLEN_CMDQ="); + MYSERIAL.println(sdlen_cmdqueue, DEC); + SERIAL_ECHOPGM("PLANNERBLOCKS="); + MYSERIAL.println(int(nplanner_blocks), DEC); + SERIAL_ECHOPGM("SDSAVED="); + MYSERIAL.println(saved_sdpos, DEC); + //SERIAL_ECHOPGM("SDFILELEN="); MYSERIAL.println(card.fileSize(), DEC); + + + { + card.setIndex(saved_sdpos); + SERIAL_ECHOLNPGM("Content of planner buffer: "); + for (unsigned int idx = 0; idx < sdlen_planner; ++ idx) + MYSERIAL.print(char(card.get())); + SERIAL_ECHOLNPGM("Content of command buffer: "); + for (unsigned int idx = 0; idx < sdlen_cmdqueue; ++ idx) + MYSERIAL.print(char(card.get())); + SERIAL_ECHOLNPGM("End of command buffer"); } - } - { - // Print the content of the command buffer, line by line: - int8_t iline = 0; - union { - struct { - char lo; - char hi; - } lohi; - uint16_t value; - } sdlen_single; - int _bufindr = bufindr; - for (int _buflen = buflen; _buflen > 0; ++ iline) { - if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) { - sdlen_single.lohi.lo = cmdbuffer[_bufindr + 1]; - sdlen_single.lohi.hi = cmdbuffer[_bufindr + 2]; - } - SERIAL_ECHOPGM("Buffer line (from buffer): "); - MYSERIAL.print(int(iline), DEC); - SERIAL_ECHOPGM(", type: "); - MYSERIAL.print(int(cmdbuffer[_bufindr]), DEC); - SERIAL_ECHOPGM(", len: "); - MYSERIAL.println(sdlen_single.value, DEC); - // Print the content of the buffer line. - MYSERIAL.println(cmdbuffer + _bufindr + CMDHDRSIZE); - - SERIAL_ECHOPGM("Buffer line (from file): "); - MYSERIAL.println(int(iline), DEC); - for (; sdlen_single.value > 0; -- sdlen_single.value) - MYSERIAL.print(char(card.get())); - - if (-- _buflen == 0) - break; - // First skip the current command ID and iterate up to the end of the string. - for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ; - // Second, skip the end of string null character and iterate until a nonzero command ID is found. - for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ; - // If the end of the buffer was empty, - if (_bufindr == sizeof(cmdbuffer)) { - // skip to the start and find the nonzero command. - for (_bufindr = 0; cmdbuffer[_bufindr] == 0; ++ _bufindr) ; + { + // Print the content of the planner buffer, line by line: + card.setIndex(saved_sdpos); + int8_t iline = 0; + for (unsigned char idx = block_buffer_tail; idx != block_buffer_head; idx = (idx + 1) & (BLOCK_BUFFER_SIZE - 1), ++ iline) { + SERIAL_ECHOPGM("Planner line (from file): "); + MYSERIAL.print(int(iline), DEC); + SERIAL_ECHOPGM(", length: "); + MYSERIAL.print(block_buffer[idx].sdlen, DEC); + SERIAL_ECHOPGM(", steps: ("); + MYSERIAL.print(block_buffer[idx].steps_x, DEC); + SERIAL_ECHOPGM(","); + MYSERIAL.print(block_buffer[idx].steps_y, DEC); + SERIAL_ECHOPGM(","); + MYSERIAL.print(block_buffer[idx].steps_z, DEC); + SERIAL_ECHOPGM(","); + MYSERIAL.print(block_buffer[idx].steps_e, DEC); + SERIAL_ECHOPGM("), events: "); + MYSERIAL.println(block_buffer[idx].step_event_count, DEC); + for (int len = block_buffer[idx].sdlen; len > 0; -- len) + MYSERIAL.print(char(card.get())); + } + } + { + // Print the content of the command buffer, line by line: + int8_t iline = 0; + union { + struct { + char lo; + char hi; + } lohi; + uint16_t value; + } sdlen_single; + int _bufindr = bufindr; + for (int _buflen = buflen; _buflen > 0; ++ iline) { + if (cmdbuffer[_bufindr] == CMDBUFFER_CURRENT_TYPE_SDCARD) { + sdlen_single.lohi.lo = cmdbuffer[_bufindr + 1]; + sdlen_single.lohi.hi = cmdbuffer[_bufindr + 2]; + } + SERIAL_ECHOPGM("Buffer line (from buffer): "); + MYSERIAL.print(int(iline), DEC); + SERIAL_ECHOPGM(", type: "); + MYSERIAL.print(int(cmdbuffer[_bufindr]), DEC); + SERIAL_ECHOPGM(", len: "); + MYSERIAL.println(sdlen_single.value, DEC); + // Print the content of the buffer line. + MYSERIAL.println(cmdbuffer + _bufindr + CMDHDRSIZE); + + SERIAL_ECHOPGM("Buffer line (from file): "); + MYSERIAL.println(int(iline), DEC); + for (; sdlen_single.value > 0; -- sdlen_single.value) + MYSERIAL.print(char(card.get())); + + if (-- _buflen == 0) + break; + // First skip the current command ID and iterate up to the end of the string. + for (_bufindr += CMDHDRSIZE; cmdbuffer[_bufindr] != 0; ++ _bufindr) ; + // Second, skip the end of string null character and iterate until a nonzero command ID is found. + for (++ _bufindr; _bufindr < sizeof(cmdbuffer) && cmdbuffer[_bufindr] == 0; ++ _bufindr) ; + // If the end of the buffer was empty, + if (_bufindr == sizeof(cmdbuffer)) { + // skip to the start and find the nonzero command. + for (_bufindr = 0; cmdbuffer[_bufindr] == 0; ++ _bufindr) ; + } } } - } #endif #if 0 - saved_feedrate2 = feedrate; //save feedrate + saved_feedrate2 = feedrate; //save feedrate #else - // Try to deduce the feedrate from the first block of the planner. - // Speed is in mm/min. - saved_feedrate2 = blocks_queued() ? (block_buffer[block_buffer_tail].nominal_speed * 60.f) : feedrate; + // Try to deduce the feedrate from the first block of the planner. + // Speed is in mm/min. + saved_feedrate2 = blocks_queued() ? (block_buffer[block_buffer_tail].nominal_speed * 60.f) : feedrate; #endif - planner_abort_hard(); //abort printing - memcpy(saved_pos, current_position, sizeof(saved_pos)); - saved_active_extruder = active_extruder; //save active_extruder - saved_extruder_temperature = degTargetHotend(active_extruder); + planner_abort_hard(); //abort printing + memcpy(saved_pos, current_position, sizeof(saved_pos)); + saved_active_extruder = active_extruder; //save active_extruder + saved_extruder_temperature = degTargetHotend(active_extruder); - saved_extruder_under_pressure = extruder_under_pressure; //extruder under pressure flag - currently unused - saved_extruder_relative_mode = axis_relative_modes[E_AXIS]; - saved_fanSpeed = fanSpeed; - cmdqueue_reset(); //empty cmdqueue - card.sdprinting = false; + saved_extruder_under_pressure = extruder_under_pressure; //extruder under pressure flag - currently unused + saved_extruder_relative_mode = axis_relative_modes[E_AXIS]; + saved_fanSpeed = fanSpeed; + cmdqueue_reset(); //empty cmdqueue + card.sdprinting = false; // card.closefile(); - saved_printing = true; - // We may have missed a stepper timer interrupt. Be safe than sorry, reset the stepper timer before re-enabling interrupts. - st_reset_timer(); - sei(); - if ((z_move != 0) || (e_move != 0)) { // extruder or z move + saved_printing = true; + // We may have missed a stepper timer interrupt. Be safe than sorry, reset the stepper timer before re-enabling interrupts. + st_reset_timer(); + sei(); + if ((z_move != 0) || (e_move != 0)) { // extruder or z move #if 1 - // Rather than calling plan_buffer_line directly, push the move into the command queue, - char buf[48]; + // Rather than calling plan_buffer_line directly, push the move into the command queue, + char buf[48]; - // First unretract (relative extrusion) - if(!saved_extruder_relative_mode){ - strcpy_P(buf, PSTR("M83")); - enquecommand(buf, false); - } - - //retract 45mm/s - strcpy_P(buf, PSTR("G1 E")); - dtostrf(e_move, 6, 3, buf + strlen(buf)); - strcat_P(buf, PSTR(" F")); - dtostrf(2700, 8, 3, buf + strlen(buf)); - enquecommand(buf, false); - - // Then lift Z axis - strcpy_P(buf, PSTR("G1 Z")); - dtostrf(saved_pos[Z_AXIS] + z_move, 8, 3, buf + strlen(buf)); - strcat_P(buf, PSTR(" F")); - dtostrf(homing_feedrate[Z_AXIS], 8, 3, buf + strlen(buf)); - // At this point the command queue is empty. - enquecommand(buf, false); - // If this call is invoked from the main Arduino loop() function, let the caller know that the command - // in the command queue is not the original command, but a new one, so it should not be removed from the queue. - repeatcommand_front(); + // First unretract (relative extrusion) + if(!saved_extruder_relative_mode) { + strcpy_P(buf, PSTR("M83")); + enquecommand(buf, false); + } + + //retract 45mm/s + strcpy_P(buf, PSTR("G1 E")); + dtostrf(e_move, 6, 3, buf + strlen(buf)); + strcat_P(buf, PSTR(" F")); + dtostrf(2700, 8, 3, buf + strlen(buf)); + enquecommand(buf, false); + + // Then lift Z axis + strcpy_P(buf, PSTR("G1 Z")); + dtostrf(saved_pos[Z_AXIS] + z_move, 8, 3, buf + strlen(buf)); + strcat_P(buf, PSTR(" F")); + dtostrf(homing_feedrate[Z_AXIS], 8, 3, buf + strlen(buf)); + // At this point the command queue is empty. + enquecommand(buf, false); + // If this call is invoked from the main Arduino loop() function, let the caller know that the command + // in the command queue is not the original command, but a new one, so it should not be removed from the queue. + repeatcommand_front(); #else - plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS] + z_move, saved_pos[E_AXIS] + e_move, homing_feedrate[Z_AXIS], active_extruder); - st_synchronize(); //wait moving - memcpy(current_position, saved_pos, sizeof(saved_pos)); - memcpy(destination, current_position, sizeof(destination)); + plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS] + z_move, saved_pos[E_AXIS] + e_move, homing_feedrate[Z_AXIS], active_extruder); + st_synchronize(); //wait moving + memcpy(current_position, saved_pos, sizeof(saved_pos)); + memcpy(destination, current_position, sizeof(destination)); #endif - } + } } //! @brief Restore print from ram @@ -8869,150 +8974,150 @@ void stop_and_save_print_to_ram(float z_move, float e_move) //! @param e_move void restore_print_from_ram_and_continue(float e_move) { - if (!saved_printing) return; + if (!saved_printing) return; // for (int axis = X_AXIS; axis <= E_AXIS; axis++) // current_position[axis] = st_get_position_mm(axis); - active_extruder = saved_active_extruder; //restore active_extruder - setTargetHotendSafe(saved_extruder_temperature,saved_active_extruder); - heating_status = 1; - wait_for_heater(millis(),saved_active_extruder); - heating_status = 2; - feedrate = saved_feedrate2; //restore feedrate - axis_relative_modes[E_AXIS] = saved_extruder_relative_mode; - fanSpeed = saved_fanSpeed; - float e = saved_pos[E_AXIS] - e_move; - plan_set_e_position(e); - //first move print head in XY to the saved position: - plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], current_position[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder); - st_synchronize(); - //then move Z - plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder); - st_synchronize(); - //and finaly unretract (35mm/s) - plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS], 35, active_extruder); - st_synchronize(); - - memcpy(current_position, saved_pos, sizeof(saved_pos)); - memcpy(destination, current_position, sizeof(destination)); - if (saved_printing_type == PRINTING_TYPE_SD) { //was sd printing - card.setIndex(saved_sdpos); - sdpos_atomic = saved_sdpos; - card.sdprinting = true; - printf_P(PSTR("ok\n")); //dummy response because of octoprint is waiting for this - } - else if (saved_printing_type == PRINTING_TYPE_USB) { //was usb printing - gcode_LastN = saved_sdpos; //saved_sdpos was reused for storing line number when usb printing - serial_count = 0; - FlushSerialRequestResend(); - } - else { - //not sd printing nor usb printing - } - lcd_setstatuspgm(_T(WELCOME_MSG)); - saved_printing = false; + active_extruder = saved_active_extruder; //restore active_extruder + setTargetHotendSafe(saved_extruder_temperature,saved_active_extruder); + heating_status = 1; + wait_for_heater(millis(),saved_active_extruder); + heating_status = 2; + feedrate = saved_feedrate2; //restore feedrate + axis_relative_modes[E_AXIS] = saved_extruder_relative_mode; + fanSpeed = saved_fanSpeed; + float e = saved_pos[E_AXIS] - e_move; + plan_set_e_position(e); + //first move print head in XY to the saved position: + plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], current_position[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder); + st_synchronize(); + //then move Z + plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS] - e_move, homing_feedrate[Z_AXIS]/13, active_extruder); + st_synchronize(); + //and finaly unretract (35mm/s) + plan_buffer_line(saved_pos[X_AXIS], saved_pos[Y_AXIS], saved_pos[Z_AXIS], saved_pos[E_AXIS], 35, active_extruder); + st_synchronize(); + + memcpy(current_position, saved_pos, sizeof(saved_pos)); + memcpy(destination, current_position, sizeof(destination)); + if (saved_printing_type == PRINTING_TYPE_SD) { //was sd printing + card.setIndex(saved_sdpos); + sdpos_atomic = saved_sdpos; + card.sdprinting = true; + printf_P(PSTR("ok\n")); //dummy response because of octoprint is waiting for this + } + else if (saved_printing_type == PRINTING_TYPE_USB) { //was usb printing + gcode_LastN = saved_sdpos; //saved_sdpos was reused for storing line number when usb printing + serial_count = 0; + FlushSerialRequestResend(); + } + else { + //not sd printing nor usb printing + } + lcd_setstatuspgm(_T(WELCOME_MSG)); + saved_printing = false; } void print_world_coordinates() { - printf_P(_N("world coordinates: (%.3f, %.3f, %.3f)\n"), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); + printf_P(_N("world coordinates: (%.3f, %.3f, %.3f)\n"), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); } void print_physical_coordinates() { - printf_P(_N("physical coordinates: (%.3f, %.3f, %.3f)\n"), st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS), st_get_position_mm(Z_AXIS)); + printf_P(_N("physical coordinates: (%.3f, %.3f, %.3f)\n"), st_get_position_mm(X_AXIS), st_get_position_mm(Y_AXIS), st_get_position_mm(Z_AXIS)); } void print_mesh_bed_leveling_table() { - SERIAL_ECHOPGM("mesh bed leveling: "); - for (int8_t y = 0; y < MESH_NUM_Y_POINTS; ++ y) - for (int8_t x = 0; x < MESH_NUM_Y_POINTS; ++ x) { - MYSERIAL.print(mbl.z_values[y][x], 3); - SERIAL_ECHOPGM(" "); - } - SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("mesh bed leveling: "); + for (int8_t y = 0; y < MESH_NUM_Y_POINTS; ++ y) + for (int8_t x = 0; x < MESH_NUM_Y_POINTS; ++ x) { + MYSERIAL.print(mbl.z_values[y][x], 3); + SERIAL_ECHOPGM(" "); + } + SERIAL_ECHOLNPGM(""); } uint16_t print_time_remaining() { - uint16_t print_t = PRINT_TIME_REMAINING_INIT; -#ifdef TMC2130 - if (SilentModeMenu == SILENT_MODE_OFF) print_t = print_time_remaining_normal; - else print_t = print_time_remaining_silent; + uint16_t print_t = PRINT_TIME_REMAINING_INIT; +#ifdef TMC2130 + if (SilentModeMenu == SILENT_MODE_OFF) print_t = print_time_remaining_normal; + else print_t = print_time_remaining_silent; #else - print_t = print_time_remaining_normal; + print_t = print_time_remaining_normal; #endif //TMC2130 - if ((print_t != PRINT_TIME_REMAINING_INIT) && (feedmultiply != 0)) print_t = 100ul * print_t / feedmultiply; - return print_t; + if ((print_t != PRINT_TIME_REMAINING_INIT) && (feedmultiply != 0)) print_t = 100ul * print_t / feedmultiply; + return print_t; } uint8_t calc_percent_done() { - //in case that we have information from M73 gcode return percentage counted by slicer, else return percentage counted as byte_printed/filesize - uint8_t percent_done = 0; + //in case that we have information from M73 gcode return percentage counted by slicer, else return percentage counted as byte_printed/filesize + uint8_t percent_done = 0; #ifdef TMC2130 - if (SilentModeMenu == SILENT_MODE_OFF && print_percent_done_normal <= 100) { - percent_done = print_percent_done_normal; - } - else if (print_percent_done_silent <= 100) { - percent_done = print_percent_done_silent; - } + if (SilentModeMenu == SILENT_MODE_OFF && print_percent_done_normal <= 100) { + percent_done = print_percent_done_normal; + } + else if (print_percent_done_silent <= 100) { + percent_done = print_percent_done_silent; + } #else - if (print_percent_done_normal <= 100) { - percent_done = print_percent_done_normal; - } + if (print_percent_done_normal <= 100) { + percent_done = print_percent_done_normal; + } #endif //TMC2130 - else { - percent_done = card.percentDone(); - } - return percent_done; + else { + percent_done = card.percentDone(); + } + return percent_done; } static void print_time_remaining_init() { - print_time_remaining_normal = PRINT_TIME_REMAINING_INIT; - print_time_remaining_silent = PRINT_TIME_REMAINING_INIT; - print_percent_done_normal = PRINT_PERCENT_DONE_INIT; - print_percent_done_silent = PRINT_PERCENT_DONE_INIT; + print_time_remaining_normal = PRINT_TIME_REMAINING_INIT; + print_time_remaining_silent = PRINT_TIME_REMAINING_INIT; + print_percent_done_normal = PRINT_PERCENT_DONE_INIT; + print_percent_done_silent = PRINT_PERCENT_DONE_INIT; } void load_filament_final_feed() { - current_position[E_AXIS]+= FILAMENTCHANGE_FINALFEED; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_EFEED_FINAL, active_extruder); + current_position[E_AXIS]+= FILAMENTCHANGE_FINALFEED; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_EFEED_FINAL, active_extruder); } void M600_check_state() { - //Wait for user to check the state - lcd_change_fil_state = 0; - while (lcd_change_fil_state != 1){ - lcd_change_fil_state = 0; - KEEPALIVE_STATE(PAUSED_FOR_USER); - lcd_alright(); - KEEPALIVE_STATE(IN_HANDLER); - switch(lcd_change_fil_state){ - // Filament failed to load so load it again - case 2: - if (mmu_enabled) - mmu_M600_load_filament(false); //nonautomatic load; change to "wrong filament loaded" option? - else - M600_load_filament_movements(); - break; - - // Filament loaded properly but color is not clear - case 3: - st_synchronize(); - load_filament_final_feed(); - lcd_loading_color(); - st_synchronize(); - break; - - // Everything good - default: - lcd_change_success(); - break; - } - } + //Wait for user to check the state + lcd_change_fil_state = 0; + while (lcd_change_fil_state != 1) { + lcd_change_fil_state = 0; + KEEPALIVE_STATE(PAUSED_FOR_USER); + lcd_alright(); + KEEPALIVE_STATE(IN_HANDLER); + switch(lcd_change_fil_state) { + // Filament failed to load so load it again + case 2: + if (mmu_enabled) + mmu_M600_load_filament(false); //nonautomatic load; change to "wrong filament loaded" option? + else + M600_load_filament_movements(); + break; + + // Filament loaded properly but color is not clear + case 3: + st_synchronize(); + load_filament_final_feed(); + lcd_loading_color(); + st_synchronize(); + break; + + // Everything good + default: + lcd_change_success(); + break; + } + } } //! @brief Wait for user action @@ -9023,164 +9128,164 @@ void M600_check_state() //! @param HotendTempBckp Temperature to be restored for active extruder, after user resolves MMU problem. void M600_wait_for_user(float HotendTempBckp) { - KEEPALIVE_STATE(PAUSED_FOR_USER); - - int counterBeep = 0; - unsigned long waiting_start_time = millis(); - uint8_t wait_for_user_state = 0; - lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD)); - bool bFirst=true; - - while (!(wait_for_user_state == 0 && lcd_clicked())){ - manage_heater(); - manage_inactivity(true); - - #if BEEPER > 0 - if (counterBeep == 500) { - counterBeep = 0; - } - SET_OUTPUT(BEEPER); - if (counterBeep == 0) { - if((eSoundMode==e_SOUND_MODE_LOUD)||((eSoundMode==e_SOUND_MODE_ONCE)&&bFirst)) - { - bFirst=false; - WRITE(BEEPER, HIGH); - } - } - if (counterBeep == 20) { - WRITE(BEEPER, LOW); - } - - counterBeep++; - #endif //BEEPER > 0 - - switch (wait_for_user_state) { - case 0: //nozzle is hot, waiting for user to press the knob to unload filament - delay_keep_alive(4); - - if (millis() > waiting_start_time + (unsigned long)M600_TIMEOUT * 1000) { - lcd_display_message_fullscreen_P(_i("Press knob to preheat nozzle and continue."));////MSG_PRESS_TO_PREHEAT c=20 r=4 - wait_for_user_state = 1; - setAllTargetHotends(0); - st_synchronize(); - disable_e0(); - disable_e1(); - disable_e2(); - } - break; - case 1: //nozzle target temperature is set to zero, waiting for user to start nozzle preheat - delay_keep_alive(4); - - if (lcd_clicked()) { - setTargetHotend(HotendTempBckp, active_extruder); - lcd_wait_for_heater(); - - wait_for_user_state = 2; - } - break; - case 2: //waiting for nozzle to reach target temperature - - if (abs(degTargetHotend(active_extruder) - degHotend(active_extruder)) < 1) { - lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD)); - waiting_start_time = millis(); - wait_for_user_state = 0; - } - else { - counterBeep = 20; //beeper will be inactive during waiting for nozzle preheat - lcd_set_cursor(1, 4); - lcd_print(ftostr3(degHotend(active_extruder))); - } - break; - - } - - } - WRITE(BEEPER, LOW); + KEEPALIVE_STATE(PAUSED_FOR_USER); + + int counterBeep = 0; + unsigned long waiting_start_time = millis(); + uint8_t wait_for_user_state = 0; + lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD)); + bool bFirst=true; + + while (!(wait_for_user_state == 0 && lcd_clicked())) { + manage_heater(); + manage_inactivity(true); + +#if BEEPER > 0 + if (counterBeep == 500) { + counterBeep = 0; + } + SET_OUTPUT(BEEPER); + if (counterBeep == 0) { + if((eSoundMode==e_SOUND_MODE_LOUD)||((eSoundMode==e_SOUND_MODE_ONCE)&&bFirst)) + { + bFirst=false; + WRITE(BEEPER, HIGH); + } + } + if (counterBeep == 20) { + WRITE(BEEPER, LOW); + } + + counterBeep++; +#endif //BEEPER > 0 + + switch (wait_for_user_state) { + case 0: //nozzle is hot, waiting for user to press the knob to unload filament + delay_keep_alive(4); + + if (millis() > waiting_start_time + (unsigned long)M600_TIMEOUT * 1000) { + lcd_display_message_fullscreen_P(_i("Press knob to preheat nozzle and continue."));////MSG_PRESS_TO_PREHEAT c=20 r=4 + wait_for_user_state = 1; + setAllTargetHotends(0); + st_synchronize(); + disable_e0(); + disable_e1(); + disable_e2(); + } + break; + case 1: //nozzle target temperature is set to zero, waiting for user to start nozzle preheat + delay_keep_alive(4); + + if (lcd_clicked()) { + setTargetHotend(HotendTempBckp, active_extruder); + lcd_wait_for_heater(); + + wait_for_user_state = 2; + } + break; + case 2: //waiting for nozzle to reach target temperature + + if (abs(degTargetHotend(active_extruder) - degHotend(active_extruder)) < 1) { + lcd_display_message_fullscreen_P(_T(MSG_PRESS_TO_UNLOAD)); + waiting_start_time = millis(); + wait_for_user_state = 0; + } + else { + counterBeep = 20; //beeper will be inactive during waiting for nozzle preheat + lcd_set_cursor(1, 4); + lcd_print(ftostr3(degHotend(active_extruder))); + } + break; + + } + + } + WRITE(BEEPER, LOW); } void M600_load_filament_movements() { #ifdef SNMM - display_loading(); - do - { - current_position[E_AXIS] += 0.002; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); - delay_keep_alive(2); - } - while (!lcd_clicked()); - st_synchronize(); - current_position[E_AXIS] += bowden_length[mmu_extruder]; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000, active_extruder); - current_position[E_AXIS] += FIL_LOAD_LENGTH - 60; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1400, active_extruder); - current_position[E_AXIS] += 40; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); - current_position[E_AXIS] += 10; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); + display_loading(); + do + { + current_position[E_AXIS] += 0.002; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 500, active_extruder); + delay_keep_alive(2); + } + while (!lcd_clicked()); + st_synchronize(); + current_position[E_AXIS] += bowden_length[mmu_extruder]; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000, active_extruder); + current_position[E_AXIS] += FIL_LOAD_LENGTH - 60; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1400, active_extruder); + current_position[E_AXIS] += 40; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 400, active_extruder); + current_position[E_AXIS] += 10; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); #else - current_position[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_EFEED_FIRST, active_extruder); -#endif - load_filament_final_feed(); - lcd_loading_filament(); - st_synchronize(); + current_position[E_AXIS]+= FILAMENTCHANGE_FIRSTFEED ; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], FILAMENTCHANGE_EFEED_FIRST, active_extruder); +#endif + load_filament_final_feed(); + lcd_loading_filament(); + st_synchronize(); } void M600_load_filament() { - //load filament for single material and SNMM - lcd_wait_interact(); + //load filament for single material and SNMM + lcd_wait_interact(); - //load_filament_time = millis(); - KEEPALIVE_STATE(PAUSED_FOR_USER); + //load_filament_time = millis(); + KEEPALIVE_STATE(PAUSED_FOR_USER); #ifdef FILAMENT_SENSOR - fsensor_autoload_check_start(); + fsensor_autoload_check_start(); #endif //FILAMENT_SENSOR - while(!lcd_clicked()) - { - manage_heater(); - manage_inactivity(true); + while(!lcd_clicked()) + { + manage_heater(); + manage_inactivity(true); #ifdef FILAMENT_SENSOR - if (fsensor_check_autoload()) - { -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - tone(BEEPER, 1000); - delay_keep_alive(50); - noTone(BEEPER); - break; - } + if (fsensor_check_autoload()) + { + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + tone(BEEPER, 1000); + delay_keep_alive(50); + noTone(BEEPER); + break; + } #endif //FILAMENT_SENSOR - } + } #ifdef FILAMENT_SENSOR - fsensor_autoload_check_stop(); + fsensor_autoload_check_stop(); #endif //FILAMENT_SENSOR - KEEPALIVE_STATE(IN_HANDLER); + KEEPALIVE_STATE(IN_HANDLER); #ifdef FSENSOR_QUALITY - fsensor_oq_meassure_start(70); + fsensor_oq_meassure_start(70); #endif //FSENSOR_QUALITY - M600_load_filament_movements(); + M600_load_filament_movements(); -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - tone(BEEPER, 500); - delay_keep_alive(50); - noTone(BEEPER); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + tone(BEEPER, 500); + delay_keep_alive(50); + noTone(BEEPER); #ifdef FSENSOR_QUALITY - fsensor_oq_meassure_stop(); - - if (!fsensor_oq_result()) - { - bool disable = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Fil. sensor response is poor, disable it?"), false, true); - lcd_update_enable(true); - lcd_update(2); - if (disable) - fsensor_disable(); - } + fsensor_oq_meassure_stop(); + + if (!fsensor_oq_result()) + { + bool disable = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Fil. sensor response is poor, disable it?"), false, true); + lcd_update_enable(true); + lcd_update(2); + if (disable) + fsensor_disable(); + } #endif //FSENSOR_QUALITY - lcd_update_enable(false); + lcd_update_enable(false); } #define FIL_LOAD_LENGTH 60 diff --git a/Firmware/Sd2Card.cpp b/Firmware/Sd2Card.cpp index 0154ee03c7..1a4406d8d8 100755 --- a/Firmware/Sd2Card.cpp +++ b/Firmware/Sd2Card.cpp @@ -34,49 +34,49 @@ * Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6] */ static void spiInit(uint8_t spiRate) { - // See avr processor documentation - SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1); - SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X; + // See avr processor documentation + SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1); + SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X; } //------------------------------------------------------------------------------ /** SPI receive a byte */ static uint8_t spiRec() { - SPDR = 0XFF; - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - return SPDR; + SPDR = 0XFF; + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + return SPDR; } //------------------------------------------------------------------------------ /** SPI read data - only one call so force inline */ static inline __attribute__((always_inline)) void spiRead(uint8_t* buf, uint16_t nbyte) { - if (nbyte-- == 0) return; - SPDR = 0XFF; - for (uint16_t i = 0; i < nbyte; i++) { - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - buf[i] = SPDR; + if (nbyte-- == 0) return; SPDR = 0XFF; - } - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - buf[nbyte] = SPDR; + for (uint16_t i = 0; i < nbyte; i++) { + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + buf[i] = SPDR; + SPDR = 0XFF; + } + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + buf[nbyte] = SPDR; } //------------------------------------------------------------------------------ /** SPI send a byte */ static void spiSend(uint8_t b) { - SPDR = b; - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + SPDR = b; + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } } //------------------------------------------------------------------------------ /** SPI send block - only one call so force inline */ static inline __attribute__((always_inline)) - void spiSendBlock(uint8_t token, const uint8_t* buf) { - SPDR = token; - for (uint16_t i = 0; i < 512; i += 2) { - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - SPDR = buf[i]; +void spiSendBlock(uint8_t token, const uint8_t* buf) { + SPDR = token; + for (uint16_t i = 0; i < 512; i += 2) { + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + SPDR = buf[i]; + while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } + SPDR = buf[i + 1]; + } while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } - SPDR = buf[i + 1]; - } - while (!(SPSR & (1 << SPIF))) { /* Intentionally left empty */ } } //------------------------------------------------------------------------------ #else // SOFTWARE_SPI @@ -86,96 +86,96 @@ static inline __attribute__((always_inline)) //------------------------------------------------------------------------------ /** Soft SPI receive byte */ static uint8_t spiRec() { - uint8_t data = 0; - // no interrupts during byte receive - about 8 us - cli(); - // output pin high - like sending 0XFF - fastDigitalWrite(SPI_MOSI_PIN, HIGH); + uint8_t data = 0; + // no interrupts during byte receive - about 8 us + cli(); + // output pin high - like sending 0XFF + fastDigitalWrite(SPI_MOSI_PIN, HIGH); - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, HIGH); + for (uint8_t i = 0; i < 8; i++) { + fastDigitalWrite(SPI_SCK_PIN, HIGH); - // adjust so SCK is nice - nop; - nop; + // adjust so SCK is nice + nop; + nop; - data <<= 1; + data <<= 1; - if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; + if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; - fastDigitalWrite(SPI_SCK_PIN, LOW); - } - // enable interrupts - sei(); - return data; + fastDigitalWrite(SPI_SCK_PIN, LOW); + } + // enable interrupts + sei(); + return data; } //------------------------------------------------------------------------------ /** Soft SPI read data */ static void spiRead(uint8_t* buf, uint16_t nbyte) { - for (uint16_t i = 0; i < nbyte; i++) { - buf[i] = spiRec(); - } + for (uint16_t i = 0; i < nbyte; i++) { + buf[i] = spiRec(); + } } //------------------------------------------------------------------------------ /** Soft SPI send byte */ static void spiSend(uint8_t data) { - // no interrupts during byte send - about 8 us - cli(); - for (uint8_t i = 0; i < 8; i++) { - fastDigitalWrite(SPI_SCK_PIN, LOW); + // no interrupts during byte send - about 8 us + cli(); + for (uint8_t i = 0; i < 8; i++) { + fastDigitalWrite(SPI_SCK_PIN, LOW); - fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); + fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); - data <<= 1; + data <<= 1; - fastDigitalWrite(SPI_SCK_PIN, HIGH); - } - // hold SCK high for a few ns - nop; - nop; - nop; - nop; + fastDigitalWrite(SPI_SCK_PIN, HIGH); + } + // hold SCK high for a few ns + nop; + nop; + nop; + nop; - fastDigitalWrite(SPI_SCK_PIN, LOW); - // enable interrupts - sei(); + fastDigitalWrite(SPI_SCK_PIN, LOW); + // enable interrupts + sei(); } //------------------------------------------------------------------------------ /** Soft SPI send block */ - void spiSendBlock(uint8_t token, const uint8_t* buf) { - spiSend(token); - for (uint16_t i = 0; i < 512; i++) { - spiSend(buf[i]); - } +void spiSendBlock(uint8_t token, const uint8_t* buf) { + spiSend(token); + for (uint16_t i = 0; i < 512; i++) { + spiSend(buf[i]); + } } #endif // SOFTWARE_SPI //------------------------------------------------------------------------------ // send command and return error code. Return zero for OK uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { - // select card - chipSelectLow(); + // select card + chipSelectLow(); - // wait up to 300 ms if busy - waitNotBusy(300); + // wait up to 300 ms if busy + waitNotBusy(300); - // send command - spiSend(cmd | 0x40); + // send command + spiSend(cmd | 0x40); - // send argument - for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); + // send argument + for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); - // send CRC - uint8_t crc = 0XFF; - if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 - if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA - spiSend(crc); + // send CRC + uint8_t crc = 0XFF; + if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 + if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA + spiSend(crc); - // skip stuff byte for stop read - if (cmd == CMD12) spiRec(); + // skip stuff byte for stop read + if (cmd == CMD12) spiRec(); - // wait for response - for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ } - return status_; + // wait for response + for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++) { /* Intentionally left empty */ } + return status_; } //------------------------------------------------------------------------------ /** @@ -185,34 +185,34 @@ uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { * or zero if an error occurs. */ uint32_t Sd2Card::cardSize() { - csd_t csd; - if (!readCSD(&csd)) return 0; - if (csd.v1.csd_ver == 0) { - uint8_t read_bl_len = csd.v1.read_bl_len; - uint16_t c_size = (csd.v1.c_size_high << 10) - | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; - uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) - | csd.v1.c_size_mult_low; - return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); - } else if (csd.v2.csd_ver == 1) { - uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) - | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; - return (c_size + 1) << 10; - } else { - error(SD_CARD_ERROR_BAD_CSD); - return 0; - } + csd_t csd; + if (!readCSD(&csd)) return 0; + if (csd.v1.csd_ver == 0) { + uint8_t read_bl_len = csd.v1.read_bl_len; + uint16_t c_size = (csd.v1.c_size_high << 10) + | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; + uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) + | csd.v1.c_size_mult_low; + return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); + } else if (csd.v2.csd_ver == 1) { + uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) + | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; + return (c_size + 1) << 10; + } else { + error(SD_CARD_ERROR_BAD_CSD); + return 0; + } } //------------------------------------------------------------------------------ void Sd2Card::chipSelectHigh() { - digitalWrite(chipSelectPin_, HIGH); + digitalWrite(chipSelectPin_, HIGH); } //------------------------------------------------------------------------------ void Sd2Card::chipSelectLow() { #ifndef SOFTWARE_SPI - spiInit(spiRate_); + spiInit(spiRate_); #endif // SOFTWARE_SPI - digitalWrite(chipSelectPin_, LOW); + digitalWrite(chipSelectPin_, LOW); } //------------------------------------------------------------------------------ /** Erase a range of blocks. @@ -229,38 +229,38 @@ void Sd2Card::chipSelectLow() { * the value zero, false, is returned for failure. */ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { - csd_t csd; - if (!readCSD(&csd)) goto fail; - // check for single block erase - if (!csd.v1.erase_blk_en) { - // erase size mask - uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; - if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { - // error card can't erase specified area - error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); - goto fail; - } - } - if (type_ != SD_CARD_TYPE_SDHC) { - firstBlock <<= 9; - lastBlock <<= 9; - } - if (cardCommand(CMD32, firstBlock) - || cardCommand(CMD33, lastBlock) - || cardCommand(CMD38, 0)) { - error(SD_CARD_ERROR_ERASE); - goto fail; - } - if (!waitNotBusy(SD_ERASE_TIMEOUT)) { - error(SD_CARD_ERROR_ERASE_TIMEOUT); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; + csd_t csd; + if (!readCSD(&csd)) goto fail; + // check for single block erase + if (!csd.v1.erase_blk_en) { + // erase size mask + uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; + if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) { + // error card can't erase specified area + error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); + goto fail; + } + } + if (type_ != SD_CARD_TYPE_SDHC) { + firstBlock <<= 9; + lastBlock <<= 9; + } + if (cardCommand(CMD32, firstBlock) + || cardCommand(CMD33, lastBlock) + || cardCommand(CMD38, 0)) { + error(SD_CARD_ERROR_ERASE); + goto fail; + } + if (!waitNotBusy(SD_ERASE_TIMEOUT)) { + error(SD_CARD_ERROR_ERASE_TIMEOUT); + goto fail; + } + chipSelectHigh(); + return true; + +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** Determine if card supports single block erase. @@ -269,8 +269,8 @@ bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { * The value zero, false, is returned if single block erase is not supported. */ bool Sd2Card::eraseSingleBlockEnable() { - csd_t csd; - return readCSD(&csd) ? csd.v1.erase_blk_en : false; + csd_t csd; + return readCSD(&csd) ? csd.v1.erase_blk_en : false; } //------------------------------------------------------------------------------ /** @@ -284,84 +284,84 @@ bool Sd2Card::eraseSingleBlockEnable() { * can be determined by calling errorCode() and errorData(). */ bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { - errorCode_ = type_ = 0; - chipSelectPin_ = chipSelectPin; - // 16-bit init start time allows over a minute - uint16_t t0 = (uint16_t)millis(); - uint32_t arg; - - // set pin modes - pinMode(chipSelectPin_, OUTPUT); - chipSelectHigh(); - pinMode(SPI_MISO_PIN, INPUT); - pinMode(SPI_MOSI_PIN, OUTPUT); - pinMode(SPI_SCK_PIN, OUTPUT); + errorCode_ = type_ = 0; + chipSelectPin_ = chipSelectPin; + // 16-bit init start time allows over a minute + uint16_t t0 = (uint16_t)millis(); + uint32_t arg; + + // set pin modes + pinMode(chipSelectPin_, OUTPUT); + chipSelectHigh(); + pinMode(SPI_MISO_PIN, INPUT); + pinMode(SPI_MOSI_PIN, OUTPUT); + pinMode(SPI_SCK_PIN, OUTPUT); #ifndef SOFTWARE_SPI - // SS must be in output mode even it is not chip select - pinMode(SS_PIN, OUTPUT); - // set SS high - may be chip select for another SPI device + // SS must be in output mode even it is not chip select + pinMode(SS_PIN, OUTPUT); + // set SS high - may be chip select for another SPI device #if SET_SPI_SS_HIGH - digitalWrite(SS_PIN, HIGH); + digitalWrite(SS_PIN, HIGH); #endif // SET_SPI_SS_HIGH - // set SCK rate for initialization commands - spiRate_ = SPI_SD_INIT_RATE; - spiInit(spiRate_); + // set SCK rate for initialization commands + spiRate_ = SPI_SD_INIT_RATE; + spiInit(spiRate_); #endif // SOFTWARE_SPI - // must supply min of 74 clock cycles with CS high. - for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); - - // command to go idle in SPI mode - while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_CMD0); - goto fail; - } - } - // check SD version - if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { - type(SD_CARD_TYPE_SD1); - } else { - // only need last byte of r7 response - for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); - if (status_ != 0XAA) { - error(SD_CARD_ERROR_CMD8); - goto fail; - } - type(SD_CARD_TYPE_SD2); - } - // initialize card and send host supports SDHC if SD2 - arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; - - while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { - // check for timeout - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { - error(SD_CARD_ERROR_ACMD41); - goto fail; - } - } - // if SD2 read OCR register to check for SDHC card - if (type() == SD_CARD_TYPE_SD2) { - if (cardCommand(CMD58, 0)) { - error(SD_CARD_ERROR_CMD58); - goto fail; - } - if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); - // discard rest of ocr - contains allowed voltage range - for (uint8_t i = 0; i < 3; i++) spiRec(); - } - chipSelectHigh(); + // must supply min of 74 clock cycles with CS high. + for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); + + // command to go idle in SPI mode + while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_CARD_ERROR_CMD0); + goto fail; + } + } + // check SD version + if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { + type(SD_CARD_TYPE_SD1); + } else { + // only need last byte of r7 response + for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); + if (status_ != 0XAA) { + error(SD_CARD_ERROR_CMD8); + goto fail; + } + type(SD_CARD_TYPE_SD2); + } + // initialize card and send host supports SDHC if SD2 + arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; + + while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { + // check for timeout + if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + error(SD_CARD_ERROR_ACMD41); + goto fail; + } + } + // if SD2 read OCR register to check for SDHC card + if (type() == SD_CARD_TYPE_SD2) { + if (cardCommand(CMD58, 0)) { + error(SD_CARD_ERROR_CMD58); + goto fail; + } + if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); + // discard rest of ocr - contains allowed voltage range + for (uint8_t i = 0; i < 3; i++) spiRec(); + } + chipSelectHigh(); #ifndef SOFTWARE_SPI - return setSckRate(sckRateID); + return setSckRate(sckRateID); #else // SOFTWARE_SPI - return true; + return true; #endif // SOFTWARE_SPI - fail: - chipSelectHigh(); - return false; +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** @@ -374,40 +374,40 @@ bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { */ 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; + 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)) { - error(SD_CARD_ERROR_CMD17); - goto fail; - } - return readData(dst, 512); + // use address if not SDHC card + if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD17, blockNumber)) { + error(SD_CARD_ERROR_CMD17); + goto fail; + } + return readData(dst, 512); #endif - fail: - chipSelectHigh(); - return false; +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** Read one data block in a multiple block read sequence @@ -418,113 +418,113 @@ bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) { * the value zero, false, is returned for failure. */ bool Sd2Card::readData(uint8_t *dst) { - chipSelectLow(); - return readData(dst, 512); + 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 + 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; + 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 - uint16_t t0 = millis(); - while ((status_ = spiRec()) == 0XFF) { - if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { - error(SD_CARD_ERROR_READ_TIMEOUT); - goto fail; - } - } - if (status_ != DATA_START_BLOCK) { - error(SD_CARD_ERROR_READ); - goto fail; - } - // transfer data - spiRead(dst, count); + // wait for start block token + uint16_t t0 = millis(); + while ((status_ = spiRec()) == 0XFF) { + if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { + error(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + if (status_ != DATA_START_BLOCK) { + error(SD_CARD_ERROR_READ); + goto fail; + } + // 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; + 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(); + // discard CRC + spiRec(); + spiRec(); #endif - chipSelectHigh(); - // Toshiba FlashAir Patch. Purge pending status byte. - if (flash_air_compatible_) - spiSend(0XFF); - return true; - - fail: - chipSelectHigh(); - // Toshiba FlashAir Patch. Purge pending status byte. - if (flash_air_compatible_) - spiSend(0XFF); - return false; + chipSelectHigh(); + // Toshiba FlashAir Patch. Purge pending status byte. + if (flash_air_compatible_) + spiSend(0XFF); + return true; + +fail: + chipSelectHigh(); + // Toshiba FlashAir Patch. Purge pending status byte. + if (flash_air_compatible_) + spiSend(0XFF); + return false; } //------------------------------------------------------------------------------ /** read CID or CSR register */ bool Sd2Card::readRegister(uint8_t cmd, void* buf) { - uint8_t* dst = reinterpret_cast(buf); - if (cardCommand(cmd, 0)) { - error(SD_CARD_ERROR_READ_REG); - goto fail; - } - return readData(dst, 16); + uint8_t* dst = reinterpret_cast(buf); + if (cardCommand(cmd, 0)) { + error(SD_CARD_ERROR_READ_REG); + goto fail; + } + return readData(dst, 16); - fail: - chipSelectHigh(); - return false; +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** Start a read multiple blocks sequence. @@ -538,17 +538,17 @@ bool Sd2Card::readRegister(uint8_t cmd, void* buf) { * the value zero, false, is returned for failure. */ bool Sd2Card::readStart(uint32_t blockNumber) { - if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD18, blockNumber)) { - error(SD_CARD_ERROR_CMD18); - goto fail; - } - chipSelectHigh(); - return true; + if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD18, blockNumber)) { + error(SD_CARD_ERROR_CMD18); + goto fail; + } + chipSelectHigh(); + return true; - fail: - chipSelectHigh(); - return false; +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** End a read multiple blocks sequence. @@ -557,17 +557,17 @@ bool Sd2Card::readStart(uint32_t blockNumber) { * the value zero, false, is returned for failure. */ bool Sd2Card::readStop() { - chipSelectLow(); - if (cardCommand(CMD12, 0)) { - error(SD_CARD_ERROR_CMD12); - goto fail; - } - chipSelectHigh(); - return true; + chipSelectLow(); + if (cardCommand(CMD12, 0)) { + error(SD_CARD_ERROR_CMD12); + goto fail; + } + chipSelectHigh(); + return true; - fail: - chipSelectHigh(); - return false; +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** @@ -583,24 +583,24 @@ bool Sd2Card::readStop() { * false, is returned for an invalid value of \a sckRateID. */ bool Sd2Card::setSckRate(uint8_t sckRateID) { - if (sckRateID > 6) { - error(SD_CARD_ERROR_SCK_RATE); - return false; - } - spiRate_ = sckRateID; - return true; + if (sckRateID > 6) { + error(SD_CARD_ERROR_SCK_RATE); + return false; + } + spiRate_ = sckRateID; + return true; } //------------------------------------------------------------------------------ // wait for card to go not busy bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) { - uint16_t t0 = millis(); - while (spiRec() != 0XFF) { - if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; - } - return true; + uint16_t t0 = millis(); + while (spiRec() != 0XFF) { + if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail; + } + return true; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** @@ -612,30 +612,30 @@ bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) { * the value zero, false, is returned for failure. */ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD24, blockNumber)) { - error(SD_CARD_ERROR_CMD24); - goto fail; - } - if (!writeData(DATA_START_BLOCK, src)) goto fail; - - // wait for flash programming to complete - if (!waitNotBusy(SD_WRITE_TIMEOUT)) { - error(SD_CARD_ERROR_WRITE_TIMEOUT); - goto fail; - } - // response is r2 so get and check two bytes for nonzero - if (cardCommand(CMD13, 0) || spiRec()) { - error(SD_CARD_ERROR_WRITE_PROGRAMMING); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; + // use address if not SDHC card + if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD24, blockNumber)) { + error(SD_CARD_ERROR_CMD24); + goto fail; + } + if (!writeData(DATA_START_BLOCK, src)) goto fail; + + // wait for flash programming to complete + if (!waitNotBusy(SD_WRITE_TIMEOUT)) { + error(SD_CARD_ERROR_WRITE_TIMEOUT); + goto fail; + } + // response is r2 so get and check two bytes for nonzero + if (cardCommand(CMD13, 0) || spiRec()) { + error(SD_CARD_ERROR_WRITE_PROGRAMMING); + goto fail; + } + chipSelectHigh(); + return true; + +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** Write one data block in a multiple block write sequence @@ -644,36 +644,36 @@ bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { * the value zero, false, is returned for failure. */ bool Sd2Card::writeData(const uint8_t* src) { - chipSelectLow(); - // wait for previous write to finish - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; - chipSelectHigh(); - return true; - - fail: - error(SD_CARD_ERROR_WRITE_MULTIPLE); - chipSelectHigh(); - return false; + chipSelectLow(); + // wait for previous write to finish + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail; + chipSelectHigh(); + return true; + +fail: + error(SD_CARD_ERROR_WRITE_MULTIPLE); + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ // send one block of data for write block or write multiple blocks bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { - spiSendBlock(token, src); + spiSendBlock(token, src); - spiSend(0xff); // dummy crc - spiSend(0xff); // dummy crc + spiSend(0xff); // dummy crc + spiSend(0xff); // dummy crc - status_ = spiRec(); - if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { - error(SD_CARD_ERROR_WRITE); - goto fail; - } - return true; + status_ = spiRec(); + if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { + error(SD_CARD_ERROR_WRITE); + goto fail; + } + return true; - fail: - chipSelectHigh(); - return false; +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** Start a write multiple blocks sequence. @@ -688,23 +688,23 @@ bool Sd2Card::writeData(uint8_t token, const uint8_t* src) { * the value zero, false, is returned for failure. */ bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { - // send pre-erase count - if (cardAcmd(ACMD23, eraseCount)) { - error(SD_CARD_ERROR_ACMD23); - goto fail; - } - // use address if not SDHC card - if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; - if (cardCommand(CMD25, blockNumber)) { - error(SD_CARD_ERROR_CMD25); - goto fail; - } - chipSelectHigh(); - return true; - - fail: - chipSelectHigh(); - return false; + // send pre-erase count + if (cardAcmd(ACMD23, eraseCount)) { + error(SD_CARD_ERROR_ACMD23); + goto fail; + } + // use address if not SDHC card + if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; + if (cardCommand(CMD25, blockNumber)) { + error(SD_CARD_ERROR_CMD25); + goto fail; + } + chipSelectHigh(); + return true; + +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ /** End a write multiple blocks sequence. @@ -713,17 +713,17 @@ bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { * the value zero, false, is returned for failure. */ bool Sd2Card::writeStop() { - chipSelectLow(); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - spiSend(STOP_TRAN_TOKEN); - if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; - chipSelectHigh(); - return true; - - fail: - error(SD_CARD_ERROR_STOP_TRAN); - chipSelectHigh(); - return false; + chipSelectLow(); + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + spiSend(STOP_TRAN_TOKEN); + if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; + chipSelectHigh(); + return true; + +fail: + error(SD_CARD_ERROR_STOP_TRAN); + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ @@ -731,60 +731,60 @@ bool Sd2Card::writeStop() { //FIXME Vojtech: Copied from a current version of Sd2Card Arduino code. // We shall likely upgrade the rest of the Sd2Card. uint8_t Sd2Card::waitStartBlock(void) { - uint16_t t0 = millis(); - while ((status_ = spiRec()) == 0XFF) { - if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { - error(SD_CARD_ERROR_READ_TIMEOUT); - goto fail; + uint16_t t0 = millis(); + while ((status_ = spiRec()) == 0XFF) { + if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) { + error(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + if (status_ != DATA_START_BLOCK) { + error(SD_CARD_ERROR_READ); + goto fail; } - } - if (status_ != DATA_START_BLOCK) { - error(SD_CARD_ERROR_READ); - goto fail; - } - return true; + return true; - fail: - chipSelectHigh(); - return false; +fail: + chipSelectHigh(); + return false; } -// Toshiba FlashAir support, copied from +// Toshiba FlashAir support, copied from // https://flashair-developers.com/en/documents/tutorials/arduino/ //------------------------------------------------------------------------------ /** Perform Extention Read. */ uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) { - uint16_t i; - - // send command and argument. - if (cardCommand(CMD48, arg)) { - error(SD_CARD_ERROR_CMD48); - goto fail; - } - - // wait for start block token. - if (!waitStartBlock()) { - goto fail; - } - - // receive data - for (i = 0; i < count; ++i) { - dst[i] = spiRec(); - } - - // skip dummy bytes and 16-bit crc. - for (; i < 514; ++i) { - spiRec(); - } + uint16_t i; + + // send command and argument. + if (cardCommand(CMD48, arg)) { + error(SD_CARD_ERROR_CMD48); + goto fail; + } - chipSelectHigh(); - spiSend(0xFF); // dummy clock to force FlashAir finish the command. - return true; + // wait for start block token. + if (!waitStartBlock()) { + goto fail; + } - fail: - chipSelectHigh(); - return false; + // receive data + for (i = 0; i < count; ++i) { + dst[i] = spiRec(); + } + + // skip dummy bytes and 16-bit crc. + for (; i < 514; ++i) { + spiRec(); + } + + chipSelectHigh(); + spiSend(0xFF); // dummy clock to force FlashAir finish the command. + return true; + +fail: + chipSelectHigh(); + return false; } //------------------------------------------------------------------------------ @@ -794,20 +794,20 @@ uint8_t Sd2Card::readExt(uint32_t arg, uint8_t* dst, uint16_t count) { * \return The value one, true, is returned for success and * the value zero, false, is returned for failure. */ -uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func, - uint32_t addr, uint16_t count, uint8_t* dst) { - uint32_t offset = addr & 0x1FF; - if (offset + count > 512) count = 512 - offset; - - if (count == 0) return true; - - uint32_t arg = - (((uint32_t)mio & 0x1) << 31) | - (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) | - ((addr & 0x1FFFF) << 9) | - ((count - 1) & 0x1FF); - - return readExt(arg, dst, count); +uint8_t Sd2Card::readExtMemory(uint8_t mio, uint8_t func, + uint32_t addr, uint16_t count, uint8_t* dst) { + uint32_t offset = addr & 0x1FF; + if (offset + count > 512) count = 512 - offset; + + if (count == 0) return true; + + uint32_t arg = + (((uint32_t)mio & 0x1) << 31) | + (mio ? (((uint32_t)func & 0x7) << 28) : (((uint32_t)func & 0xF) << 27)) | + ((addr & 0x1FFFF) << 9) | + ((count - 1) & 0x1FF); + + return readExt(arg, dst, count); } #endif diff --git a/Firmware/Sd2Card.h b/Firmware/Sd2Card.h index 537d249c96..df6b1f8d69 100755 --- a/Firmware/Sd2Card.h +++ b/Firmware/Sd2Card.h @@ -160,101 +160,115 @@ uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN; * \brief Raw access to SD and SDHC flash memory cards. */ class Sd2Card { - public: - /** Construct an instance of Sd2Card. */ - Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0), flash_air_compatible_(false) {} - uint32_t cardSize(); - bool erase(uint32_t firstBlock, uint32_t lastBlock); - bool eraseSingleBlockEnable(); - /** - * Set SD error code. - * \param[in] code value for error code. - */ - void error(uint8_t code) {errorCode_ = code;} - /** - * \return error code for last error. See Sd2Card.h for a list of error codes. - */ - int errorCode() const {return errorCode_;} - /** \return error data for last error. */ - int errorData() const {return status_;} - /** - * Initialize an SD flash memory card with default clock rate and chip - * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). - * - * \return true for success or false for failure. - */ - bool init(uint8_t sckRateID = SPI_FULL_SPEED, - uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); - bool readBlock(uint32_t block, uint8_t* dst); - /** - * Read a card's CID register. The CID contains card identification - * information such as Manufacturer ID, Product name, Product serial - * number and Manufacturing date. - * - * \param[out] cid pointer to area for returned data. - * - * \return true for success or false for failure. - */ - bool readCID(cid_t* cid) { - return readRegister(CMD10, cid); - } - /** - * Read a card's CSD register. The CSD contains Card-Specific Data that - * provides information regarding access to the card's contents. - * - * \param[out] csd pointer to area for returned data. - * - * \return true for success or false for failure. - */ - bool readCSD(csd_t* csd) { - return readRegister(CMD9, csd); - } - bool readData(uint8_t *dst); - bool readStart(uint32_t blockNumber); - bool readStop(); - bool setSckRate(uint8_t sckRateID); - /** Return the card type: SD V1, SD V2 or SDHC - * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. - */ - int type() const {return type_;} - bool writeBlock(uint32_t blockNumber, const uint8_t* src); - bool writeData(const uint8_t* src); - bool writeStart(uint32_t blockNumber, uint32_t eraseCount); - bool writeStop(); +public: + /** Construct an instance of Sd2Card. */ + Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0), flash_air_compatible_(false) {} + uint32_t cardSize(); + bool erase(uint32_t firstBlock, uint32_t lastBlock); + bool eraseSingleBlockEnable(); + /** + * Set SD error code. + * \param[in] code value for error code. + */ + void error(uint8_t code) { + errorCode_ = code; + } + /** + * \return error code for last error. See Sd2Card.h for a list of error codes. + */ + int errorCode() const { + return errorCode_; + } + /** \return error data for last error. */ + int errorData() const { + return status_; + } + /** + * Initialize an SD flash memory card with default clock rate and chip + * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). + * + * \return true for success or false for failure. + */ + bool init(uint8_t sckRateID = SPI_FULL_SPEED, + uint8_t chipSelectPin = SD_CHIP_SELECT_PIN); + bool readBlock(uint32_t block, uint8_t* dst); + /** + * Read a card's CID register. The CID contains card identification + * information such as Manufacturer ID, Product name, Product serial + * number and Manufacturing date. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCID(cid_t* cid) { + return readRegister(CMD10, cid); + } + /** + * Read a card's CSD register. The CSD contains Card-Specific Data that + * provides information regarding access to the card's contents. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCSD(csd_t* csd) { + return readRegister(CMD9, csd); + } + bool readData(uint8_t *dst); + bool readStart(uint32_t blockNumber); + bool readStop(); + bool setSckRate(uint8_t sckRateID); + /** Return the card type: SD V1, SD V2 or SDHC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. + */ + int type() const { + return type_; + } + bool writeBlock(uint32_t blockNumber, const uint8_t* src); + bool writeData(const uint8_t* src); + bool writeStart(uint32_t blockNumber, uint32_t eraseCount); + bool writeStop(); - // Toshiba FlashAir support - uint8_t readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst); + // Toshiba FlashAir support + uint8_t readExtMemory(uint8_t mio, uint8_t func, uint32_t addr, uint16_t count, uint8_t* dst); - void setFlashAirCompatible(bool flashAirCompatible) { flash_air_compatible_ = flashAirCompatible; } - bool getFlashAirCompatible() const { return flash_air_compatible_; } + void setFlashAirCompatible(bool flashAirCompatible) { + flash_air_compatible_ = flashAirCompatible; + } + bool getFlashAirCompatible() const { + return flash_air_compatible_; + } - private: - //---------------------------------------------------------------------------- - uint8_t chipSelectPin_; - uint8_t errorCode_; - uint8_t spiRate_; - uint8_t status_; - uint8_t type_; - bool flash_air_compatible_; - // private functions - uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { - cardCommand(CMD55, 0); - return cardCommand(cmd, arg); - } - uint8_t cardCommand(uint8_t cmd, uint32_t arg); +private: + //---------------------------------------------------------------------------- + uint8_t chipSelectPin_; + uint8_t errorCode_; + uint8_t spiRate_; + uint8_t status_; + uint8_t type_; + bool flash_air_compatible_; + // private functions + uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { + cardCommand(CMD55, 0); + return cardCommand(cmd, arg); + } + uint8_t cardCommand(uint8_t cmd, uint32_t arg); - bool readData(uint8_t* dst, uint16_t count); - bool readRegister(uint8_t cmd, void* buf); - void chipSelectHigh(); - void chipSelectLow(); - void type(uint8_t value) {type_ = value;} - bool waitNotBusy(uint16_t timeoutMillis); - bool writeData(uint8_t token, const uint8_t* src); + bool readData(uint8_t* dst, uint16_t count); + bool readRegister(uint8_t cmd, void* buf); + void chipSelectHigh(); + void chipSelectLow(); + void type(uint8_t value) { + type_ = value; + } + bool waitNotBusy(uint16_t timeoutMillis); + bool writeData(uint8_t token, const uint8_t* src); - // Toshiba FlashAir support - uint8_t waitStartBlock(void); - uint8_t readExt(uint32_t arg, uint8_t* dst, uint16_t count); + // Toshiba FlashAir support + uint8_t waitStartBlock(void); + uint8_t readExt(uint32_t arg, uint8_t* dst, uint16_t count); }; #endif // Sd2Card_h diff --git a/Firmware/Sd2PinMap.h b/Firmware/Sd2PinMap.h index 8a608731ee..70ea6eaaa6 100755 --- a/Firmware/Sd2PinMap.h +++ b/Firmware/Sd2PinMap.h @@ -27,10 +27,10 @@ //------------------------------------------------------------------------------ /** struct for mapping digital pins */ struct pin_map_t { - volatile uint8_t* ddr; - volatile uint8_t* pin; - volatile uint8_t* port; - uint8_t bit; + volatile uint8_t* ddr; + volatile uint8_t* pin; + volatile uint8_t* port; + uint8_t bit; }; //------------------------------------------------------------------------------ #if defined(__AVR_ATmega1280__)\ @@ -50,76 +50,76 @@ uint8_t const MISO_PIN = 50; // B3 uint8_t const SCK_PIN = 52; // B1 static const pin_map_t digitalPinMap[] = { - {&DDRE, &PINE, &PORTE, 0}, // E0 0 - {&DDRE, &PINE, &PORTE, 1}, // E1 1 - {&DDRE, &PINE, &PORTE, 4}, // E4 2 - {&DDRE, &PINE, &PORTE, 5}, // E5 3 - {&DDRG, &PING, &PORTG, 5}, // G5 4 - {&DDRE, &PINE, &PORTE, 3}, // E3 5 - {&DDRH, &PINH, &PORTH, 3}, // H3 6 - {&DDRH, &PINH, &PORTH, 4}, // H4 7 - {&DDRH, &PINH, &PORTH, 5}, // H5 8 - {&DDRH, &PINH, &PORTH, 6}, // H6 9 - {&DDRB, &PINB, &PORTB, 4}, // B4 10 - {&DDRB, &PINB, &PORTB, 5}, // B5 11 - {&DDRB, &PINB, &PORTB, 6}, // B6 12 - {&DDRB, &PINB, &PORTB, 7}, // B7 13 - {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 - {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 - {&DDRH, &PINH, &PORTH, 1}, // H1 16 - {&DDRH, &PINH, &PORTH, 0}, // H0 17 - {&DDRD, &PIND, &PORTD, 3}, // D3 18 - {&DDRD, &PIND, &PORTD, 2}, // D2 19 - {&DDRD, &PIND, &PORTD, 1}, // D1 20 - {&DDRD, &PIND, &PORTD, 0}, // D0 21 - {&DDRA, &PINA, &PORTA, 0}, // A0 22 - {&DDRA, &PINA, &PORTA, 1}, // A1 23 - {&DDRA, &PINA, &PORTA, 2}, // A2 24 - {&DDRA, &PINA, &PORTA, 3}, // A3 25 - {&DDRA, &PINA, &PORTA, 4}, // A4 26 - {&DDRA, &PINA, &PORTA, 5}, // A5 27 - {&DDRA, &PINA, &PORTA, 6}, // A6 28 - {&DDRA, &PINA, &PORTA, 7}, // A7 29 - {&DDRC, &PINC, &PORTC, 7}, // C7 30 - {&DDRC, &PINC, &PORTC, 6}, // C6 31 - {&DDRC, &PINC, &PORTC, 5}, // C5 32 - {&DDRC, &PINC, &PORTC, 4}, // C4 33 - {&DDRC, &PINC, &PORTC, 3}, // C3 34 - {&DDRC, &PINC, &PORTC, 2}, // C2 35 - {&DDRC, &PINC, &PORTC, 1}, // C1 36 - {&DDRC, &PINC, &PORTC, 0}, // C0 37 - {&DDRD, &PIND, &PORTD, 7}, // D7 38 - {&DDRG, &PING, &PORTG, 2}, // G2 39 - {&DDRG, &PING, &PORTG, 1}, // G1 40 - {&DDRG, &PING, &PORTG, 0}, // G0 41 - {&DDRL, &PINL, &PORTL, 7}, // L7 42 - {&DDRL, &PINL, &PORTL, 6}, // L6 43 - {&DDRL, &PINL, &PORTL, 5}, // L5 44 - {&DDRL, &PINL, &PORTL, 4}, // L4 45 - {&DDRL, &PINL, &PORTL, 3}, // L3 46 - {&DDRL, &PINL, &PORTL, 2}, // L2 47 - {&DDRL, &PINL, &PORTL, 1}, // L1 48 - {&DDRL, &PINL, &PORTL, 0}, // L0 49 - {&DDRB, &PINB, &PORTB, 3}, // B3 50 - {&DDRB, &PINB, &PORTB, 2}, // B2 51 - {&DDRB, &PINB, &PORTB, 1}, // B1 52 - {&DDRB, &PINB, &PORTB, 0}, // B0 53 - {&DDRF, &PINF, &PORTF, 0}, // F0 54 - {&DDRF, &PINF, &PORTF, 1}, // F1 55 - {&DDRF, &PINF, &PORTF, 2}, // F2 56 - {&DDRF, &PINF, &PORTF, 3}, // F3 57 - {&DDRF, &PINF, &PORTF, 4}, // F4 58 - {&DDRF, &PINF, &PORTF, 5}, // F5 59 - {&DDRF, &PINF, &PORTF, 6}, // F6 60 - {&DDRF, &PINF, &PORTF, 7}, // F7 61 - {&DDRK, &PINK, &PORTK, 0}, // K0 62 - {&DDRK, &PINK, &PORTK, 1}, // K1 63 - {&DDRK, &PINK, &PORTK, 2}, // K2 64 - {&DDRK, &PINK, &PORTK, 3}, // K3 65 - {&DDRK, &PINK, &PORTK, 4}, // K4 66 - {&DDRK, &PINK, &PORTK, 5}, // K5 67 - {&DDRK, &PINK, &PORTK, 6}, // K6 68 - {&DDRK, &PINK, &PORTK, 7} // K7 69 + {&DDRE, &PINE, &PORTE, 0}, // E0 0 + {&DDRE, &PINE, &PORTE, 1}, // E1 1 + {&DDRE, &PINE, &PORTE, 4}, // E4 2 + {&DDRE, &PINE, &PORTE, 5}, // E5 3 + {&DDRG, &PING, &PORTG, 5}, // G5 4 + {&DDRE, &PINE, &PORTE, 3}, // E3 5 + {&DDRH, &PINH, &PORTH, 3}, // H3 6 + {&DDRH, &PINH, &PORTH, 4}, // H4 7 + {&DDRH, &PINH, &PORTH, 5}, // H5 8 + {&DDRH, &PINH, &PORTH, 6}, // H6 9 + {&DDRB, &PINB, &PORTB, 4}, // B4 10 + {&DDRB, &PINB, &PORTB, 5}, // B5 11 + {&DDRB, &PINB, &PORTB, 6}, // B6 12 + {&DDRB, &PINB, &PORTB, 7}, // B7 13 + {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 + {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 + {&DDRH, &PINH, &PORTH, 1}, // H1 16 + {&DDRH, &PINH, &PORTH, 0}, // H0 17 + {&DDRD, &PIND, &PORTD, 3}, // D3 18 + {&DDRD, &PIND, &PORTD, 2}, // D2 19 + {&DDRD, &PIND, &PORTD, 1}, // D1 20 + {&DDRD, &PIND, &PORTD, 0}, // D0 21 + {&DDRA, &PINA, &PORTA, 0}, // A0 22 + {&DDRA, &PINA, &PORTA, 1}, // A1 23 + {&DDRA, &PINA, &PORTA, 2}, // A2 24 + {&DDRA, &PINA, &PORTA, 3}, // A3 25 + {&DDRA, &PINA, &PORTA, 4}, // A4 26 + {&DDRA, &PINA, &PORTA, 5}, // A5 27 + {&DDRA, &PINA, &PORTA, 6}, // A6 28 + {&DDRA, &PINA, &PORTA, 7}, // A7 29 + {&DDRC, &PINC, &PORTC, 7}, // C7 30 + {&DDRC, &PINC, &PORTC, 6}, // C6 31 + {&DDRC, &PINC, &PORTC, 5}, // C5 32 + {&DDRC, &PINC, &PORTC, 4}, // C4 33 + {&DDRC, &PINC, &PORTC, 3}, // C3 34 + {&DDRC, &PINC, &PORTC, 2}, // C2 35 + {&DDRC, &PINC, &PORTC, 1}, // C1 36 + {&DDRC, &PINC, &PORTC, 0}, // C0 37 + {&DDRD, &PIND, &PORTD, 7}, // D7 38 + {&DDRG, &PING, &PORTG, 2}, // G2 39 + {&DDRG, &PING, &PORTG, 1}, // G1 40 + {&DDRG, &PING, &PORTG, 0}, // G0 41 + {&DDRL, &PINL, &PORTL, 7}, // L7 42 + {&DDRL, &PINL, &PORTL, 6}, // L6 43 + {&DDRL, &PINL, &PORTL, 5}, // L5 44 + {&DDRL, &PINL, &PORTL, 4}, // L4 45 + {&DDRL, &PINL, &PORTL, 3}, // L3 46 + {&DDRL, &PINL, &PORTL, 2}, // L2 47 + {&DDRL, &PINL, &PORTL, 1}, // L1 48 + {&DDRL, &PINL, &PORTL, 0}, // L0 49 + {&DDRB, &PINB, &PORTB, 3}, // B3 50 + {&DDRB, &PINB, &PORTB, 2}, // B2 51 + {&DDRB, &PINB, &PORTB, 1}, // B1 52 + {&DDRB, &PINB, &PORTB, 0}, // B0 53 + {&DDRF, &PINF, &PORTF, 0}, // F0 54 + {&DDRF, &PINF, &PORTF, 1}, // F1 55 + {&DDRF, &PINF, &PORTF, 2}, // F2 56 + {&DDRF, &PINF, &PORTF, 3}, // F3 57 + {&DDRF, &PINF, &PORTF, 4}, // F4 58 + {&DDRF, &PINF, &PORTF, 5}, // F5 59 + {&DDRF, &PINF, &PORTF, 6}, // F6 60 + {&DDRF, &PINF, &PORTF, 7}, // F7 61 + {&DDRK, &PINK, &PORTK, 0}, // K0 62 + {&DDRK, &PINK, &PORTK, 1}, // K1 63 + {&DDRK, &PINK, &PORTK, 2}, // K2 64 + {&DDRK, &PINK, &PORTK, 3}, // K3 65 + {&DDRK, &PINK, &PORTK, 4}, // K4 66 + {&DDRK, &PINK, &PORTK, 5}, // K5 67 + {&DDRK, &PINK, &PORTK, 6}, // K6 68 + {&DDRK, &PINK, &PORTK, 7} // K7 69 }; //------------------------------------------------------------------------------ #elif defined(__AVR_ATmega644P__)\ @@ -138,38 +138,38 @@ uint8_t const MISO_PIN = 6; // B6 uint8_t const SCK_PIN = 7; // B7 static const pin_map_t digitalPinMap[] = { - {&DDRB, &PINB, &PORTB, 0}, // B0 0 - {&DDRB, &PINB, &PORTB, 1}, // B1 1 - {&DDRB, &PINB, &PORTB, 2}, // B2 2 - {&DDRB, &PINB, &PORTB, 3}, // B3 3 - {&DDRB, &PINB, &PORTB, 4}, // B4 4 - {&DDRB, &PINB, &PORTB, 5}, // B5 5 - {&DDRB, &PINB, &PORTB, 6}, // B6 6 - {&DDRB, &PINB, &PORTB, 7}, // B7 7 - {&DDRD, &PIND, &PORTD, 0}, // D0 8 - {&DDRD, &PIND, &PORTD, 1}, // D1 9 - {&DDRD, &PIND, &PORTD, 2}, // D2 10 - {&DDRD, &PIND, &PORTD, 3}, // D3 11 - {&DDRD, &PIND, &PORTD, 4}, // D4 12 - {&DDRD, &PIND, &PORTD, 5}, // D5 13 - {&DDRD, &PIND, &PORTD, 6}, // D6 14 - {&DDRD, &PIND, &PORTD, 7}, // D7 15 - {&DDRC, &PINC, &PORTC, 0}, // C0 16 - {&DDRC, &PINC, &PORTC, 1}, // C1 17 - {&DDRC, &PINC, &PORTC, 2}, // C2 18 - {&DDRC, &PINC, &PORTC, 3}, // C3 19 - {&DDRC, &PINC, &PORTC, 4}, // C4 20 - {&DDRC, &PINC, &PORTC, 5}, // C5 21 - {&DDRC, &PINC, &PORTC, 6}, // C6 22 - {&DDRC, &PINC, &PORTC, 7}, // C7 23 - {&DDRA, &PINA, &PORTA, 7}, // A7 24 - {&DDRA, &PINA, &PORTA, 6}, // A6 25 - {&DDRA, &PINA, &PORTA, 5}, // A5 26 - {&DDRA, &PINA, &PORTA, 4}, // A4 27 - {&DDRA, &PINA, &PORTA, 3}, // A3 28 - {&DDRA, &PINA, &PORTA, 2}, // A2 29 - {&DDRA, &PINA, &PORTA, 1}, // A1 30 - {&DDRA, &PINA, &PORTA, 0} // A0 31 + {&DDRB, &PINB, &PORTB, 0}, // B0 0 + {&DDRB, &PINB, &PORTB, 1}, // B1 1 + {&DDRB, &PINB, &PORTB, 2}, // B2 2 + {&DDRB, &PINB, &PORTB, 3}, // B3 3 + {&DDRB, &PINB, &PORTB, 4}, // B4 4 + {&DDRB, &PINB, &PORTB, 5}, // B5 5 + {&DDRB, &PINB, &PORTB, 6}, // B6 6 + {&DDRB, &PINB, &PORTB, 7}, // B7 7 + {&DDRD, &PIND, &PORTD, 0}, // D0 8 + {&DDRD, &PIND, &PORTD, 1}, // D1 9 + {&DDRD, &PIND, &PORTD, 2}, // D2 10 + {&DDRD, &PIND, &PORTD, 3}, // D3 11 + {&DDRD, &PIND, &PORTD, 4}, // D4 12 + {&DDRD, &PIND, &PORTD, 5}, // D5 13 + {&DDRD, &PIND, &PORTD, 6}, // D6 14 + {&DDRD, &PIND, &PORTD, 7}, // D7 15 + {&DDRC, &PINC, &PORTC, 0}, // C0 16 + {&DDRC, &PINC, &PORTC, 1}, // C1 17 + {&DDRC, &PINC, &PORTC, 2}, // C2 18 + {&DDRC, &PINC, &PORTC, 3}, // C3 19 + {&DDRC, &PINC, &PORTC, 4}, // C4 20 + {&DDRC, &PINC, &PORTC, 5}, // C5 21 + {&DDRC, &PINC, &PORTC, 6}, // C6 22 + {&DDRC, &PINC, &PORTC, 7}, // C7 23 + {&DDRA, &PINA, &PORTA, 7}, // A7 24 + {&DDRA, &PINA, &PORTA, 6}, // A6 25 + {&DDRA, &PINA, &PORTA, 5}, // A5 26 + {&DDRA, &PINA, &PORTA, 4}, // A4 27 + {&DDRA, &PINA, &PORTA, 3}, // A3 28 + {&DDRA, &PINA, &PORTA, 2}, // A2 29 + {&DDRA, &PINA, &PORTA, 1}, // A1 30 + {&DDRA, &PINA, &PORTA, 0} // A0 31 }; //------------------------------------------------------------------------------ #elif defined(__AVR_ATmega32U4__) @@ -186,31 +186,31 @@ uint8_t const MISO_PIN = 3; // B3 uint8_t const SCK_PIN = 1; // B1 static const pin_map_t digitalPinMap[] = { - {&DDRB, &PINB, &PORTB, 0}, // B0 0 - {&DDRB, &PINB, &PORTB, 1}, // B1 1 - {&DDRB, &PINB, &PORTB, 2}, // B2 2 - {&DDRB, &PINB, &PORTB, 3}, // B3 3 - {&DDRB, &PINB, &PORTB, 7}, // B7 4 - {&DDRD, &PIND, &PORTD, 0}, // D0 5 - {&DDRD, &PIND, &PORTD, 1}, // D1 6 - {&DDRD, &PIND, &PORTD, 2}, // D2 7 - {&DDRD, &PIND, &PORTD, 3}, // D3 8 - {&DDRC, &PINC, &PORTC, 6}, // C6 9 - {&DDRC, &PINC, &PORTC, 7}, // C7 10 - {&DDRD, &PIND, &PORTD, 6}, // D6 11 - {&DDRD, &PIND, &PORTD, 7}, // D7 12 - {&DDRB, &PINB, &PORTB, 4}, // B4 13 - {&DDRB, &PINB, &PORTB, 5}, // B5 14 - {&DDRB, &PINB, &PORTB, 6}, // B6 15 - {&DDRF, &PINF, &PORTF, 7}, // F7 16 - {&DDRF, &PINF, &PORTF, 6}, // F6 17 - {&DDRF, &PINF, &PORTF, 5}, // F5 18 - {&DDRF, &PINF, &PORTF, 4}, // F4 19 - {&DDRF, &PINF, &PORTF, 1}, // F1 20 - {&DDRF, &PINF, &PORTF, 0}, // F0 21 - {&DDRD, &PIND, &PORTD, 4}, // D4 22 - {&DDRD, &PIND, &PORTD, 5}, // D5 23 - {&DDRE, &PINE, &PORTE, 6} // E6 24 + {&DDRB, &PINB, &PORTB, 0}, // B0 0 + {&DDRB, &PINB, &PORTB, 1}, // B1 1 + {&DDRB, &PINB, &PORTB, 2}, // B2 2 + {&DDRB, &PINB, &PORTB, 3}, // B3 3 + {&DDRB, &PINB, &PORTB, 7}, // B7 4 + {&DDRD, &PIND, &PORTD, 0}, // D0 5 + {&DDRD, &PIND, &PORTD, 1}, // D1 6 + {&DDRD, &PIND, &PORTD, 2}, // D2 7 + {&DDRD, &PIND, &PORTD, 3}, // D3 8 + {&DDRC, &PINC, &PORTC, 6}, // C6 9 + {&DDRC, &PINC, &PORTC, 7}, // C7 10 + {&DDRD, &PIND, &PORTD, 6}, // D6 11 + {&DDRD, &PIND, &PORTD, 7}, // D7 12 + {&DDRB, &PINB, &PORTB, 4}, // B4 13 + {&DDRB, &PINB, &PORTB, 5}, // B5 14 + {&DDRB, &PINB, &PORTB, 6}, // B6 15 + {&DDRF, &PINF, &PORTF, 7}, // F7 16 + {&DDRF, &PINF, &PORTF, 6}, // F6 17 + {&DDRF, &PINF, &PORTF, 5}, // F5 18 + {&DDRF, &PINF, &PORTF, 4}, // F4 19 + {&DDRF, &PINF, &PORTF, 1}, // F1 20 + {&DDRF, &PINF, &PORTF, 0}, // F0 21 + {&DDRD, &PIND, &PORTD, 4}, // D4 22 + {&DDRD, &PIND, &PORTD, 5}, // D5 23 + {&DDRE, &PINE, &PORTE, 6} // E6 24 }; //------------------------------------------------------------------------------ #elif defined(__AVR_AT90USB646__)\ @@ -228,52 +228,52 @@ 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 - {&DDRD, &PIND, &PORTD, 1}, // D1 1 - {&DDRD, &PIND, &PORTD, 2}, // D2 2 - {&DDRD, &PIND, &PORTD, 3}, // D3 3 - {&DDRD, &PIND, &PORTD, 4}, // D4 4 - {&DDRD, &PIND, &PORTD, 5}, // D5 5 - {&DDRD, &PIND, &PORTD, 6}, // D6 6 - {&DDRD, &PIND, &PORTD, 7}, // D7 7 - {&DDRE, &PINE, &PORTE, 0}, // E0 8 - {&DDRE, &PINE, &PORTE, 1}, // E1 9 - {&DDRC, &PINC, &PORTC, 0}, // C0 10 - {&DDRC, &PINC, &PORTC, 1}, // C1 11 - {&DDRC, &PINC, &PORTC, 2}, // C2 12 - {&DDRC, &PINC, &PORTC, 3}, // C3 13 - {&DDRC, &PINC, &PORTC, 4}, // C4 14 - {&DDRC, &PINC, &PORTC, 5}, // C5 15 - {&DDRC, &PINC, &PORTC, 6}, // C6 16 - {&DDRC, &PINC, &PORTC, 7}, // C7 17 - {&DDRE, &PINE, &PORTE, 6}, // E6 18 - {&DDRE, &PINE, &PORTE, 7}, // E7 19 - {&DDRB, &PINB, &PORTB, 0}, // B0 20 - {&DDRB, &PINB, &PORTB, 1}, // B1 21 - {&DDRB, &PINB, &PORTB, 2}, // B2 22 - {&DDRB, &PINB, &PORTB, 3}, // B3 23 - {&DDRB, &PINB, &PORTB, 4}, // B4 24 - {&DDRB, &PINB, &PORTB, 5}, // B5 25 - {&DDRB, &PINB, &PORTB, 6}, // B6 26 - {&DDRB, &PINB, &PORTB, 7}, // B7 27 - {&DDRA, &PINA, &PORTA, 0}, // A0 28 - {&DDRA, &PINA, &PORTA, 1}, // A1 29 - {&DDRA, &PINA, &PORTA, 2}, // A2 30 - {&DDRA, &PINA, &PORTA, 3}, // A3 31 - {&DDRA, &PINA, &PORTA, 4}, // A4 32 - {&DDRA, &PINA, &PORTA, 5}, // A5 33 - {&DDRA, &PINA, &PORTA, 6}, // A6 34 - {&DDRA, &PINA, &PORTA, 7}, // A7 35 - {&DDRE, &PINE, &PORTE, 4}, // E4 36 - {&DDRE, &PINE, &PORTE, 5}, // E5 37 - {&DDRF, &PINF, &PORTF, 0}, // F0 38 - {&DDRF, &PINF, &PORTF, 1}, // F1 39 - {&DDRF, &PINF, &PORTF, 2}, // F2 40 - {&DDRF, &PINF, &PORTF, 3}, // F3 41 - {&DDRF, &PINF, &PORTF, 4}, // F4 42 - {&DDRF, &PINF, &PORTF, 5}, // F5 43 - {&DDRF, &PINF, &PORTF, 6}, // F6 44 - {&DDRF, &PINF, &PORTF, 7} // F7 45 + {&DDRD, &PIND, &PORTD, 0}, // D0 0 + {&DDRD, &PIND, &PORTD, 1}, // D1 1 + {&DDRD, &PIND, &PORTD, 2}, // D2 2 + {&DDRD, &PIND, &PORTD, 3}, // D3 3 + {&DDRD, &PIND, &PORTD, 4}, // D4 4 + {&DDRD, &PIND, &PORTD, 5}, // D5 5 + {&DDRD, &PIND, &PORTD, 6}, // D6 6 + {&DDRD, &PIND, &PORTD, 7}, // D7 7 + {&DDRE, &PINE, &PORTE, 0}, // E0 8 + {&DDRE, &PINE, &PORTE, 1}, // E1 9 + {&DDRC, &PINC, &PORTC, 0}, // C0 10 + {&DDRC, &PINC, &PORTC, 1}, // C1 11 + {&DDRC, &PINC, &PORTC, 2}, // C2 12 + {&DDRC, &PINC, &PORTC, 3}, // C3 13 + {&DDRC, &PINC, &PORTC, 4}, // C4 14 + {&DDRC, &PINC, &PORTC, 5}, // C5 15 + {&DDRC, &PINC, &PORTC, 6}, // C6 16 + {&DDRC, &PINC, &PORTC, 7}, // C7 17 + {&DDRE, &PINE, &PORTE, 6}, // E6 18 + {&DDRE, &PINE, &PORTE, 7}, // E7 19 + {&DDRB, &PINB, &PORTB, 0}, // B0 20 + {&DDRB, &PINB, &PORTB, 1}, // B1 21 + {&DDRB, &PINB, &PORTB, 2}, // B2 22 + {&DDRB, &PINB, &PORTB, 3}, // B3 23 + {&DDRB, &PINB, &PORTB, 4}, // B4 24 + {&DDRB, &PINB, &PORTB, 5}, // B5 25 + {&DDRB, &PINB, &PORTB, 6}, // B6 26 + {&DDRB, &PINB, &PORTB, 7}, // B7 27 + {&DDRA, &PINA, &PORTA, 0}, // A0 28 + {&DDRA, &PINA, &PORTA, 1}, // A1 29 + {&DDRA, &PINA, &PORTA, 2}, // A2 30 + {&DDRA, &PINA, &PORTA, 3}, // A3 31 + {&DDRA, &PINA, &PORTA, 4}, // A4 32 + {&DDRA, &PINA, &PORTA, 5}, // A5 33 + {&DDRA, &PINA, &PORTA, 6}, // A6 34 + {&DDRA, &PINA, &PORTA, 7}, // A7 35 + {&DDRE, &PINE, &PORTE, 4}, // E4 36 + {&DDRE, &PINE, &PORTE, 5}, // E5 37 + {&DDRF, &PINF, &PORTF, 0}, // F0 38 + {&DDRF, &PINF, &PORTF, 1}, // F1 39 + {&DDRF, &PINF, &PORTF, 2}, // F2 40 + {&DDRF, &PINF, &PORTF, 3}, // F3 41 + {&DDRF, &PINF, &PORTF, 4}, // F4 42 + {&DDRF, &PINF, &PORTF, 5}, // F5 43 + {&DDRF, &PINF, &PORTF, 6}, // F6 44 + {&DDRF, &PINF, &PORTF, 7} // F7 45 }; //------------------------------------------------------------------------------ #elif defined(__AVR_ATmega168__)\ @@ -292,26 +292,26 @@ uint8_t const MISO_PIN = 12; // B4 uint8_t const SCK_PIN = 13; // B5 static const pin_map_t digitalPinMap[] = { - {&DDRD, &PIND, &PORTD, 0}, // D0 0 - {&DDRD, &PIND, &PORTD, 1}, // D1 1 - {&DDRD, &PIND, &PORTD, 2}, // D2 2 - {&DDRD, &PIND, &PORTD, 3}, // D3 3 - {&DDRD, &PIND, &PORTD, 4}, // D4 4 - {&DDRD, &PIND, &PORTD, 5}, // D5 5 - {&DDRD, &PIND, &PORTD, 6}, // D6 6 - {&DDRD, &PIND, &PORTD, 7}, // D7 7 - {&DDRB, &PINB, &PORTB, 0}, // B0 8 - {&DDRB, &PINB, &PORTB, 1}, // B1 9 - {&DDRB, &PINB, &PORTB, 2}, // B2 10 - {&DDRB, &PINB, &PORTB, 3}, // B3 11 - {&DDRB, &PINB, &PORTB, 4}, // B4 12 - {&DDRB, &PINB, &PORTB, 5}, // B5 13 - {&DDRC, &PINC, &PORTC, 0}, // C0 14 - {&DDRC, &PINC, &PORTC, 1}, // C1 15 - {&DDRC, &PINC, &PORTC, 2}, // C2 16 - {&DDRC, &PINC, &PORTC, 3}, // C3 17 - {&DDRC, &PINC, &PORTC, 4}, // C4 18 - {&DDRC, &PINC, &PORTC, 5} // C5 19 + {&DDRD, &PIND, &PORTD, 0}, // D0 0 + {&DDRD, &PIND, &PORTD, 1}, // D1 1 + {&DDRD, &PIND, &PORTD, 2}, // D2 2 + {&DDRD, &PIND, &PORTD, 3}, // D3 3 + {&DDRD, &PIND, &PORTD, 4}, // D4 4 + {&DDRD, &PIND, &PORTD, 5}, // D5 5 + {&DDRD, &PIND, &PORTD, 6}, // D6 6 + {&DDRD, &PIND, &PORTD, 7}, // D7 7 + {&DDRB, &PINB, &PORTB, 0}, // B0 8 + {&DDRB, &PINB, &PORTB, 1}, // B1 9 + {&DDRB, &PINB, &PORTB, 2}, // B2 10 + {&DDRB, &PINB, &PORTB, 3}, // B3 11 + {&DDRB, &PINB, &PORTB, 4}, // B4 12 + {&DDRB, &PINB, &PORTB, 5}, // B5 13 + {&DDRC, &PINC, &PORTC, 0}, // C0 14 + {&DDRC, &PINC, &PORTC, 1}, // C1 15 + {&DDRC, &PINC, &PORTC, 2}, // C2 16 + {&DDRC, &PINC, &PORTC, 3}, // C3 17 + {&DDRC, &PINC, &PORTC, 4}, // C4 18 + {&DDRC, &PINC, &PORTC, 5} // C5 19 }; #else // defined(__AVR_ATmega1280__) #error unknown chip @@ -320,47 +320,47 @@ static const pin_map_t digitalPinMap[] = { static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t); uint8_t badPinNumber(void) - __attribute__((error("Pin number is too large or not a constant"))); +__attribute__((error("Pin number is too large or not a constant"))); static inline __attribute__((always_inline)) - bool getPinMode(uint8_t pin) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; - } else { - return badPinNumber(); - } +bool getPinMode(uint8_t pin) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; + } else { + return badPinNumber(); + } } static inline __attribute__((always_inline)) - void setPinMode(uint8_t pin, uint8_t mode) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - if (mode) { - *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit; +void setPinMode(uint8_t pin, uint8_t mode) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + if (mode) { + *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit; + } else { + *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit); + } } else { - *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit); + badPinNumber(); } - } else { - badPinNumber(); - } } static inline __attribute__((always_inline)) - bool fastDigitalRead(uint8_t pin) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; - } else { - return badPinNumber(); - } +bool fastDigitalRead(uint8_t pin) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; + } else { + return badPinNumber(); + } } static inline __attribute__((always_inline)) - void fastDigitalWrite(uint8_t pin, uint8_t value) { - if (__builtin_constant_p(pin) && pin < digitalPinCount) { - if (value) { - *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit; +void fastDigitalWrite(uint8_t pin, uint8_t value) { + if (__builtin_constant_p(pin) && pin < digitalPinCount) { + if (value) { + *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit; + } else { + *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit); + } } else { - *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit); + badPinNumber(); } - } else { - badPinNumber(); - } } #endif // Sd2PinMap_h diff --git a/Firmware/SdBaseFile.cpp b/Firmware/SdBaseFile.cpp index be04ab1a22..9f31b820fd 100755 --- a/Firmware/SdBaseFile.cpp +++ b/Firmware/SdBaseFile.cpp @@ -30,57 +30,57 @@ void (*SdBaseFile::dateTime_)(uint16_t* date, uint16_t* time) = 0; //------------------------------------------------------------------------------ // add a cluster to a file bool SdBaseFile::addCluster() { - if (!vol_->allocContiguous(1, &curCluster_)) goto fail; + if (!vol_->allocContiguous(1, &curCluster_)) goto fail; - // if first cluster of file link to directory entry - if (firstCluster_ == 0) { - firstCluster_ = curCluster_; - flags_ |= F_FILE_DIR_DIRTY; - } - return true; + // if first cluster of file link to directory entry + if (firstCluster_ == 0) { + firstCluster_ = curCluster_; + flags_ |= F_FILE_DIR_DIRTY; + } + return true; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ // Add a cluster to a directory file and zero the cluster. // return with first block of cluster in the cache bool SdBaseFile::addDirCluster() { - uint32_t block; - // max folder size - if (fileSize_/sizeof(dir_t) >= 0XFFFF) goto fail; + uint32_t block; + // max folder size + if (fileSize_/sizeof(dir_t) >= 0XFFFF) goto fail; - if (!addCluster()) goto fail; - if (!vol_->cacheFlush()) goto fail; + if (!addCluster()) goto fail; + if (!vol_->cacheFlush()) goto fail; - block = vol_->clusterStartBlock(curCluster_); + block = vol_->clusterStartBlock(curCluster_); - // set cache to first block of cluster - vol_->cacheSetBlockNumber(block, true); + // set cache to first block of cluster + vol_->cacheSetBlockNumber(block, true); - // zero first block of cluster - memset(vol_->cacheBuffer_.data, 0, 512); + // zero first block of cluster + memset(vol_->cacheBuffer_.data, 0, 512); - // zero rest of cluster - for (uint8_t i = 1; i < vol_->blocksPerCluster_; i++) { - if (!vol_->writeBlock(block + i, vol_->cacheBuffer_.data)) goto fail; - } - // Increase directory file size by cluster size - fileSize_ += 512UL << vol_->clusterSizeShift_; - return true; + // zero rest of cluster + for (uint8_t i = 1; i < vol_->blocksPerCluster_; i++) { + if (!vol_->writeBlock(block + i, vol_->cacheBuffer_.data)) goto fail; + } + // Increase directory file size by cluster size + fileSize_ += 512UL << vol_->clusterSizeShift_; + return true; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ // cache a file's directory entry // return pointer to cached entry or null for failure dir_t* SdBaseFile::cacheDirEntry(uint8_t action) { - if (!vol_->cacheRawBlock(dirBlock_, action)) goto fail; - return vol_->cache()->dir + dirIndex_; + if (!vol_->cacheRawBlock(dirBlock_, action)) goto fail; + return vol_->cache()->dir + dirIndex_; - fail: - return 0; +fail: + return 0; } //------------------------------------------------------------------------------ /** Close a file and force cached data and directory information @@ -91,9 +91,9 @@ dir_t* SdBaseFile::cacheDirEntry(uint8_t action) { * Reasons for failure include no file is open or an I/O error. */ bool SdBaseFile::close() { - bool rtn = sync(); - type_ = FAT_FILE_TYPE_CLOSED; - return rtn; + bool rtn = sync(); + type_ = FAT_FILE_TYPE_CLOSED; + return rtn; } //------------------------------------------------------------------------------ /** Check for contiguous file and return its raw block range. @@ -107,26 +107,26 @@ bool SdBaseFile::close() { * or an I/O error occurred. */ bool SdBaseFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { - // error if no blocks - if (firstCluster_ == 0) goto fail; - - for (uint32_t c = firstCluster_; ; c++) { - uint32_t next; - if (!vol_->fatGet(c, &next)) goto fail; - - // check for contiguous - if (next != (c + 1)) { - // error if not end of chain - if (!vol_->isEOC(next)) goto fail; - *bgnBlock = vol_->clusterStartBlock(firstCluster_); - *endBlock = vol_->clusterStartBlock(c) - + vol_->blocksPerCluster_ - 1; - return true; + // error if no blocks + if (firstCluster_ == 0) goto fail; + + for (uint32_t c = firstCluster_; ; c++) { + uint32_t next; + if (!vol_->fatGet(c, &next)) goto fail; + + // check for contiguous + if (next != (c + 1)) { + // error if not end of chain + if (!vol_->isEOC(next)) goto fail; + *bgnBlock = vol_->clusterStartBlock(firstCluster_); + *endBlock = vol_->clusterStartBlock(c) + + vol_->blocksPerCluster_ - 1; + return true; + } } - } - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Create and open a new contiguous file of a specified size. @@ -147,29 +147,29 @@ bool SdBaseFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { * */ bool SdBaseFile::createContiguous(SdBaseFile* dirFile, - const char* path, uint32_t size) { - uint32_t count; - // don't allow zero length file - if (size == 0) goto fail; - if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) goto fail; - - // calculate number of clusters needed - count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; - - // allocate clusters - if (!vol_->allocContiguous(count, &firstCluster_)) { - remove(); - goto fail; - } - fileSize_ = size; + const char* path, uint32_t size) { + uint32_t count; + // don't allow zero length file + if (size == 0) goto fail; + if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) goto fail; + + // calculate number of clusters needed + count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; + + // allocate clusters + if (!vol_->allocContiguous(count, &firstCluster_)) { + remove(); + goto fail; + } + fileSize_ = size; - // insure sync() will update dir entry - flags_ |= F_FILE_DIR_DIRTY; + // insure sync() will update dir entry + flags_ |= F_FILE_DIR_DIRTY; - return sync(); + return sync(); - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Return a file's directory entry. @@ -180,20 +180,20 @@ bool SdBaseFile::createContiguous(SdBaseFile* dirFile, * the value zero, false, is returned for failure. */ bool SdBaseFile::dirEntry(dir_t* dir) { - dir_t* p; - // make sure fields on SD are correct - if (!sync()) goto fail; + dir_t* p; + // make sure fields on SD are correct + if (!sync()) goto fail; - // read entry - p = cacheDirEntry(SdVolume::CACHE_FOR_READ); - if (!p) goto fail; + // read entry + p = cacheDirEntry(SdVolume::CACHE_FOR_READ); + if (!p) goto fail; - // copy to caller's struct - memcpy(dir, p, sizeof(dir_t)); - return true; + // copy to caller's struct + memcpy(dir, p, sizeof(dir_t)); + return true; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Format the name field of \a dir into the 13 byte array @@ -203,13 +203,13 @@ bool SdBaseFile::dirEntry(dir_t* dir) { * \param[out] name A 13 byte char array for the formatted name. */ void SdBaseFile::dirName(const dir_t& dir, char* name) { - uint8_t j = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ')continue; - if (i == 8) name[j++] = '.'; - name[j++] = dir.name[i]; - } - name[j] = 0; + uint8_t j = 0; + for (uint8_t i = 0; i < 11; i++) { + if (dir.name[i] == ' ')continue; + if (i == 8) name[j++] = '.'; + name[j++] = dir.name[i]; + } + name[j] = 0; } //------------------------------------------------------------------------------ /** Test for the existence of a file in a directory @@ -224,8 +224,8 @@ void SdBaseFile::dirName(const dir_t& dir, char* name) { * \return true if the file exists else false. */ bool SdBaseFile::exists(const char* name) { - SdBaseFile file; - return file.open(this, name, O_READ); + SdBaseFile file; + return file.open(this, name, O_READ); } //------------------------------------------------------------------------------ /** @@ -249,25 +249,25 @@ bool SdBaseFile::exists(const char* name) { * If no data is read, fgets() returns zero for EOF or -1 if an error occurred. **/ int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) { - char ch; - int16_t n = 0; - int16_t r = -1; - while ((n + 1) < num && (r = read(&ch, 1)) == 1) { - // delete CR - if (ch == '\r') continue; - str[n++] = ch; - if (!delim) { - if (ch == '\n') break; - } else { - if (strchr(delim, ch)) break; + char ch; + int16_t n = 0; + int16_t r = -1; + while ((n + 1) < num && (r = read(&ch, 1)) == 1) { + // delete CR + if (ch == '\r') continue; + str[n++] = ch; + if (!delim) { + if (ch == '\n') break; + } else { + if (strchr(delim, ch)) break; + } } - } - if (r < 0) { - // read error - return -1; - } - str[n] = '\0'; - return n; + if (r < 0) { + // read error + return -1; + } + str[n] = '\0'; + return n; } //------------------------------------------------------------------------------ /** Get a file's name @@ -278,25 +278,25 @@ int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) { * the value zero, false, is returned for failure. */ bool SdBaseFile::getFilename(char* name) { - if (!isOpen()) return false; + if (!isOpen()) return false; + + if (isRoot()) { + name[0] = '/'; + name[1] = '\0'; + return true; + } + // cache entry + dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); + if (!p) return false; - if (isRoot()) { - name[0] = '/'; - name[1] = '\0'; + // format name + dirName(*p, name); return true; - } - // cache entry - dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); - if (!p) return false; - - // format name - dirName(*p, name); - return true; } //------------------------------------------------------------------------------ void SdBaseFile::getpos(filepos_t* pos) { - pos->position = curPosition_; - pos->cluster = curCluster_; + pos->position = curPosition_; + pos->cluster = curCluster_; } //------------------------------------------------------------------------------ @@ -316,99 +316,99 @@ void SdBaseFile::getpos(filepos_t* pos) { * list to indicate subdirectory level. */ void SdBaseFile::ls(uint8_t flags, uint8_t indent) { - rewind(); - int8_t status; - while ((status = lsPrintNext( flags, indent))) { - if (status > 1 && (flags & LS_R)) { - uint16_t index = curPosition()/32 - 1; - SdBaseFile s; - if (s.open(this, index, O_READ)) s.ls( flags, indent + 2); - seekSet(32 * (index + 1)); + rewind(); + int8_t status; + while ((status = lsPrintNext( flags, indent))) { + if (status > 1 && (flags & LS_R)) { + uint16_t index = curPosition()/32 - 1; + SdBaseFile s; + if (s.open(this, index, O_READ)) s.ls( flags, indent + 2); + seekSet(32 * (index + 1)); + } } - } } //------------------------------------------------------------------------------ // saves 32 bytes on stack for ls recursion // return 0 - EOF, 1 - normal file, or 2 - directory int8_t SdBaseFile::lsPrintNext( uint8_t flags, uint8_t indent) { - dir_t dir; - uint8_t w = 0; - - while (1) { - if (read(&dir, sizeof(dir)) != sizeof(dir)) return 0; - if (dir.name[0] == DIR_NAME_FREE) return 0; - - // skip deleted entry and entries for . and .. - if (dir.name[0] != DIR_NAME_DELETED && dir.name[0] != '.' - && DIR_IS_FILE_OR_SUBDIR(&dir)) break; - } - // indent for dir level - for (uint8_t i = 0; i < indent; i++) MYSERIAL.write(' '); - - // print name - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ')continue; - if (i == 8) { - MYSERIAL.write('.'); - w++; + dir_t dir; + uint8_t w = 0; + + while (1) { + if (read(&dir, sizeof(dir)) != sizeof(dir)) return 0; + if (dir.name[0] == DIR_NAME_FREE) return 0; + + // skip deleted entry and entries for . and .. + if (dir.name[0] != DIR_NAME_DELETED && dir.name[0] != '.' + && DIR_IS_FILE_OR_SUBDIR(&dir)) break; + } + // indent for dir level + for (uint8_t i = 0; i < indent; i++) MYSERIAL.write(' '); + + // print name + for (uint8_t i = 0; i < 11; i++) { + if (dir.name[i] == ' ')continue; + if (i == 8) { + MYSERIAL.write('.'); + w++; + } + MYSERIAL.write(dir.name[i]); + w++; + } + if (DIR_IS_SUBDIR(&dir)) { + MYSERIAL.write('/'); + w++; + } + if (flags & (LS_DATE | LS_SIZE)) { + while (w++ < 14) MYSERIAL.write(' '); } - MYSERIAL.write(dir.name[i]); - w++; - } - if (DIR_IS_SUBDIR(&dir)) { - MYSERIAL.write('/'); - w++; - } - if (flags & (LS_DATE | LS_SIZE)) { - while (w++ < 14) MYSERIAL.write(' '); - } - // print modify date/time if requested - if (flags & LS_DATE) { - MYSERIAL.write(' '); - printFatDate( dir.lastWriteDate); - MYSERIAL.write(' '); - printFatTime( dir.lastWriteTime); - } - // print size if requested - if (!DIR_IS_SUBDIR(&dir) && (flags & LS_SIZE)) { - MYSERIAL.write(' '); - MYSERIAL.print(dir.fileSize); - } - MYSERIAL.println(); - return DIR_IS_FILE(&dir) ? 1 : 2; + // print modify date/time if requested + if (flags & LS_DATE) { + MYSERIAL.write(' '); + printFatDate( dir.lastWriteDate); + MYSERIAL.write(' '); + printFatTime( dir.lastWriteTime); + } + // print size if requested + if (!DIR_IS_SUBDIR(&dir) && (flags & LS_SIZE)) { + MYSERIAL.write(' '); + MYSERIAL.print(dir.fileSize); + } + MYSERIAL.println(); + return DIR_IS_FILE(&dir) ? 1 : 2; } //------------------------------------------------------------------------------ // format directory name field from a 8.3 name string bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) { - uint8_t c; - uint8_t n = 7; // max index for part before dot - uint8_t i = 0; - // blank fill name and extension - while (i < 11) name[i++] = ' '; - i = 0; - while (*str != '\0' && *str != '/') { - c = *str++; - if (c == '.') { - if (n == 10) goto fail; // only one dot allowed - n = 10; // max index for full 8.3 name - i = 8; // place for extension - } else { - // illegal FAT characters - PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); - uint8_t b; - while ((b = pgm_read_byte(p++))) if (b == c) goto fail; - // check size and only allow ASCII printable characters - if (i > n || c < 0X21 || c > 0X7E)goto fail; - // only upper case allowed in 8.3 names - convert lower to upper - name[i++] = (c < 'a' || c > 'z') ? (c) : (c + ('A' - 'a')); + uint8_t c; + uint8_t n = 7; // max index for part before dot + uint8_t i = 0; + // blank fill name and extension + while (i < 11) name[i++] = ' '; + i = 0; + while (*str != '\0' && *str != '/') { + c = *str++; + if (c == '.') { + if (n == 10) goto fail; // only one dot allowed + n = 10; // max index for full 8.3 name + i = 8; // place for extension + } else { + // illegal FAT characters + PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); + uint8_t b; + while ((b = pgm_read_byte(p++))) if (b == c) goto fail; + // check size and only allow ASCII printable characters + if (i > n || c < 0X21 || c > 0X7E)goto fail; + // only upper case allowed in 8.3 names - convert lower to upper + name[i++] = (c < 'a' || c > 'z') ? (c) : (c + ('A' - 'a')); + } } - } - *ptr = str; - // must have a file name, extension is optional - return name[0] != ' '; + *ptr = str; + // must have a file name, extension is optional + return name[0] != ' '; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Make a new directory. @@ -426,110 +426,110 @@ bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) { * directory, \a path is invalid or already exists in \a parent. */ bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) { - uint8_t dname[11]; - SdBaseFile dir1, dir2; - SdBaseFile* sub = &dir1; - SdBaseFile* start = parent; - - if (!parent || isOpen()) goto fail; - - if (*path == '/') { - while (*path == '/') path++; - if (!parent->isRoot()) { - if (!dir2.openRoot(parent->vol_)) goto fail; - parent = &dir2; + uint8_t dname[11]; + SdBaseFile dir1, dir2; + SdBaseFile* sub = &dir1; + SdBaseFile* start = parent; + + if (!parent || isOpen()) goto fail; + + if (*path == '/') { + while (*path == '/') path++; + if (!parent->isRoot()) { + if (!dir2.openRoot(parent->vol_)) goto fail; + parent = &dir2; + } } - } - while (1) { - if (!make83Name(path, dname, &path)) goto fail; - while (*path == '/') path++; - if (!*path) break; - if (!sub->open(parent, dname, O_READ)) { - if (!pFlag || !sub->mkdir(parent, dname)) { - goto fail; - } + while (1) { + if (!make83Name(path, dname, &path)) goto fail; + while (*path == '/') path++; + if (!*path) break; + if (!sub->open(parent, dname, O_READ)) { + if (!pFlag || !sub->mkdir(parent, dname)) { + goto fail; + } + } + if (parent != start) parent->close(); + parent = sub; + sub = parent != &dir1 ? &dir1 : &dir2; } - if (parent != start) parent->close(); - parent = sub; - sub = parent != &dir1 ? &dir1 : &dir2; - } - return mkdir(parent, dname); - - fail: - return false; + return mkdir(parent, dname); + +fail: + return false; } //------------------------------------------------------------------------------ bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) { - uint32_t block; - dir_t d; - dir_t* p; + uint32_t block; + dir_t d; + dir_t* p; - if (!parent->isDir()) goto fail; + if (!parent->isDir()) goto fail; - // create a normal file - if (!open(parent, dname, O_CREAT | O_EXCL | O_RDWR)) goto fail; + // create a normal file + if (!open(parent, dname, O_CREAT | O_EXCL | O_RDWR)) goto fail; - // convert file to directory - flags_ = O_READ; - type_ = FAT_FILE_TYPE_SUBDIR; + // convert file to directory + flags_ = O_READ; + type_ = FAT_FILE_TYPE_SUBDIR; - // allocate and zero first cluster - if (!addDirCluster())goto fail; + // allocate and zero first cluster + if (!addDirCluster())goto fail; - // force entry to SD - if (!sync()) goto fail; + // force entry to SD + if (!sync()) goto fail; - // cache entry - should already be in cache due to sync() call - p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) goto fail; + // cache entry - should already be in cache due to sync() call + p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!p) goto fail; - // change directory entry attribute - p->attributes = DIR_ATT_DIRECTORY; + // change directory entry attribute + p->attributes = DIR_ATT_DIRECTORY; - // make entry for '.' - memcpy(&d, p, sizeof(d)); - d.name[0] = '.'; - for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; + // make entry for '.' + memcpy(&d, p, sizeof(d)); + d.name[0] = '.'; + for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; - // cache block for '.' and '..' - block = vol_->clusterStartBlock(firstCluster_); - if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; + // cache block for '.' and '..' + block = vol_->clusterStartBlock(firstCluster_); + if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; - // copy '.' to block - memcpy(&vol_->cache()->dir[0], &d, sizeof(d)); + // copy '.' to block + memcpy(&vol_->cache()->dir[0], &d, sizeof(d)); - // make entry for '..' - d.name[1] = '.'; - if (parent->isRoot()) { - d.firstClusterLow = 0; - d.firstClusterHigh = 0; - } else { - d.firstClusterLow = parent->firstCluster_ & 0XFFFF; - d.firstClusterHigh = parent->firstCluster_ >> 16; - } - // copy '..' to block - memcpy(&vol_->cache()->dir[1], &d, sizeof(d)); + // make entry for '..' + d.name[1] = '.'; + if (parent->isRoot()) { + d.firstClusterLow = 0; + d.firstClusterHigh = 0; + } else { + d.firstClusterLow = parent->firstCluster_ & 0XFFFF; + d.firstClusterHigh = parent->firstCluster_ >> 16; + } + // copy '..' to block + memcpy(&vol_->cache()->dir[1], &d, sizeof(d)); - // write first block - return vol_->cacheFlush(); + // write first block + return vol_->cacheFlush(); - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ - /** Open a file in the current working directory. - * - * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. - * - * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive - * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. - */ - bool SdBaseFile::open(const char* path, uint8_t oflag) { +/** Open a file in the current working directory. + * + * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. + * + * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive + * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. + */ +bool SdBaseFile::open(const char* path, uint8_t oflag) { return open(cwd_, path, oflag); - } +} //------------------------------------------------------------------------------ /** Open a file or directory by name. * @@ -582,115 +582,115 @@ bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) { * or can't be opened in the access mode specified by oflag. */ bool SdBaseFile::open(SdBaseFile* dirFile, const char* path, uint8_t oflag) { - uint8_t dname[11]; - SdBaseFile dir1, dir2; - SdBaseFile *parent = dirFile; - SdBaseFile *sub = &dir1; + uint8_t dname[11]; + SdBaseFile dir1, dir2; + SdBaseFile *parent = dirFile; + SdBaseFile *sub = &dir1; - if (!dirFile) goto fail; + if (!dirFile) goto fail; - // error if already open - if (isOpen()) goto fail; + // error if already open + if (isOpen()) goto fail; - if (*path == '/') { - while (*path == '/') path++; - if (!dirFile->isRoot()) { - if (!dir2.openRoot(dirFile->vol_)) goto fail; - parent = &dir2; + if (*path == '/') { + while (*path == '/') path++; + if (!dirFile->isRoot()) { + if (!dir2.openRoot(dirFile->vol_)) goto fail; + parent = &dir2; + } } - } - while (1) { - if (!make83Name(path, dname, &path)) goto fail; - while (*path == '/') path++; - if (!*path) break; - if (!sub->open(parent, dname, O_READ)) goto fail; - if (parent != dirFile) parent->close(); - parent = sub; - sub = parent != &dir1 ? &dir1 : &dir2; - } - return open(parent, dname, oflag); - - fail: - return false; + while (1) { + if (!make83Name(path, dname, &path)) goto fail; + while (*path == '/') path++; + if (!*path) break; + if (!sub->open(parent, dname, O_READ)) goto fail; + if (parent != dirFile) parent->close(); + parent = sub; + sub = parent != &dir1 ? &dir1 : &dir2; + } + return open(parent, dname, oflag); + +fail: + return false; } //------------------------------------------------------------------------------ // open with filename in dname bool SdBaseFile::open(SdBaseFile* dirFile, - const uint8_t dname[11], uint8_t oflag) { - bool emptyFound = false; - bool fileFound = false; - uint8_t index; - dir_t* p; - - vol_ = dirFile->vol_; - - dirFile->rewind(); - // search for file - - while (dirFile->curPosition_ < dirFile->fileSize_) { - index = 0XF & (dirFile->curPosition_ >> 5); - p = dirFile->readDirCache(); - if (!p) goto fail; - - if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { - // remember first empty slot - if (!emptyFound) { - dirBlock_ = dirFile->vol_->cacheBlockNumber(); - dirIndex_ = index; - emptyFound = true; - } - // done if no entries follow - if (p->name[0] == DIR_NAME_FREE) break; - } else if (!memcmp(dname, p->name, 11)) { - fileFound = true; - break; + const uint8_t dname[11], uint8_t oflag) { + bool emptyFound = false; + bool fileFound = false; + uint8_t index; + dir_t* p; + + vol_ = dirFile->vol_; + + dirFile->rewind(); + // search for file + + while (dirFile->curPosition_ < dirFile->fileSize_) { + index = 0XF & (dirFile->curPosition_ >> 5); + p = dirFile->readDirCache(); + if (!p) goto fail; + + if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { + // remember first empty slot + if (!emptyFound) { + dirBlock_ = dirFile->vol_->cacheBlockNumber(); + dirIndex_ = index; + emptyFound = true; + } + // done if no entries follow + if (p->name[0] == DIR_NAME_FREE) break; + } else if (!memcmp(dname, p->name, 11)) { + fileFound = true; + break; + } } - } - if (fileFound) { - // don't open existing file if O_EXCL - if (oflag & O_EXCL) goto fail; - } else { - // don't create unless O_CREAT and O_WRITE - if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) goto fail; - if (emptyFound) { - index = dirIndex_; - p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) goto fail; + if (fileFound) { + // don't open existing file if O_EXCL + if (oflag & O_EXCL) goto fail; } else { - if (dirFile->type_ == FAT_FILE_TYPE_ROOT_FIXED) goto fail; + // don't create unless O_CREAT and O_WRITE + if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) goto fail; + if (emptyFound) { + index = dirIndex_; + p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!p) goto fail; + } else { + if (dirFile->type_ == FAT_FILE_TYPE_ROOT_FIXED) goto fail; - // add and zero cluster for dirFile - first cluster is in cache for write - if (!dirFile->addDirCluster()) goto fail; + // add and zero cluster for dirFile - first cluster is in cache for write + if (!dirFile->addDirCluster()) goto fail; - // use first entry in cluster - p = dirFile->vol_->cache()->dir; - index = 0; - } - // initialize as empty file - memset(p, 0, sizeof(dir_t)); - memcpy(p->name, dname, 11); - - // set timestamps - if (dateTime_) { - // call user date/time function - dateTime_(&p->creationDate, &p->creationTime); - } else { - // use default date/time - p->creationDate = FAT_DEFAULT_DATE; - p->creationTime = FAT_DEFAULT_TIME; - } - p->lastAccessDate = p->creationDate; - p->lastWriteDate = p->creationDate; - p->lastWriteTime = p->creationTime; + // use first entry in cluster + p = dirFile->vol_->cache()->dir; + index = 0; + } + // initialize as empty file + memset(p, 0, sizeof(dir_t)); + memcpy(p->name, dname, 11); + + // set timestamps + if (dateTime_) { + // call user date/time function + dateTime_(&p->creationDate, &p->creationTime); + } else { + // use default date/time + p->creationDate = FAT_DEFAULT_DATE; + p->creationTime = FAT_DEFAULT_TIME; + } + p->lastAccessDate = p->creationDate; + p->lastWriteDate = p->creationDate; + p->lastWriteTime = p->creationTime; - // write entry to SD - if (!dirFile->vol_->cacheFlush()) goto fail; - } - // open entry in cache - return openCachedEntry(index, oflag); + // write entry to SD + if (!dirFile->vol_->cacheFlush()) goto fail; + } + // open entry in cache + return openCachedEntry(index, oflag); - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Open a file by index. @@ -707,74 +707,74 @@ bool SdBaseFile::open(SdBaseFile* dirFile, * \return true for success or false for failure. */ bool SdBaseFile::open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag) { - dir_t* p; + dir_t* p; - vol_ = dirFile->vol_; + vol_ = dirFile->vol_; - // error if already open - if (isOpen() || !dirFile) goto fail; + // error if already open + if (isOpen() || !dirFile) goto fail; - // don't open existing file if O_EXCL - user call error - if (oflag & O_EXCL) goto fail; + // don't open existing file if O_EXCL - user call error + if (oflag & O_EXCL) goto fail; - // seek to location of entry - if (!dirFile->seekSet(32 * index)) goto fail; + // seek to location of entry + if (!dirFile->seekSet(32 * index)) goto fail; - // read entry into cache - p = dirFile->readDirCache(); - if (!p) goto fail; + // read entry into cache + p = dirFile->readDirCache(); + if (!p) goto fail; - // error if empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_FREE || - p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { - goto fail; - } - // open cached entry - return openCachedEntry(index & 0XF, oflag); + // error if empty slot or '.' or '..' + if (p->name[0] == DIR_NAME_FREE || + p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { + goto fail; + } + // open cached entry + return openCachedEntry(index & 0XF, oflag); - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ // open a cached directory entry. Assumes vol_ is initialized bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { - // location of entry in cache - dir_t* p = &vol_->cache()->dir[dirIndex]; - - // write or truncate is an error for a directory or read-only file - if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { - if (oflag & (O_WRITE | O_TRUNC)) goto fail; - } - // remember location of directory entry on SD - dirBlock_ = vol_->cacheBlockNumber(); - dirIndex_ = dirIndex; - - // copy first cluster number for directory fields - firstCluster_ = (uint32_t)p->firstClusterHigh << 16; - firstCluster_ |= p->firstClusterLow; - - // make sure it is a normal file or subdirectory - if (DIR_IS_FILE(p)) { - fileSize_ = p->fileSize; - type_ = FAT_FILE_TYPE_NORMAL; - } else if (DIR_IS_SUBDIR(p)) { - if (!vol_->chainSize(firstCluster_, &fileSize_)) goto fail; - type_ = FAT_FILE_TYPE_SUBDIR; - } else { - goto fail; - } - // save open flags for read/write - flags_ = oflag & F_OFLAG; - - // set to start of file - curCluster_ = 0; - curPosition_ = 0; - if ((oflag & O_TRUNC) && !truncate(0)) return false; - return oflag & O_AT_END ? seekEnd(0) : true; - - fail: - type_ = FAT_FILE_TYPE_CLOSED; - return false; + // location of entry in cache + dir_t* p = &vol_->cache()->dir[dirIndex]; + + // write or truncate is an error for a directory or read-only file + if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { + if (oflag & (O_WRITE | O_TRUNC)) goto fail; + } + // remember location of directory entry on SD + dirBlock_ = vol_->cacheBlockNumber(); + dirIndex_ = dirIndex; + + // copy first cluster number for directory fields + firstCluster_ = (uint32_t)p->firstClusterHigh << 16; + firstCluster_ |= p->firstClusterLow; + + // make sure it is a normal file or subdirectory + if (DIR_IS_FILE(p)) { + fileSize_ = p->fileSize; + type_ = FAT_FILE_TYPE_NORMAL; + } else if (DIR_IS_SUBDIR(p)) { + if (!vol_->chainSize(firstCluster_, &fileSize_)) goto fail; + type_ = FAT_FILE_TYPE_SUBDIR; + } else { + goto fail; + } + // save open flags for read/write + flags_ = oflag & F_OFLAG; + + // set to start of file + curCluster_ = 0; + curPosition_ = 0; + if ((oflag & O_TRUNC) && !truncate(0)) return false; + return oflag & O_AT_END ? seekEnd(0) : true; + +fail: + type_ = FAT_FILE_TYPE_CLOSED; + return false; } //------------------------------------------------------------------------------ /** Open the next file or subdirectory in a directory. @@ -789,38 +789,38 @@ bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { * \return true for success or false for failure. */ bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) { - dir_t* p; - uint8_t index; + dir_t* p; + uint8_t index; - if (!dirFile) goto fail; + if (!dirFile) goto fail; - // error if already open - if (isOpen()) goto fail; + // error if already open + if (isOpen()) goto fail; - vol_ = dirFile->vol_; + vol_ = dirFile->vol_; - while (1) { - index = 0XF & (dirFile->curPosition_ >> 5); + while (1) { + index = 0XF & (dirFile->curPosition_ >> 5); - // read entry into cache - p = dirFile->readDirCache(); - if (!p) goto fail; + // read entry into cache + p = dirFile->readDirCache(); + if (!p) goto fail; - // done if last entry - if (p->name[0] == DIR_NAME_FREE) goto fail; + // done if last entry + if (p->name[0] == DIR_NAME_FREE) goto fail; - // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { - continue; - } - // must be file or dir - if (DIR_IS_FILE_OR_SUBDIR(p)) { - return openCachedEntry(index, oflag); + // skip empty slot or '.' or '..' + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { + continue; + } + // must be file or dir + if (DIR_IS_FILE_OR_SUBDIR(p)) { + return openCachedEntry(index, oflag); + } } - } - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Open a directory's parent directory. @@ -831,51 +831,51 @@ bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) { * the value zero, false, is returned for failure. */ bool SdBaseFile::openParent(SdBaseFile* dir) { - dir_t entry; - dir_t* p; - SdBaseFile file; - uint32_t c; - uint32_t cluster; - uint32_t lbn; - // error if already open or dir is root or dir is not a directory - if (isOpen() || !dir || dir->isRoot() || !dir->isDir()) goto fail; - vol_ = dir->vol_; - // position to '..' - if (!dir->seekSet(32)) goto fail; - // read '..' entry - if (dir->read(&entry, sizeof(entry)) != 32) goto fail; - // verify it is '..' - if (entry.name[0] != '.' || entry.name[1] != '.') goto fail; - // start cluster for '..' - cluster = entry.firstClusterLow; - cluster |= (uint32_t)entry.firstClusterHigh << 16; - if (cluster == 0) return openRoot(vol_); - // start block for '..' - lbn = vol_->clusterStartBlock(cluster); - // first block of parent dir - if (!vol_->cacheRawBlock(lbn, SdVolume::CACHE_FOR_READ)) { - goto fail; - } - p = &vol_->cacheBuffer_.dir[1]; - // verify name for '../..' - if (p->name[0] != '.' || p->name[1] != '.') goto fail; - // '..' is pointer to first cluster of parent. open '../..' to find parent - if (p->firstClusterHigh == 0 && p->firstClusterLow == 0) { - if (!file.openRoot(dir->volume())) goto fail; - } else { - if (!file.openCachedEntry(1, O_READ)) goto fail; - } - // search for parent in '../..' - do { - if (file.readDir(&entry, NULL) != 32) goto fail; - c = entry.firstClusterLow; - c |= (uint32_t)entry.firstClusterHigh << 16; - } while (c != cluster); - // open parent - return open(&file, file.curPosition()/32 - 1, O_READ); - - fail: - return false; + dir_t entry; + dir_t* p; + SdBaseFile file; + uint32_t c; + uint32_t cluster; + uint32_t lbn; + // error if already open or dir is root or dir is not a directory + if (isOpen() || !dir || dir->isRoot() || !dir->isDir()) goto fail; + vol_ = dir->vol_; + // position to '..' + if (!dir->seekSet(32)) goto fail; + // read '..' entry + if (dir->read(&entry, sizeof(entry)) != 32) goto fail; + // verify it is '..' + if (entry.name[0] != '.' || entry.name[1] != '.') goto fail; + // start cluster for '..' + cluster = entry.firstClusterLow; + cluster |= (uint32_t)entry.firstClusterHigh << 16; + if (cluster == 0) return openRoot(vol_); + // start block for '..' + lbn = vol_->clusterStartBlock(cluster); + // first block of parent dir + if (!vol_->cacheRawBlock(lbn, SdVolume::CACHE_FOR_READ)) { + goto fail; + } + p = &vol_->cacheBuffer_.dir[1]; + // verify name for '../..' + if (p->name[0] != '.' || p->name[1] != '.') goto fail; + // '..' is pointer to first cluster of parent. open '../..' to find parent + if (p->firstClusterHigh == 0 && p->firstClusterLow == 0) { + if (!file.openRoot(dir->volume())) goto fail; + } else { + if (!file.openCachedEntry(1, O_READ)) goto fail; + } + // search for parent in '../..' + do { + if (file.readDir(&entry, NULL) != 32) goto fail; + c = entry.firstClusterLow; + c |= (uint32_t)entry.firstClusterHigh << 16; + } while (c != cluster); + // open parent + return open(&file, file.curPosition()/32 - 1, O_READ); + +fail: + return false; } //------------------------------------------------------------------------------ /** Open a volume's root directory. @@ -888,36 +888,36 @@ bool SdBaseFile::openParent(SdBaseFile* dir) { * not been initialized or it a FAT12 volume. */ bool SdBaseFile::openRoot(SdVolume* vol) { - // error if file is already open - if (isOpen()) goto fail; - - if (vol->fatType() == 16 || (FAT12_SUPPORT && vol->fatType() == 12)) { - type_ = FAT_FILE_TYPE_ROOT_FIXED; - firstCluster_ = 0; - fileSize_ = 32 * vol->rootDirEntryCount(); - } else if (vol->fatType() == 32) { - type_ = FAT_FILE_TYPE_ROOT32; - firstCluster_ = vol->rootDirStart(); - if (!vol->chainSize(firstCluster_, &fileSize_)) goto fail; - } else { - // volume is not initialized, invalid, or FAT12 without support + // error if file is already open + if (isOpen()) goto fail; + + if (vol->fatType() == 16 || (FAT12_SUPPORT && vol->fatType() == 12)) { + type_ = FAT_FILE_TYPE_ROOT_FIXED; + firstCluster_ = 0; + fileSize_ = 32 * vol->rootDirEntryCount(); + } else if (vol->fatType() == 32) { + type_ = FAT_FILE_TYPE_ROOT32; + firstCluster_ = vol->rootDirStart(); + if (!vol->chainSize(firstCluster_, &fileSize_)) goto fail; + } else { + // volume is not initialized, invalid, or FAT12 without support + return false; + } + vol_ = vol; + // read only + flags_ = O_READ; + + // set to start of file + curCluster_ = 0; + curPosition_ = 0; + + // root has no directory entry + dirBlock_ = 0; + dirIndex_ = 0; + return true; + +fail: return false; - } - vol_ = vol; - // read only - flags_ = O_READ; - - // set to start of file - curCluster_ = 0; - curPosition_ = 0; - - // root has no directory entry - dirBlock_ = 0; - dirIndex_ = 0; - return true; - - fail: - return false; } //------------------------------------------------------------------------------ /** Return the next available byte without consuming it. @@ -925,11 +925,11 @@ bool SdBaseFile::openRoot(SdVolume* vol) { * \return The byte if no error and not at eof else -1; */ int SdBaseFile::peek() { - filepos_t pos; - getpos(&pos); - int c = read(); - if (c >= 0) setpos(&pos); - return c; + filepos_t pos; + getpos(&pos); + int c = read(); + if (c >= 0) setpos(&pos); + return c; } //------------------------------------------------------------------------------ @@ -940,31 +940,31 @@ int SdBaseFile::peek() { * \param[in] printSlash Print '/' after directory names if true. */ void SdBaseFile::printDirName(const dir_t& dir, - uint8_t width, bool printSlash) { - uint8_t w = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ')continue; - if (i == 8) { - MYSERIAL.write('.'); - w++; + uint8_t width, bool printSlash) { + uint8_t w = 0; + for (uint8_t i = 0; i < 11; i++) { + if (dir.name[i] == ' ')continue; + if (i == 8) { + MYSERIAL.write('.'); + w++; + } + MYSERIAL.write(dir.name[i]); + w++; + } + if (DIR_IS_SUBDIR(&dir) && printSlash) { + MYSERIAL.write('/'); + w++; + } + while (w < width) { + MYSERIAL.write(' '); + w++; } - MYSERIAL.write(dir.name[i]); - w++; - } - if (DIR_IS_SUBDIR(&dir) && printSlash) { - MYSERIAL.write('/'); - w++; - } - while (w < width) { - MYSERIAL.write(' '); - w++; - } } //------------------------------------------------------------------------------ // print uint8_t with width 2 static void print2u( uint8_t v) { - if (v < 10) MYSERIAL.write('0'); - MYSERIAL.print(v, DEC); + if (v < 10) MYSERIAL.write('0'); + MYSERIAL.print(v, DEC); } //------------------------------------------------------------------------------ /** %Print a directory date field to Serial. @@ -983,11 +983,11 @@ static void print2u( uint8_t v) { * \param[in] fatDate The date field from a directory entry. */ void SdBaseFile::printFatDate(uint16_t fatDate) { - MYSERIAL.print(FAT_YEAR(fatDate)); - MYSERIAL.write('-'); - print2u( FAT_MONTH(fatDate)); - MYSERIAL.write('-'); - print2u( FAT_DAY(fatDate)); + MYSERIAL.print(FAT_YEAR(fatDate)); + MYSERIAL.write('-'); + print2u( FAT_MONTH(fatDate)); + MYSERIAL.write('-'); + print2u( FAT_DAY(fatDate)); } //------------------------------------------------------------------------------ @@ -999,11 +999,11 @@ void SdBaseFile::printFatDate(uint16_t fatDate) { * \param[in] fatTime The time field from a directory entry. */ void SdBaseFile::printFatTime( uint16_t fatTime) { - print2u( FAT_HOUR(fatTime)); - MYSERIAL.write(':'); - print2u( FAT_MINUTE(fatTime)); - MYSERIAL.write(':'); - print2u( FAT_SECOND(fatTime)); + print2u( FAT_HOUR(fatTime)); + MYSERIAL.write(':'); + print2u( FAT_MINUTE(fatTime)); + MYSERIAL.write(':'); + print2u( FAT_SECOND(fatTime)); } //------------------------------------------------------------------------------ /** Print a file's name to Serial @@ -1012,10 +1012,10 @@ void SdBaseFile::printFatTime( uint16_t fatTime) { * the value zero, false, is returned for failure. */ bool SdBaseFile::printName() { - char name[13]; - if (!getFilename(name)) return false; - MYSERIAL.print(name); - return true; + char name[13]; + if (!getFilename(name)) return false; + MYSERIAL.print(name); + return true; } //------------------------------------------------------------------------------ /** Read the next byte from a file. @@ -1024,8 +1024,8 @@ bool SdBaseFile::printName() { * If an error occurs or end of file is reached -1 is returned. */ int16_t SdBaseFile::read() { - uint8_t b; - return read(&b, 1) == 1 ? b : -1; + uint8_t b; + return read(&b, 1) == 1 ? b : -1; } //------------------------------------------------------------------------------ /** Read data from a file starting at the current position. @@ -1042,60 +1042,60 @@ int16_t SdBaseFile::read() { * or an I/O error occurred. */ int16_t SdBaseFile::read(void* buf, uint16_t nbyte) { - uint8_t* dst = reinterpret_cast(buf); - uint16_t offset; - uint16_t toRead; - uint32_t block; // raw device block number - - // error if not open or write only - if (!isOpen() || !(flags_ & O_READ)) goto fail; - - // max bytes left in file - if (nbyte >= (fileSize_ - curPosition_)) { - nbyte = fileSize_ - curPosition_; - } - // amount left to read - toRead = nbyte; - while (toRead > 0) { - offset = curPosition_ & 0X1FF; // offset in block - if (type_ == FAT_FILE_TYPE_ROOT_FIXED) { - block = vol_->rootDirStart() + (curPosition_ >> 9); - } else { - uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); - if (offset == 0 && blockOfCluster == 0) { - // start of new cluster - if (curPosition_ == 0) { - // use first cluster in file - curCluster_ = firstCluster_; + uint8_t* dst = reinterpret_cast(buf); + uint16_t offset; + uint16_t toRead; + uint32_t block; // raw device block number + + // error if not open or write only + if (!isOpen() || !(flags_ & O_READ)) goto fail; + + // max bytes left in file + if (nbyte >= (fileSize_ - curPosition_)) { + nbyte = fileSize_ - curPosition_; + } + // amount left to read + toRead = nbyte; + while (toRead > 0) { + offset = curPosition_ & 0X1FF; // offset in block + if (type_ == FAT_FILE_TYPE_ROOT_FIXED) { + block = vol_->rootDirStart() + (curPosition_ >> 9); } else { - // get next cluster from FAT - if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail; + uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); + if (offset == 0 && blockOfCluster == 0) { + // start of new cluster + if (curPosition_ == 0) { + // use first cluster in file + curCluster_ = firstCluster_; + } else { + // get next cluster from FAT + if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail; + } + } + block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; } - } - block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; - } - uint16_t n = toRead; + uint16_t n = toRead; - // amount to be read from current block - if (n > (512 - offset)) n = 512 - offset; + // amount to be read from current block + if (n > (512 - offset)) n = 512 - offset; - // no buffering needed if n == 512 - if (n == 512 && block != vol_->cacheBlockNumber()) { - if (!vol_->readBlock(block, dst)) goto fail; - } else { - // read block to cache and copy data to caller - if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail; - uint8_t* src = vol_->cache()->data + offset; - memcpy(dst, src, n); + // no buffering needed if n == 512 + if (n == 512 && block != vol_->cacheBlockNumber()) { + if (!vol_->readBlock(block, dst)) goto fail; + } else { + // read block to cache and copy data to caller + if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail; + uint8_t* src = vol_->cache()->data + offset; + memcpy(dst, src, n); + } + dst += n; + curPosition_ += n; + toRead -= n; } - dst += n; - curPosition_ += n; - toRead -= n; - } - return nbyte; - - fail: - return -1; + return nbyte; + +fail: + return -1; } //------------------------------------------------------------------------------ /** Read the next directory entry from a directory file. @@ -1109,77 +1109,77 @@ int16_t SdBaseFile::read(void* buf, uint16_t nbyte) { * a directory file or an I/O error occurred. */ int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) { - int16_t n; - // if not a directory file or miss-positioned return an error - if (!isDir() || (0X1F & curPosition_)) return -1; - - //If we have a longFilename buffer, mark it as invalid. If we find a long filename it will be filled automaticly. - if (longFilename != NULL) - { - longFilename[0] = '\0'; - } - - while (1) { - n = read(dir, sizeof(dir_t)); - if (n != sizeof(dir_t)) return n == 0 ? 0 : -1; - // last entry if DIR_NAME_FREE - if (dir->name[0] == DIR_NAME_FREE) return 0; - // skip empty entries and entry for . and .. - if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; - //Fill the long filename if we have a long filename entry, - // long filename entries are stored before the actual filename. - if (DIR_IS_LONG_NAME(dir) && longFilename != NULL) + int16_t n; + // if not a directory file or miss-positioned return an error + if (!isDir() || (0X1F & curPosition_)) return -1; + + //If we have a longFilename buffer, mark it as invalid. If we find a long filename it will be filled automaticly. + if (longFilename != NULL) { - vfat_t *VFAT = (vfat_t*)dir; - //Sanity check the VFAT entry. The first cluster is always set to zero. And th esequence number should be higher then 0 - if (VFAT->firstClusterLow == 0 && (VFAT->sequenceNumber & 0x1F) > 0 && (VFAT->sequenceNumber & 0x1F) <= MAX_VFAT_ENTRIES) - { - //TODO: Store the filename checksum to verify if a none-long filename aware system modified the file table. - n = ((VFAT->sequenceNumber & 0x1F) - 1) * 13; - longFilename[n+0] = VFAT->name1[0]; - longFilename[n+1] = VFAT->name1[1]; - longFilename[n+2] = VFAT->name1[2]; - longFilename[n+3] = VFAT->name1[3]; - longFilename[n+4] = VFAT->name1[4]; - longFilename[n+5] = VFAT->name2[0]; - longFilename[n+6] = VFAT->name2[1]; - longFilename[n+7] = VFAT->name2[2]; - longFilename[n+8] = VFAT->name2[3]; - longFilename[n+9] = VFAT->name2[4]; - longFilename[n+10] = VFAT->name2[5]; - longFilename[n+11] = VFAT->name3[0]; - longFilename[n+12] = VFAT->name3[1]; - //If this VFAT entry is the last one, add a NUL terminator at the end of the string - if (VFAT->sequenceNumber & 0x40) - longFilename[n+13] = '\0'; - } + longFilename[0] = '\0'; + } + + while (1) { + n = read(dir, sizeof(dir_t)); + if (n != sizeof(dir_t)) return n == 0 ? 0 : -1; + // last entry if DIR_NAME_FREE + if (dir->name[0] == DIR_NAME_FREE) return 0; + // skip empty entries and entry for . and .. + if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; + //Fill the long filename if we have a long filename entry, + // long filename entries are stored before the actual filename. + if (DIR_IS_LONG_NAME(dir) && longFilename != NULL) + { + vfat_t *VFAT = (vfat_t*)dir; + //Sanity check the VFAT entry. The first cluster is always set to zero. And th esequence number should be higher then 0 + if (VFAT->firstClusterLow == 0 && (VFAT->sequenceNumber & 0x1F) > 0 && (VFAT->sequenceNumber & 0x1F) <= MAX_VFAT_ENTRIES) + { + //TODO: Store the filename checksum to verify if a none-long filename aware system modified the file table. + n = ((VFAT->sequenceNumber & 0x1F) - 1) * 13; + longFilename[n+0] = VFAT->name1[0]; + longFilename[n+1] = VFAT->name1[1]; + longFilename[n+2] = VFAT->name1[2]; + longFilename[n+3] = VFAT->name1[3]; + longFilename[n+4] = VFAT->name1[4]; + longFilename[n+5] = VFAT->name2[0]; + longFilename[n+6] = VFAT->name2[1]; + longFilename[n+7] = VFAT->name2[2]; + longFilename[n+8] = VFAT->name2[3]; + longFilename[n+9] = VFAT->name2[4]; + longFilename[n+10] = VFAT->name2[5]; + longFilename[n+11] = VFAT->name3[0]; + longFilename[n+12] = VFAT->name3[1]; + //If this VFAT entry is the last one, add a NUL terminator at the end of the string + if (VFAT->sequenceNumber & 0x40) + longFilename[n+13] = '\0'; + } + } + // return if normal file or subdirectory + if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; } - // return if normal file or subdirectory - if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; - } } //------------------------------------------------------------------------------ // Read next directory entry into the cache // Assumes file is correctly positioned dir_t* SdBaseFile::readDirCache() { - uint8_t i; - // error if not directory - if (!isDir()) goto fail; + uint8_t i; + // error if not directory + if (!isDir()) goto fail; - // index of entry in cache - i = (curPosition_ >> 5) & 0XF; + // index of entry in cache + i = (curPosition_ >> 5) & 0XF; - // use read to locate and cache block - if (read() < 0) goto fail; + // use read to locate and cache block + if (read() < 0) goto fail; - // advance to next entry - curPosition_ += 31; + // advance to next entry + curPosition_ += 31; - // return pointer to entry - return vol_->cache()->dir + i; + // return pointer to entry + return vol_->cache()->dir + i; - fail: - return 0; +fail: + return 0; } //------------------------------------------------------------------------------ /** Remove a file. @@ -1196,26 +1196,26 @@ dir_t* SdBaseFile::readDirCache() { * or an I/O error occurred. */ bool SdBaseFile::remove() { - dir_t* d; - // free any clusters - will fail if read-only or directory - if (!truncate(0)) goto fail; + dir_t* d; + // free any clusters - will fail if read-only or directory + if (!truncate(0)) goto fail; - // cache directory entry - d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) goto fail; + // cache directory entry + d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) goto fail; - // mark entry deleted - d->name[0] = DIR_NAME_DELETED; + // mark entry deleted + d->name[0] = DIR_NAME_DELETED; - // set this file closed - type_ = FAT_FILE_TYPE_CLOSED; + // set this file closed + type_ = FAT_FILE_TYPE_CLOSED; - // write entry to SD - return vol_->cacheFlush(); - return true; + // write entry to SD + return vol_->cacheFlush(); + return true; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Remove a file. @@ -1236,13 +1236,13 @@ bool SdBaseFile::remove() { * or an I/O error occurred. */ bool SdBaseFile::remove(SdBaseFile* dirFile, const char* path) { - SdBaseFile file; - if (!file.open(dirFile, path, O_WRITE)) goto fail; - return file.remove(); + SdBaseFile file; + if (!file.open(dirFile, path, O_WRITE)) goto fail; + return file.remove(); - fail: - // can't set iostate - static function - return false; +fail: + // can't set iostate - static function + return false; } //------------------------------------------------------------------------------ /** Rename a file or subdirectory. @@ -1256,81 +1256,81 @@ bool SdBaseFile::remove(SdBaseFile* dirFile, const char* path) { * file, newPath is invalid or already exists, or an I/O error occurs. */ bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) { - dir_t entry; - uint32_t dirCluster = 0; - SdBaseFile file; - dir_t* d; + dir_t entry; + uint32_t dirCluster = 0; + SdBaseFile file; + dir_t* d; - // must be an open file or subdirectory - if (!(isFile() || isSubDir())) goto fail; + // must be an open file or subdirectory + if (!(isFile() || isSubDir())) goto fail; - // can't move file - if (vol_ != dirFile->vol_) goto fail; + // can't move file + if (vol_ != dirFile->vol_) goto fail; - // sync() and cache directory entry - sync(); - d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) goto fail; + // sync() and cache directory entry + sync(); + d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) goto fail; - // save directory entry - memcpy(&entry, d, sizeof(entry)); + // save directory entry + memcpy(&entry, d, sizeof(entry)); - // mark entry deleted - d->name[0] = DIR_NAME_DELETED; + // mark entry deleted + d->name[0] = DIR_NAME_DELETED; - // make directory entry for new path - if (isFile()) { - if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRITE)) { - goto restore; + // make directory entry for new path + if (isFile()) { + if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRITE)) { + goto restore; + } + } else { + // don't create missing path prefix components + if (!file.mkdir(dirFile, newPath, false)) { + goto restore; + } + // save cluster containing new dot dot + dirCluster = file.firstCluster_; } - } else { - // don't create missing path prefix components - if (!file.mkdir(dirFile, newPath, false)) { - goto restore; + // change to new directory entry + dirBlock_ = file.dirBlock_; + dirIndex_ = file.dirIndex_; + + // mark closed to avoid possible destructor close call + file.type_ = FAT_FILE_TYPE_CLOSED; + + // cache new directory entry + d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) goto fail; + + // copy all but name field to new directory entry + memcpy(&d->attributes, &entry.attributes, sizeof(entry) - sizeof(d->name)); + + // update dot dot if directory + if (dirCluster) { + // get new dot dot + uint32_t block = vol_->clusterStartBlock(dirCluster); + if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail; + memcpy(&entry, &vol_->cache()->dir[1], sizeof(entry)); + + // free unused cluster + if (!vol_->freeChain(dirCluster)) goto fail; + + // store new dot dot + block = vol_->clusterStartBlock(firstCluster_); + if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; + memcpy(&vol_->cache()->dir[1], &entry, sizeof(entry)); } - // save cluster containing new dot dot - dirCluster = file.firstCluster_; - } - // change to new directory entry - dirBlock_ = file.dirBlock_; - dirIndex_ = file.dirIndex_; - - // mark closed to avoid possible destructor close call - file.type_ = FAT_FILE_TYPE_CLOSED; - - // cache new directory entry - d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) goto fail; - - // copy all but name field to new directory entry - memcpy(&d->attributes, &entry.attributes, sizeof(entry) - sizeof(d->name)); - - // update dot dot if directory - if (dirCluster) { - // get new dot dot - uint32_t block = vol_->clusterStartBlock(dirCluster); - if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail; - memcpy(&entry, &vol_->cache()->dir[1], sizeof(entry)); - - // free unused cluster - if (!vol_->freeChain(dirCluster)) goto fail; - - // store new dot dot - block = vol_->clusterStartBlock(firstCluster_); - if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; - memcpy(&vol_->cache()->dir[1], &entry, sizeof(entry)); - } - return vol_->cacheFlush(); - - restore: - d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) goto fail; - // restore entry - d->name[0] = entry.name[0]; - vol_->cacheFlush(); - - fail: - return false; + return vol_->cacheFlush(); + +restore: + d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) goto fail; + // restore entry + d->name[0] = entry.name[0]; + vol_->cacheFlush(); + +fail: + return false; } //------------------------------------------------------------------------------ /** Remove a directory file. @@ -1349,29 +1349,29 @@ bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) { * directory, is not empty, or an I/O error occurred. */ bool SdBaseFile::rmdir() { - // must be open subdirectory - if (!isSubDir()) goto fail; - - rewind(); + // must be open subdirectory + if (!isSubDir()) goto fail; + + rewind(); + + // make sure directory is empty + while (curPosition_ < fileSize_) { + dir_t* p = readDirCache(); + if (!p) goto fail; + // done if past last used entry + if (p->name[0] == DIR_NAME_FREE) break; + // skip empty slot, '.' or '..' + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; + // error not empty + if (DIR_IS_FILE_OR_SUBDIR(p)) goto fail; + } + // convert empty directory to normal file for remove + type_ = FAT_FILE_TYPE_NORMAL; + flags_ |= O_WRITE; + return remove(); - // make sure directory is empty - while (curPosition_ < fileSize_) { - dir_t* p = readDirCache(); - if (!p) goto fail; - // done if past last used entry - if (p->name[0] == DIR_NAME_FREE) break; - // skip empty slot, '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - // error not empty - if (DIR_IS_FILE_OR_SUBDIR(p)) goto fail; - } - // convert empty directory to normal file for remove - type_ = FAT_FILE_TYPE_NORMAL; - flags_ |= O_WRITE; - return remove(); - - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Recursively delete a directory and all contained files. @@ -1390,47 +1390,47 @@ bool SdBaseFile::rmdir() { * the value zero, false, is returned for failure. */ bool SdBaseFile::rmRfStar() { - uint16_t index; - SdBaseFile f; - rewind(); - while (curPosition_ < fileSize_) { - // remember position - index = curPosition_/32; - - dir_t* p = readDirCache(); - if (!p) goto fail; + uint16_t index; + SdBaseFile f; + rewind(); + while (curPosition_ < fileSize_) { + // remember position + index = curPosition_/32; - // done if past last entry - if (p->name[0] == DIR_NAME_FREE) break; + dir_t* p = readDirCache(); + if (!p) goto fail; - // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; + // done if past last entry + if (p->name[0] == DIR_NAME_FREE) break; - // skip if part of long file name or volume label in root - if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; + // skip empty slot or '.' or '..' + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; - if (!f.open(this, index, O_READ)) goto fail; - if (f.isSubDir()) { - // recursively delete - if (!f.rmRfStar()) goto fail; - } else { - // ignore read-only - f.flags_ |= O_WRITE; - if (!f.remove()) goto fail; + // skip if part of long file name or volume label in root + if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; + + if (!f.open(this, index, O_READ)) goto fail; + if (f.isSubDir()) { + // recursively delete + if (!f.rmRfStar()) goto fail; + } else { + // ignore read-only + f.flags_ |= O_WRITE; + if (!f.remove()) goto fail; + } + // position to next entry if required + if (curPosition_ != (32*(index + 1))) { + if (!seekSet(32*(index + 1))) goto fail; + } } - // position to next entry if required - if (curPosition_ != (32*(index + 1))) { - if (!seekSet(32*(index + 1))) goto fail; + // don't try to delete root + if (!isRoot()) { + if (!rmdir()) goto fail; } - } - // don't try to delete root - if (!isRoot()) { - if (!rmdir()) goto fail; - } - return true; - - fail: - return false; + return true; + +fail: + return false; } //------------------------------------------------------------------------------ /** Create a file object and open it in the current working directory. @@ -1441,9 +1441,9 @@ bool SdBaseFile::rmRfStar() { * OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t). */ SdBaseFile::SdBaseFile(const char* path, uint8_t oflag) { - type_ = FAT_FILE_TYPE_CLOSED; - writeError = false; - open(path, oflag); + type_ = FAT_FILE_TYPE_CLOSED; + writeError = false; + open(path, oflag); } //------------------------------------------------------------------------------ /** Sets a file's position. @@ -1454,47 +1454,47 @@ SdBaseFile::SdBaseFile(const char* path, uint8_t oflag) { * the value zero, false, is returned for failure. */ bool SdBaseFile::seekSet(uint32_t pos) { - uint32_t nCur; - uint32_t nNew; - // error if file not open or seek past end of file - if (!isOpen() || pos > fileSize_) goto fail; + uint32_t nCur; + uint32_t nNew; + // error if file not open or seek past end of file + if (!isOpen() || pos > fileSize_) goto fail; - if (type_ == FAT_FILE_TYPE_ROOT_FIXED) { + if (type_ == FAT_FILE_TYPE_ROOT_FIXED) { + curPosition_ = pos; + goto done; + } + if (pos == 0) { + // set position to start of file + curCluster_ = 0; + curPosition_ = 0; + goto done; + } + // calculate cluster index for cur and new position + nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); + nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); + + if (nNew < nCur || curPosition_ == 0) { + // must follow chain from first cluster + curCluster_ = firstCluster_; + } else { + // advance from curPosition + nNew -= nCur; + } + while (nNew--) { + if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail; + } curPosition_ = pos; - goto done; - } - if (pos == 0) { - // set position to start of file - curCluster_ = 0; - curPosition_ = 0; - goto done; - } - // calculate cluster index for cur and new position - nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); - nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); - - if (nNew < nCur || curPosition_ == 0) { - // must follow chain from first cluster - curCluster_ = firstCluster_; - } else { - // advance from curPosition - nNew -= nCur; - } - while (nNew--) { - if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail; - } - curPosition_ = pos; - - done: - return true; - - fail: - return false; + +done: + return true; + +fail: + return false; } //------------------------------------------------------------------------------ void SdBaseFile::setpos(filepos_t* pos) { - curPosition_ = pos->position; - curCluster_ = pos->cluster; + curPosition_ = pos->position; + curCluster_ = pos->cluster; } //------------------------------------------------------------------------------ /** The sync() call causes all modified data and directory fields @@ -1506,34 +1506,34 @@ void SdBaseFile::setpos(filepos_t* pos) { * opened or an I/O error. */ bool SdBaseFile::sync() { - // only allow open files and directories - if (!isOpen()) goto fail; + // only allow open files and directories + if (!isOpen()) goto fail; - if (flags_ & F_FILE_DIR_DIRTY) { - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - // check for deleted by another open file object - if (!d || d->name[0] == DIR_NAME_DELETED) goto fail; + if (flags_ & F_FILE_DIR_DIRTY) { + dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + // check for deleted by another open file object + if (!d || d->name[0] == DIR_NAME_DELETED) goto fail; - // do not set filesize for dir files - if (!isDir()) d->fileSize = fileSize_; + // do not set filesize for dir files + if (!isDir()) d->fileSize = fileSize_; - // update first cluster fields - d->firstClusterLow = firstCluster_ & 0XFFFF; - d->firstClusterHigh = firstCluster_ >> 16; + // update first cluster fields + d->firstClusterLow = firstCluster_ & 0XFFFF; + d->firstClusterHigh = firstCluster_ >> 16; - // set modify time if user supplied a callback date/time function - if (dateTime_) { - dateTime_(&d->lastWriteDate, &d->lastWriteTime); - d->lastAccessDate = d->lastWriteDate; + // set modify time if user supplied a callback date/time function + if (dateTime_) { + dateTime_(&d->lastWriteDate, &d->lastWriteTime); + d->lastAccessDate = d->lastWriteDate; + } + // clear directory dirty + flags_ &= ~F_FILE_DIR_DIRTY; } - // clear directory dirty - flags_ &= ~F_FILE_DIR_DIRTY; - } - return vol_->cacheFlush(); - - fail: - writeError = true; - return false; + return vol_->cacheFlush(); + +fail: + writeError = true; + return false; } //------------------------------------------------------------------------------ /** Copy a file's timestamps @@ -1548,31 +1548,31 @@ bool SdBaseFile::sync() { * the value zero, false, is returned for failure. */ bool SdBaseFile::timestamp(SdBaseFile* file) { - dir_t* d; - dir_t dir; + dir_t* d; + dir_t dir; - // get timestamps - if (!file->dirEntry(&dir)) goto fail; + // get timestamps + if (!file->dirEntry(&dir)) goto fail; - // update directory fields - if (!sync()) goto fail; + // update directory fields + if (!sync()) goto fail; - d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) goto fail; + d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) goto fail; - // copy timestamps - d->lastAccessDate = dir.lastAccessDate; - d->creationDate = dir.creationDate; - d->creationTime = dir.creationTime; - d->creationTimeTenths = dir.creationTimeTenths; - d->lastWriteDate = dir.lastWriteDate; - d->lastWriteTime = dir.lastWriteTime; + // copy timestamps + d->lastAccessDate = dir.lastAccessDate; + d->creationDate = dir.creationDate; + d->creationTime = dir.creationTime; + d->creationTimeTenths = dir.creationTimeTenths; + d->lastWriteDate = dir.lastWriteDate; + d->lastWriteTime = dir.lastWriteTime; - // write back entry - return vol_->cacheFlush(); + // write back entry + return vol_->cacheFlush(); - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Set a file's timestamps in its directory entry. @@ -1609,48 +1609,48 @@ bool SdBaseFile::timestamp(SdBaseFile* file) { * the value zero, false, is returned for failure. */ bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, - uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { - uint16_t dirDate; - uint16_t dirTime; - dir_t* d; - - if (!isOpen() - || year < 1980 - || year > 2107 - || month < 1 - || month > 12 - || day < 1 - || day > 31 - || hour > 23 - || minute > 59 - || second > 59) { - goto fail; - } - // update directory entry - if (!sync()) goto fail; - - d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) goto fail; - - dirDate = FAT_DATE(year, month, day); - dirTime = FAT_TIME(hour, minute, second); - if (flags & T_ACCESS) { - d->lastAccessDate = dirDate; - } - if (flags & T_CREATE) { - d->creationDate = dirDate; - d->creationTime = dirTime; - // seems to be units of 1/100 second not 1/10 as Microsoft states - d->creationTimeTenths = second & 1 ? 100 : 0; - } - if (flags & T_WRITE) { - d->lastWriteDate = dirDate; - d->lastWriteTime = dirTime; - } - return vol_->cacheFlush(); - - fail: - return false; + uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { + uint16_t dirDate; + uint16_t dirTime; + dir_t* d; + + if (!isOpen() + || year < 1980 + || year > 2107 + || month < 1 + || month > 12 + || day < 1 + || day > 31 + || hour > 23 + || minute > 59 + || second > 59) { + goto fail; + } + // update directory entry + if (!sync()) goto fail; + + d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) goto fail; + + dirDate = FAT_DATE(year, month, day); + dirTime = FAT_TIME(hour, minute, second); + if (flags & T_ACCESS) { + d->lastAccessDate = dirDate; + } + if (flags & T_CREATE) { + d->creationDate = dirDate; + d->creationTime = dirTime; + // seems to be units of 1/100 second not 1/10 as Microsoft states + d->creationTimeTenths = second & 1 ? 100 : 0; + } + if (flags & T_WRITE) { + d->lastWriteDate = dirDate; + d->lastWriteTime = dirTime; + } + return vol_->cacheFlush(); + +fail: + return false; } //------------------------------------------------------------------------------ /** Truncate a file to a specified length. The current file position @@ -1665,50 +1665,50 @@ bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, * \a length is greater than the current file size or an I/O error occurs. */ bool SdBaseFile::truncate(uint32_t length) { - uint32_t newPos; - // error if not a normal file or read-only - if (!isFile() || !(flags_ & O_WRITE)) goto fail; + uint32_t newPos; + // error if not a normal file or read-only + if (!isFile() || !(flags_ & O_WRITE)) goto fail; - // error if length is greater than current size - if (length > fileSize_) goto fail; + // error if length is greater than current size + if (length > fileSize_) goto fail; - // fileSize and length are zero - nothing to do - if (fileSize_ == 0) return true; + // fileSize and length are zero - nothing to do + if (fileSize_ == 0) return true; - // remember position for seek after truncation - newPos = curPosition_ > length ? length : curPosition_; + // remember position for seek after truncation + newPos = curPosition_ > length ? length : curPosition_; - // position to last cluster in truncated file - if (!seekSet(length)) goto fail; + // position to last cluster in truncated file + if (!seekSet(length)) goto fail; - if (length == 0) { - // free all clusters - if (!vol_->freeChain(firstCluster_)) goto fail; - firstCluster_ = 0; - } else { - uint32_t toFree; - if (!vol_->fatGet(curCluster_, &toFree)) goto fail; + if (length == 0) { + // free all clusters + if (!vol_->freeChain(firstCluster_)) goto fail; + firstCluster_ = 0; + } else { + uint32_t toFree; + if (!vol_->fatGet(curCluster_, &toFree)) goto fail; - if (!vol_->isEOC(toFree)) { - // free extra clusters - if (!vol_->freeChain(toFree)) goto fail; + if (!vol_->isEOC(toFree)) { + // free extra clusters + if (!vol_->freeChain(toFree)) goto fail; - // current cluster is end of chain - if (!vol_->fatPutEOC(curCluster_)) goto fail; + // current cluster is end of chain + if (!vol_->fatPutEOC(curCluster_)) goto fail; + } } - } - fileSize_ = length; + fileSize_ = length; - // need to update directory entry - flags_ |= F_FILE_DIR_DIRTY; + // need to update directory entry + flags_ |= F_FILE_DIR_DIRTY; - if (!sync()) goto fail; + if (!sync()) goto fail; - // set file to correct position - return seekSet(newPos); + // set file to correct position + return seekSet(newPos); - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Write data to an open file. @@ -1727,93 +1727,93 @@ bool SdBaseFile::truncate(uint32_t length) { * */ int16_t SdBaseFile::write(const void* buf, uint16_t nbyte) { - // convert void* to uint8_t* - must be before goto statements - const uint8_t* src = reinterpret_cast(buf); - - // number of bytes left to write - must be before goto statements - uint16_t nToWrite = nbyte; - - // error if not a normal file or is read-only - if (!isFile() || !(flags_ & O_WRITE)) goto fail; - - // seek to end of file if append flag - if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { - if (!seekEnd()) goto fail; - } - - while (nToWrite > 0) { - uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); - uint16_t blockOffset = curPosition_ & 0X1FF; - if (blockOfCluster == 0 && blockOffset == 0) { - // start of new cluster - if (curCluster_ == 0) { - if (firstCluster_ == 0) { - // allocate first cluster of file - if (!addCluster()) goto fail; - } else { - curCluster_ = firstCluster_; + // convert void* to uint8_t* - must be before goto statements + const uint8_t* src = reinterpret_cast(buf); + + // number of bytes left to write - must be before goto statements + uint16_t nToWrite = nbyte; + + // error if not a normal file or is read-only + if (!isFile() || !(flags_ & O_WRITE)) goto fail; + + // seek to end of file if append flag + if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { + if (!seekEnd()) goto fail; + } + + while (nToWrite > 0) { + uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); + uint16_t blockOffset = curPosition_ & 0X1FF; + if (blockOfCluster == 0 && blockOffset == 0) { + // start of new cluster + if (curCluster_ == 0) { + if (firstCluster_ == 0) { + // allocate first cluster of file + if (!addCluster()) goto fail; + } else { + curCluster_ = firstCluster_; + } + } else { + uint32_t next; + if (!vol_->fatGet(curCluster_, &next)) goto fail; + if (vol_->isEOC(next)) { + // add cluster if at end of chain + if (!addCluster()) goto fail; + } else { + curCluster_ = next; + } + } } - } else { - uint32_t next; - if (!vol_->fatGet(curCluster_, &next)) goto fail; - if (vol_->isEOC(next)) { - // add cluster if at end of chain - if (!addCluster()) goto fail; + // max space in block + uint16_t n = 512 - blockOffset; + + // lesser of space and amount to write + if (n > nToWrite) n = nToWrite; + + // block for data write + uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; + if (n == 512) { + // full block - don't need to use cache + if (vol_->cacheBlockNumber() == block) { + // invalidate cache if block is in cache + vol_->cacheSetBlockNumber(0XFFFFFFFF, false); + } + if (!vol_->writeBlock(block, src)) goto fail; } else { - curCluster_ = next; + if (blockOffset == 0 && curPosition_ >= fileSize_) { + // start of new block don't need to read into cache + if (!vol_->cacheFlush()) goto fail; + // set cache dirty and SD address of block + vol_->cacheSetBlockNumber(block, true); + } else { + // rewrite part of block + if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; + } + uint8_t* dst = vol_->cache()->data + blockOffset; + memcpy(dst, src, n); } - } + curPosition_ += n; + src += n; + nToWrite -= n; } - // max space in block - uint16_t n = 512 - blockOffset; - - // lesser of space and amount to write - if (n > nToWrite) n = nToWrite; - - // block for data write - uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; - if (n == 512) { - // full block - don't need to use cache - if (vol_->cacheBlockNumber() == block) { - // invalidate cache if block is in cache - vol_->cacheSetBlockNumber(0XFFFFFFFF, false); - } - if (!vol_->writeBlock(block, src)) goto fail; - } else { - if (blockOffset == 0 && curPosition_ >= fileSize_) { - // start of new block don't need to read into cache - if (!vol_->cacheFlush()) goto fail; - // set cache dirty and SD address of block - vol_->cacheSetBlockNumber(block, true); - } else { - // rewrite part of block - if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail; - } - uint8_t* dst = vol_->cache()->data + blockOffset; - memcpy(dst, src, n); + if (curPosition_ > fileSize_) { + // update fileSize and insure sync will update dir entry + fileSize_ = curPosition_; + flags_ |= F_FILE_DIR_DIRTY; + } else if (dateTime_ && nbyte) { + // insure sync will update modified date and time + flags_ |= F_FILE_DIR_DIRTY; } - curPosition_ += n; - src += n; - nToWrite -= n; - } - if (curPosition_ > fileSize_) { - // update fileSize and insure sync will update dir entry - fileSize_ = curPosition_; - flags_ |= F_FILE_DIR_DIRTY; - } else if (dateTime_ && nbyte) { - // insure sync will update modified date and time - flags_ |= F_FILE_DIR_DIRTY; - } - if (flags_ & O_SYNC) { - if (!sync()) goto fail; - } - return nbyte; + if (flags_ & O_SYNC) { + if (!sync()) goto fail; + } + return nbyte; - fail: - // return for write error - writeError = true; - return -1; +fail: + // return for write error + writeError = true; + return -1; } //------------------------------------------------------------------------------ // suppress cpplint warnings with NOLINT comment diff --git a/Firmware/SdBaseFile.h b/Firmware/SdBaseFile.h index 923a391dd5..fa6ad5c3e6 100755 --- a/Firmware/SdBaseFile.h +++ b/Firmware/SdBaseFile.h @@ -36,11 +36,11 @@ * do not use in user apps */ struct filepos_t { - /** stream position */ - uint32_t position; - /** cluster for position */ - uint32_t cluster; - filepos_t() : position(0), cluster(0) {} + /** stream position */ + uint32_t position; + /** cluster for position */ + uint32_t cluster; + filepos_t() : position(0), cluster(0) {} }; // use the gnu style oflag in open() @@ -108,7 +108,7 @@ uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED; * \return Packed date for dir_t entry. */ static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { - return (year - 1980) << 9 | month << 5 | day; + return (year - 1980) << 9 | month << 5 | day; } /** year part of FAT directory date field * \param[in] fatDate Date in packed dir format. @@ -116,7 +116,7 @@ static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { * \return Extracted year [1980,2107] */ static inline uint16_t FAT_YEAR(uint16_t fatDate) { - return 1980 + (fatDate >> 9); + return 1980 + (fatDate >> 9); } /** month part of FAT directory date field * \param[in] fatDate Date in packed dir format. @@ -124,7 +124,7 @@ static inline uint16_t FAT_YEAR(uint16_t fatDate) { * \return Extracted month [1,12] */ static inline uint8_t FAT_MONTH(uint16_t fatDate) { - return (fatDate >> 5) & 0XF; + return (fatDate >> 5) & 0XF; } /** day part of FAT directory date field * \param[in] fatDate Date in packed dir format. @@ -132,7 +132,7 @@ static inline uint8_t FAT_MONTH(uint16_t fatDate) { * \return Extracted day [1,31] */ static inline uint8_t FAT_DAY(uint16_t fatDate) { - return fatDate & 0X1F; + return fatDate & 0X1F; } /** time field for FAT directory entry * \param[in] hour [0,23] @@ -142,7 +142,7 @@ static inline uint8_t FAT_DAY(uint16_t fatDate) { * \return Packed time for dir_t entry. */ static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { - return hour << 11 | minute << 5 | second >> 1; + return hour << 11 | minute << 5 | second >> 1; } /** hour part of FAT directory time field * \param[in] fatTime Time in packed dir format. @@ -150,7 +150,7 @@ static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { * \return Extracted hour [0,23] */ static inline uint8_t FAT_HOUR(uint16_t fatTime) { - return fatTime >> 11; + return fatTime >> 11; } /** minute part of FAT directory time field * \param[in] fatTime Time in packed dir format. @@ -158,7 +158,7 @@ static inline uint8_t FAT_HOUR(uint16_t fatTime) { * \return Extracted minute [0,59] */ static inline uint8_t FAT_MINUTE(uint16_t fatTime) { - return(fatTime >> 5) & 0X3F; + return(fatTime >> 5) & 0X3F; } /** second part of FAT directory time field * Note second/2 is stored in packed time. @@ -168,7 +168,7 @@ static inline uint8_t FAT_MINUTE(uint16_t fatTime) { * \return Extracted second [0,58] */ static inline uint8_t FAT_SECOND(uint16_t fatTime) { - return 2*(fatTime & 0X1F); + return 2*(fatTime & 0X1F); } /** Default date for file timestamps is 1 Jan 2000 */ uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1; @@ -180,302 +180,340 @@ uint16_t const FAT_DEFAULT_TIME = (1 << 11); * \brief Base class for SdFile with Print and C++ streams. */ class SdBaseFile { - public: - /** Create an instance. */ - SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {} - SdBaseFile(const char* path, uint8_t oflag); - ~SdBaseFile() {if(isOpen()) close();} - /** - * writeError is set to true if an error occurs during a write(). - * Set writeError to false before calling print() and/or write() and check - * for true after calls to print() and/or write(). - */ - bool writeError; - //---------------------------------------------------------------------------- - // helpers for stream classes - /** get position for streams - * \param[out] pos struct to receive position - */ - void getpos(filepos_t* pos); - /** set position for streams - * \param[out] pos struct with value for new position - */ - void setpos(filepos_t* pos); - //---------------------------------------------------------------------------- - bool close(); - bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); - bool createContiguous(SdBaseFile* dirFile, - const char* path, uint32_t size); - /** \return The current cluster number for a file or directory. */ - uint32_t curCluster() const {return curCluster_;} - /** \return The current position for a file or directory. */ - uint32_t curPosition() const {return curPosition_;} - /** \return Current working directory */ - static SdBaseFile* cwd() {return cwd_;} - /** Set the date/time callback function - * - * \param[in] dateTime The user's call back function. The callback - * function is of the form: - * - * \code - * void dateTime(uint16_t* date, uint16_t* time) { - * uint16_t year; - * uint8_t month, day, hour, minute, second; - * - * // User gets date and time from GPS or real-time clock here - * - * // return date using FAT_DATE macro to format fields - * *date = FAT_DATE(year, month, day); - * - * // return time using FAT_TIME macro to format fields - * *time = FAT_TIME(hour, minute, second); - * } - * \endcode - * - * Sets the function that is called when a file is created or when - * a file's directory entry is modified by sync(). All timestamps, - * access, creation, and modify, are set when a file is created. - * sync() maintains the last access date and last modify date/time. - * - * See the timestamp() function. - */ - static void dateTimeCallback( - void (*dateTime)(uint16_t* date, uint16_t* time)) { - dateTime_ = dateTime; - } - /** Cancel the date/time callback function. */ - static void dateTimeCallbackCancel() {dateTime_ = 0;} - bool dirEntry(dir_t* dir); - static void dirName(const dir_t& dir, char* name); - bool exists(const char* name); - int16_t fgets(char* str, int16_t num, char* delim = 0); - /** \return The total number of bytes in a file or directory. */ - uint32_t fileSize() const {return fileSize_;} - /** \return The first cluster number for a file or directory. */ - uint32_t firstCluster() const {return firstCluster_;} - bool getFilename(char* name); - /** \return True if this is a directory else false. */ - bool isDir() const {return type_ >= FAT_FILE_TYPE_MIN_DIR;} - /** \return True if this is a normal file else false. */ - bool isFile() const {return type_ == FAT_FILE_TYPE_NORMAL;} - /** \return True if this is an open file/directory else false. */ - bool isOpen() const {return type_ != FAT_FILE_TYPE_CLOSED;} - /** \return True if this is a subdirectory else false. */ - bool isSubDir() const {return type_ == FAT_FILE_TYPE_SUBDIR;} - /** \return True if this is the root directory. */ - bool isRoot() const { - return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32; - } - void ls( uint8_t flags = 0, uint8_t indent = 0); - bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true); - // alias for backward compactability - bool makeDir(SdBaseFile* dir, const char* path) { - return mkdir(dir, path, false); - } - bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag); - bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag); - bool open(const char* path, uint8_t oflag = O_READ); - bool openNext(SdBaseFile* dirFile, uint8_t oflag); - bool openRoot(SdVolume* vol); - int peek(); - static void printFatDate(uint16_t fatDate); - static void printFatTime( uint16_t fatTime); - bool printName(); - int16_t read(); - int16_t read(void* buf, uint16_t nbyte); - int8_t readDir(dir_t* dir, char* longFilename); - static bool remove(SdBaseFile* dirFile, const char* path); - bool remove(); - /** Set the file's current position to zero. */ - void rewind() {seekSet(0);} - bool rename(SdBaseFile* dirFile, const char* newPath); - bool rmdir(); - // for backward compatibility - bool rmDir() {return rmdir();} - bool rmRfStar(); - /** Set the files position to current position + \a pos. See seekSet(). - * \param[in] offset The new position in bytes from the current position. - * \return true for success or false for failure. - */ - bool seekCur(int32_t offset) { - return seekSet(curPosition_ + offset); - } - /** Set the files position to end-of-file + \a offset. See seekSet(). - * \param[in] offset The new position in bytes from end-of-file. - * \return true for success or false for failure. - */ - bool seekEnd(int32_t offset = 0) {return seekSet(fileSize_ + offset);} - bool seekSet(uint32_t pos); - bool sync(); - bool timestamp(SdBaseFile* file); - bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, - uint8_t hour, uint8_t minute, uint8_t second); - /** Type of file. You should use isFile() or isDir() instead of type() - * if possible. - * - * \return The file or directory type. - */ - uint8_t type() const {return type_;} - bool truncate(uint32_t size); - /** \return SdVolume that contains this file. */ - SdVolume* volume() const {return vol_;} - int16_t write(const void* buf, uint16_t nbyte); +public: + /** Create an instance. */ + SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {} + SdBaseFile(const char* path, uint8_t oflag); + ~SdBaseFile() { + if(isOpen()) close(); + } + /** + * writeError is set to true if an error occurs during a write(). + * Set writeError to false before calling print() and/or write() and check + * for true after calls to print() and/or write(). + */ + bool writeError; + //---------------------------------------------------------------------------- + // helpers for stream classes + /** get position for streams + * \param[out] pos struct to receive position + */ + void getpos(filepos_t* pos); + /** set position for streams + * \param[out] pos struct with value for new position + */ + void setpos(filepos_t* pos); + //---------------------------------------------------------------------------- + bool close(); + bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); + bool createContiguous(SdBaseFile* dirFile, + const char* path, uint32_t size); + /** \return The current cluster number for a file or directory. */ + uint32_t curCluster() const { + return curCluster_; + } + /** \return The current position for a file or directory. */ + uint32_t curPosition() const { + return curPosition_; + } + /** \return Current working directory */ + static SdBaseFile* cwd() { + return cwd_; + } + /** Set the date/time callback function + * + * \param[in] dateTime The user's call back function. The callback + * function is of the form: + * + * \code + * void dateTime(uint16_t* date, uint16_t* time) { + * uint16_t year; + * uint8_t month, day, hour, minute, second; + * + * // User gets date and time from GPS or real-time clock here + * + * // return date using FAT_DATE macro to format fields + * *date = FAT_DATE(year, month, day); + * + * // return time using FAT_TIME macro to format fields + * *time = FAT_TIME(hour, minute, second); + * } + * \endcode + * + * Sets the function that is called when a file is created or when + * a file's directory entry is modified by sync(). All timestamps, + * access, creation, and modify, are set when a file is created. + * sync() maintains the last access date and last modify date/time. + * + * See the timestamp() function. + */ + static void dateTimeCallback( + void (*dateTime)(uint16_t* date, uint16_t* time)) { + dateTime_ = dateTime; + } + /** Cancel the date/time callback function. */ + static void dateTimeCallbackCancel() { + dateTime_ = 0; + } + bool dirEntry(dir_t* dir); + static void dirName(const dir_t& dir, char* name); + bool exists(const char* name); + int16_t fgets(char* str, int16_t num, char* delim = 0); + /** \return The total number of bytes in a file or directory. */ + uint32_t fileSize() const { + return fileSize_; + } + /** \return The first cluster number for a file or directory. */ + uint32_t firstCluster() const { + return firstCluster_; + } + bool getFilename(char* name); + /** \return True if this is a directory else false. */ + bool isDir() const { + return type_ >= FAT_FILE_TYPE_MIN_DIR; + } + /** \return True if this is a normal file else false. */ + bool isFile() const { + return type_ == FAT_FILE_TYPE_NORMAL; + } + /** \return True if this is an open file/directory else false. */ + bool isOpen() const { + return type_ != FAT_FILE_TYPE_CLOSED; + } + /** \return True if this is a subdirectory else false. */ + bool isSubDir() const { + return type_ == FAT_FILE_TYPE_SUBDIR; + } + /** \return True if this is the root directory. */ + bool isRoot() const { + return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32; + } + void ls( uint8_t flags = 0, uint8_t indent = 0); + bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true); + // alias for backward compactability + bool makeDir(SdBaseFile* dir, const char* path) { + return mkdir(dir, path, false); + } + bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag); + bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag); + bool open(const char* path, uint8_t oflag = O_READ); + bool openNext(SdBaseFile* dirFile, uint8_t oflag); + bool openRoot(SdVolume* vol); + int peek(); + static void printFatDate(uint16_t fatDate); + static void printFatTime( uint16_t fatTime); + bool printName(); + int16_t read(); + int16_t read(void* buf, uint16_t nbyte); + int8_t readDir(dir_t* dir, char* longFilename); + static bool remove(SdBaseFile* dirFile, const char* path); + bool remove(); + /** Set the file's current position to zero. */ + void rewind() { + seekSet(0); + } + bool rename(SdBaseFile* dirFile, const char* newPath); + bool rmdir(); + // for backward compatibility + bool rmDir() { + return rmdir(); + } + bool rmRfStar(); + /** Set the files position to current position + \a pos. See seekSet(). + * \param[in] offset The new position in bytes from the current position. + * \return true for success or false for failure. + */ + bool seekCur(int32_t offset) { + return seekSet(curPosition_ + offset); + } + /** Set the files position to end-of-file + \a offset. See seekSet(). + * \param[in] offset The new position in bytes from end-of-file. + * \return true for success or false for failure. + */ + bool seekEnd(int32_t offset = 0) { + return seekSet(fileSize_ + offset); + } + bool seekSet(uint32_t pos); + bool sync(); + bool timestamp(SdBaseFile* file); + bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, + uint8_t hour, uint8_t minute, uint8_t second); + /** Type of file. You should use isFile() or isDir() instead of type() + * if possible. + * + * \return The file or directory type. + */ + uint8_t type() const { + return type_; + } + bool truncate(uint32_t size); + /** \return SdVolume that contains this file. */ + SdVolume* volume() const { + return vol_; + } + int16_t write(const void* buf, uint16_t nbyte); //------------------------------------------------------------------------------ - private: - // allow SdFat to set cwd_ - friend class SdFat; - // global pointer to cwd dir - static SdBaseFile* cwd_; - // data time callback function - static void (*dateTime_)(uint16_t* date, uint16_t* time); - // bits defined in flags_ - // should be 0X0F - static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC); - // sync of directory entry required - static uint8_t const F_FILE_DIR_DIRTY = 0X80; +private: + // allow SdFat to set cwd_ + friend class SdFat; + // global pointer to cwd dir + static SdBaseFile* cwd_; + // data time callback function + static void (*dateTime_)(uint16_t* date, uint16_t* time); + // bits defined in flags_ + // should be 0X0F + static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC); + // sync of directory entry required + static uint8_t const F_FILE_DIR_DIRTY = 0X80; - // private data - uint8_t flags_; // See above for definition of flags_ bits - uint8_t fstate_; // error and eof indicator - uint8_t type_; // type of file see above for values - uint32_t curCluster_; // cluster for current file position - uint32_t curPosition_; // current file position in bytes from beginning - uint32_t dirBlock_; // block for this files directory entry - uint8_t dirIndex_; // index of directory entry in dirBlock - uint32_t fileSize_; // file size in bytes - uint32_t firstCluster_; // first cluster of file - SdVolume* vol_; // volume where file is located + // private data + uint8_t flags_; // See above for definition of flags_ bits + uint8_t fstate_; // error and eof indicator + uint8_t type_; // type of file see above for values + uint32_t curCluster_; // cluster for current file position + uint32_t curPosition_; // current file position in bytes from beginning + uint32_t dirBlock_; // block for this files directory entry + uint8_t dirIndex_; // index of directory entry in dirBlock + uint32_t fileSize_; // file size in bytes + uint32_t firstCluster_; // first cluster of file + SdVolume* vol_; // volume where file is located - /** experimental don't use */ - bool openParent(SdBaseFile* dir); - // private functions - bool addCluster(); - bool addDirCluster(); - dir_t* cacheDirEntry(uint8_t action); - int8_t lsPrintNext( uint8_t flags, uint8_t indent); - static bool make83Name(const char* str, uint8_t* name, const char** ptr); - bool mkdir(SdBaseFile* parent, const uint8_t dname[11]); - bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag); - bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags); - dir_t* readDirCache(); + /** experimental don't use */ + bool openParent(SdBaseFile* dir); + // private functions + bool addCluster(); + bool addDirCluster(); + dir_t* cacheDirEntry(uint8_t action); + int8_t lsPrintNext( uint8_t flags, uint8_t indent); + static bool make83Name(const char* str, uint8_t* name, const char** ptr); + bool mkdir(SdBaseFile* parent, const uint8_t dname[11]); + bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag); + bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags); + dir_t* readDirCache(); //------------------------------------------------------------------------------ // to be deleted - static void printDirName( const dir_t& dir, - uint8_t width, bool printSlash); + static void printDirName( const dir_t& dir, + uint8_t width, bool printSlash); //------------------------------------------------------------------------------ // Deprecated functions - suppress cpplint warnings with NOLINT comment #if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN) - public: - /** \deprecated Use: - * bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); - * \param[out] bgnBlock the first block address for the file. - * \param[out] endBlock the last block address for the file. - * \return true for success or false for failure. - */ - bool contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT - return contiguousRange(&bgnBlock, &endBlock); - } - /** \deprecated Use: - * bool createContiguous(SdBaseFile* dirFile, - * const char* path, uint32_t size) - * \param[in] dirFile The directory where the file will be created. - * \param[in] path A path with a valid DOS 8.3 file name. - * \param[in] size The desired file size. - * \return true for success or false for failure. - */ - bool createContiguous(SdBaseFile& dirFile, // NOLINT - const char* path, uint32_t size) { - return createContiguous(&dirFile, path, size); - } - /** \deprecated Use: - * static void dateTimeCallback( - * void (*dateTime)(uint16_t* date, uint16_t* time)); - * \param[in] dateTime The user's call back function. - */ - static void dateTimeCallback( - void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT - oldDateTime_ = dateTime; - dateTime_ = dateTime ? oldToNew : 0; - } - /** \deprecated Use: bool dirEntry(dir_t* dir); - * \param[out] dir Location for return of the file's directory entry. - * \return true for success or false for failure. - */ - bool dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT - /** \deprecated Use: - * bool mkdir(SdBaseFile* dir, const char* path); - * \param[in] dir An open SdFat instance for the directory that will contain - * the new directory. - * \param[in] path A path with a valid 8.3 DOS name for the new directory. - * \return true for success or false for failure. - */ - bool mkdir(SdBaseFile& dir, const char* path) { // NOLINT - return mkdir(&dir, path); - } - /** \deprecated Use: - * bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag); - * \param[in] dirFile An open SdFat instance for the directory containing the - * file to be opened. - * \param[in] path A path with a valid 8.3 DOS name for the file. - * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive - * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. - * \return true for success or false for failure. - */ - bool open(SdBaseFile& dirFile, // NOLINT - const char* path, uint8_t oflag) { - return open(&dirFile, path, oflag); - } - /** \deprecated Do not use in new apps - * \param[in] dirFile An open SdFat instance for the directory containing the - * file to be opened. - * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. - * \return true for success or false for failure. - */ - bool open(SdBaseFile& dirFile, const char* path) { // NOLINT - return open(dirFile, path, O_RDWR); - } - /** \deprecated Use: - * bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag); - * \param[in] dirFile An open SdFat instance for the directory. - * \param[in] index The \a index of the directory entry for the file to be - * opened. The value for \a index is (directory file position)/32. - * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive - * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. - * \return true for success or false for failure. - */ - bool open(SdBaseFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT - return open(&dirFile, index, oflag); - } - /** \deprecated Use: bool openRoot(SdVolume* vol); - * \param[in] vol The FAT volume containing the root directory to be opened. - * \return true for success or false for failure. - */ - bool openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT - /** \deprecated Use: int8_t readDir(dir_t* dir); - * \param[out] dir The dir_t struct that will receive the data. - * \return bytes read for success zero for eof or -1 for failure. - */ - int8_t readDir(dir_t& dir, char* longFilename) {return readDir(&dir, longFilename);} // NOLINT - /** \deprecated Use: - * static uint8_t remove(SdBaseFile* dirFile, const char* path); - * \param[in] dirFile The directory that contains the file. - * \param[in] path The name of the file to be removed. - * \return true for success or false for failure. - */ - static bool remove(SdBaseFile& dirFile, const char* path) { // NOLINT - return remove(&dirFile, path); - } +public: + /** \deprecated Use: + * bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); + * \param[out] bgnBlock the first block address for the file. + * \param[out] endBlock the last block address for the file. + * \return true for success or false for failure. + */ + bool contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT + return contiguousRange(&bgnBlock, &endBlock); + } + /** \deprecated Use: + * bool createContiguous(SdBaseFile* dirFile, + * const char* path, uint32_t size) + * \param[in] dirFile The directory where the file will be created. + * \param[in] path A path with a valid DOS 8.3 file name. + * \param[in] size The desired file size. + * \return true for success or false for failure. + */ + bool createContiguous(SdBaseFile& dirFile, // NOLINT + const char* path, uint32_t size) { + return createContiguous(&dirFile, path, size); + } + /** \deprecated Use: + * static void dateTimeCallback( + * void (*dateTime)(uint16_t* date, uint16_t* time)); + * \param[in] dateTime The user's call back function. + */ + static void dateTimeCallback( + void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT + oldDateTime_ = dateTime; + dateTime_ = dateTime ? oldToNew : 0; + } + /** \deprecated Use: bool dirEntry(dir_t* dir); + * \param[out] dir Location for return of the file's directory entry. + * \return true for success or false for failure. + */ + bool dirEntry(dir_t& dir) { + return dirEntry(&dir); // NOLINT + } + /** \deprecated Use: + * bool mkdir(SdBaseFile* dir, const char* path); + * \param[in] dir An open SdFat instance for the directory that will contain + * the new directory. + * \param[in] path A path with a valid 8.3 DOS name for the new directory. + * \return true for success or false for failure. + */ + bool mkdir(SdBaseFile& dir, const char* path) { // NOLINT + return mkdir(&dir, path); + } + /** \deprecated Use: + * bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag); + * \param[in] dirFile An open SdFat instance for the directory containing the + * file to be opened. + * \param[in] path A path with a valid 8.3 DOS name for the file. + * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive + * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. + * \return true for success or false for failure. + */ + bool open(SdBaseFile& dirFile, // NOLINT + const char* path, uint8_t oflag) { + return open(&dirFile, path, oflag); + } + /** \deprecated Do not use in new apps + * \param[in] dirFile An open SdFat instance for the directory containing the + * file to be opened. + * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. + * \return true for success or false for failure. + */ + bool open(SdBaseFile& dirFile, const char* path) { // NOLINT + return open(dirFile, path, O_RDWR); + } + /** \deprecated Use: + * bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag); + * \param[in] dirFile An open SdFat instance for the directory. + * \param[in] index The \a index of the directory entry for the file to be + * opened. The value for \a index is (directory file position)/32. + * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive + * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. + * \return true for success or false for failure. + */ + bool open(SdBaseFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT + return open(&dirFile, index, oflag); + } + /** \deprecated Use: bool openRoot(SdVolume* vol); + * \param[in] vol The FAT volume containing the root directory to be opened. + * \return true for success or false for failure. + */ + bool openRoot(SdVolume& vol) { + return openRoot(&vol); // NOLINT + } + /** \deprecated Use: int8_t readDir(dir_t* dir); + * \param[out] dir The dir_t struct that will receive the data. + * \return bytes read for success zero for eof or -1 for failure. + */ + int8_t readDir(dir_t& dir, char* longFilename) { + return readDir(&dir, longFilename); // NOLINT + } + /** \deprecated Use: + * static uint8_t remove(SdBaseFile* dirFile, const char* path); + * \param[in] dirFile The directory that contains the file. + * \param[in] path The name of the file to be removed. + * \return true for success or false for failure. + */ + static bool remove(SdBaseFile& dirFile, const char* path) { // NOLINT + return remove(&dirFile, path); + } //------------------------------------------------------------------------------ // rest are private - private: - static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT - static void oldToNew(uint16_t* date, uint16_t* time) { - uint16_t d; - uint16_t t; - oldDateTime_(d, t); - *date = d; - *time = t; - } +private: + static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT + static void oldToNew(uint16_t* date, uint16_t* time) { + uint16_t d; + uint16_t t; + oldDateTime_(d, t); + *date = d; + *time = t; + } #endif // ALLOW_DEPRECATED_FUNCTIONS }; diff --git a/Firmware/SdFatStructs.h b/Firmware/SdFatStructs.h index 3867216160..297c1659f8 100755 --- a/Firmware/SdFatStructs.h +++ b/Firmware/SdFatStructs.h @@ -48,55 +48,55 @@ uint8_t const EXTENDED_BOOT_SIG = 0X29; * The MBR partition table has four entries. */ struct partitionTable { - /** - * Boot Indicator . Indicates whether the volume is the active - * partition. Legal values include: 0X00. Do not use for booting. - * 0X80 Active partition. - */ - uint8_t boot; - /** - * Head part of Cylinder-head-sector address of the first block in - * the partition. Legal values are 0-255. Only used in old PC BIOS. - */ - uint8_t beginHead; - /** - * Sector part of Cylinder-head-sector address of the first block in - * the partition. Legal values are 1-63. Only used in old PC BIOS. - */ - unsigned beginSector : 6; - /** High bits cylinder for first block in partition. */ - unsigned beginCylinderHigh : 2; - /** - * Combine beginCylinderLow with beginCylinderHigh. Legal values - * are 0-1023. Only used in old PC BIOS. - */ - uint8_t beginCylinderLow; - /** - * Partition type. See defines that begin with PART_TYPE_ for - * some Microsoft partition types. - */ - uint8_t type; - /** - * head part of cylinder-head-sector address of the last sector in the - * partition. Legal values are 0-255. Only used in old PC BIOS. - */ - uint8_t endHead; - /** - * Sector part of cylinder-head-sector address of the last sector in - * the partition. Legal values are 1-63. Only used in old PC BIOS. - */ - unsigned endSector : 6; - /** High bits of end cylinder */ - unsigned endCylinderHigh : 2; - /** - * Combine endCylinderLow with endCylinderHigh. Legal values - * are 0-1023. Only used in old PC BIOS. - */ - uint8_t endCylinderLow; - /** Logical block address of the first block in the partition. */ - uint32_t firstSector; - /** Length of the partition, in blocks. */ - uint32_t totalSectors; + /** + * Boot Indicator . Indicates whether the volume is the active + * partition. Legal values include: 0X00. Do not use for booting. + * 0X80 Active partition. + */ + uint8_t boot; + /** + * Head part of Cylinder-head-sector address of the first block in + * the partition. Legal values are 0-255. Only used in old PC BIOS. + */ + uint8_t beginHead; + /** + * Sector part of Cylinder-head-sector address of the first block in + * the partition. Legal values are 1-63. Only used in old PC BIOS. + */ + unsigned beginSector : 6; + /** High bits cylinder for first block in partition. */ + unsigned beginCylinderHigh : 2; + /** + * Combine beginCylinderLow with beginCylinderHigh. Legal values + * are 0-1023. Only used in old PC BIOS. + */ + uint8_t beginCylinderLow; + /** + * Partition type. See defines that begin with PART_TYPE_ for + * some Microsoft partition types. + */ + uint8_t type; + /** + * head part of cylinder-head-sector address of the last sector in the + * partition. Legal values are 0-255. Only used in old PC BIOS. + */ + uint8_t endHead; + /** + * Sector part of cylinder-head-sector address of the last sector in + * the partition. Legal values are 1-63. Only used in old PC BIOS. + */ + unsigned endSector : 6; + /** High bits of end cylinder */ + unsigned endCylinderHigh : 2; + /** + * Combine endCylinderLow with endCylinderHigh. Legal values + * are 0-1023. Only used in old PC BIOS. + */ + uint8_t endCylinderLow; + /** Logical block address of the first block in the partition. */ + uint32_t firstSector; + /** Length of the partition, in blocks. */ + uint32_t totalSectors; } PACKED; /** Type name for partitionTable */ typedef struct partitionTable part_t; @@ -109,18 +109,18 @@ typedef struct partitionTable part_t; * The first block of a storage device that is formatted with a MBR. */ struct masterBootRecord { - /** Code Area for master boot program. */ - uint8_t codeArea[440]; - /** Optional Windows NT disk signature. May contain boot code. */ - uint32_t diskSignature; - /** Usually zero but may be more boot code. */ - uint16_t usuallyZero; - /** Partition tables. */ - part_t part[4]; - /** First MBR signature byte. Must be 0X55 */ - uint8_t mbrSig0; - /** Second MBR signature byte. Must be 0XAA */ - uint8_t mbrSig1; + /** Code Area for master boot program. */ + uint8_t codeArea[440]; + /** Optional Windows NT disk signature. May contain boot code. */ + uint32_t diskSignature; + /** Usually zero but may be more boot code. */ + uint16_t usuallyZero; + /** Partition tables. */ + part_t part[4]; + /** First MBR signature byte. Must be 0X55 */ + uint8_t mbrSig0; + /** Second MBR signature byte. Must be 0XAA */ + uint8_t mbrSig1; } PACKED; /** Type name for masterBootRecord */ typedef struct masterBootRecord mbr_t; @@ -132,123 +132,123 @@ typedef struct masterBootRecord mbr_t; * */ struct fat_boot { - /** - * The first three bytes of the boot sector must be valid, - * executable x 86-based CPU instructions. This includes a - * jump instruction that skips the next nonexecutable bytes. - */ - uint8_t jump[3]; - /** - * This is typically a string of characters that identifies - * the operating system that formatted the volume. - */ - char oemId[8]; - /** - * The size of a hardware sector. Valid decimal values for this - * field are 512, 1024, 2048, and 4096. For most disks used in - * the United States, the value of this field is 512. - */ - uint16_t bytesPerSector; - /** - * Number of sectors per allocation unit. This value must be a - * power of 2 that is greater than 0. The legal values are - * 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided. - */ - uint8_t sectorsPerCluster; - /** - * The number of sectors preceding the start of the first FAT, - * including the boot sector. The value of this field is always 1. - */ - uint16_t reservedSectorCount; - /** - * The number of copies of the FAT on the volume. - * The value of this field is always 2. - */ - uint8_t fatCount; - /** - * For FAT12 and FAT16 volumes, this field contains the count of - * 32-byte directory entries in the root directory. For FAT32 volumes, - * this field must be set to 0. For FAT12 and FAT16 volumes, this - * value should always specify a count that when multiplied by 32 - * results in a multiple of bytesPerSector. FAT16 volumes should - * use the value 512. - */ - uint16_t rootDirEntryCount; - /** - * This field is the old 16-bit total count of sectors on the volume. - * This count includes the count of all sectors in all four regions - * of the volume. This field can be 0; if it is 0, then totalSectors32 - * must be nonzero. For FAT32 volumes, this field must be 0. For - * FAT12 and FAT16 volumes, this field contains the sector count, and - * totalSectors32 is 0 if the total sector count fits - * (is less than 0x10000). - */ - uint16_t totalSectors16; - /** - * This dates back to the old MS-DOS 1.x media determination and is - * no longer usually used for anything. 0xF8 is the standard value - * for fixed (nonremovable) media. For removable media, 0xF0 is - * frequently used. Legal values are 0xF0 or 0xF8-0xFF. - */ - uint8_t mediaType; - /** - * Count of sectors occupied by one FAT on FAT12/FAT16 volumes. - * On FAT32 volumes this field must be 0, and sectorsPerFat32 - * contains the FAT size count. - */ - uint16_t sectorsPerFat16; - /** Sectors per track for interrupt 0x13. Not used otherwise. */ - uint16_t sectorsPerTrack; - /** Number of heads for interrupt 0x13. Not used otherwise. */ - uint16_t headCount; - /** - * Count of hidden sectors preceding the partition that contains this - * FAT volume. This field is generally only relevant for media - * visible on interrupt 0x13. - */ - uint32_t hidddenSectors; - /** - * This field is the new 32-bit total count of sectors on the volume. - * This count includes the count of all sectors in all four regions - * of the volume. This field can be 0; if it is 0, then - * totalSectors16 must be nonzero. - */ - uint32_t totalSectors32; - /** - * Related to the BIOS physical drive number. Floppy drives are - * identified as 0x00 and physical hard disks are identified as - * 0x80, regardless of the number of physical disk drives. - * Typically, this value is set prior to issuing an INT 13h BIOS - * call to specify the device to access. The value is only - * relevant if the device is a boot device. - */ - uint8_t driveNumber; - /** used by Windows NT - should be zero for FAT */ - uint8_t reserved1; - /** 0X29 if next three fields are valid */ - uint8_t bootSignature; - /** - * A random serial number created when formatting a disk, - * which helps to distinguish between disks. - * Usually generated by combining date and time. - */ - uint32_t volumeSerialNumber; - /** - * A field once used to store the volume label. The volume label - * is now stored as a special file in the root directory. - */ - char volumeLabel[11]; - /** - * A field with a value of either FAT, FAT12 or FAT16, - * depending on the disk format. - */ - char fileSystemType[8]; - /** X86 boot code */ - uint8_t bootCode[448]; - /** must be 0X55 */ - uint8_t bootSectorSig0; - /** must be 0XAA */ - uint8_t bootSectorSig1; + /** + * The first three bytes of the boot sector must be valid, + * executable x 86-based CPU instructions. This includes a + * jump instruction that skips the next nonexecutable bytes. + */ + uint8_t jump[3]; + /** + * This is typically a string of characters that identifies + * the operating system that formatted the volume. + */ + char oemId[8]; + /** + * The size of a hardware sector. Valid decimal values for this + * field are 512, 1024, 2048, and 4096. For most disks used in + * the United States, the value of this field is 512. + */ + uint16_t bytesPerSector; + /** + * Number of sectors per allocation unit. This value must be a + * power of 2 that is greater than 0. The legal values are + * 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided. + */ + uint8_t sectorsPerCluster; + /** + * The number of sectors preceding the start of the first FAT, + * including the boot sector. The value of this field is always 1. + */ + uint16_t reservedSectorCount; + /** + * The number of copies of the FAT on the volume. + * The value of this field is always 2. + */ + uint8_t fatCount; + /** + * For FAT12 and FAT16 volumes, this field contains the count of + * 32-byte directory entries in the root directory. For FAT32 volumes, + * this field must be set to 0. For FAT12 and FAT16 volumes, this + * value should always specify a count that when multiplied by 32 + * results in a multiple of bytesPerSector. FAT16 volumes should + * use the value 512. + */ + uint16_t rootDirEntryCount; + /** + * This field is the old 16-bit total count of sectors on the volume. + * This count includes the count of all sectors in all four regions + * of the volume. This field can be 0; if it is 0, then totalSectors32 + * must be nonzero. For FAT32 volumes, this field must be 0. For + * FAT12 and FAT16 volumes, this field contains the sector count, and + * totalSectors32 is 0 if the total sector count fits + * (is less than 0x10000). + */ + uint16_t totalSectors16; + /** + * This dates back to the old MS-DOS 1.x media determination and is + * no longer usually used for anything. 0xF8 is the standard value + * for fixed (nonremovable) media. For removable media, 0xF0 is + * frequently used. Legal values are 0xF0 or 0xF8-0xFF. + */ + uint8_t mediaType; + /** + * Count of sectors occupied by one FAT on FAT12/FAT16 volumes. + * On FAT32 volumes this field must be 0, and sectorsPerFat32 + * contains the FAT size count. + */ + uint16_t sectorsPerFat16; + /** Sectors per track for interrupt 0x13. Not used otherwise. */ + uint16_t sectorsPerTrack; + /** Number of heads for interrupt 0x13. Not used otherwise. */ + uint16_t headCount; + /** + * Count of hidden sectors preceding the partition that contains this + * FAT volume. This field is generally only relevant for media + * visible on interrupt 0x13. + */ + uint32_t hidddenSectors; + /** + * This field is the new 32-bit total count of sectors on the volume. + * This count includes the count of all sectors in all four regions + * of the volume. This field can be 0; if it is 0, then + * totalSectors16 must be nonzero. + */ + uint32_t totalSectors32; + /** + * Related to the BIOS physical drive number. Floppy drives are + * identified as 0x00 and physical hard disks are identified as + * 0x80, regardless of the number of physical disk drives. + * Typically, this value is set prior to issuing an INT 13h BIOS + * call to specify the device to access. The value is only + * relevant if the device is a boot device. + */ + uint8_t driveNumber; + /** used by Windows NT - should be zero for FAT */ + uint8_t reserved1; + /** 0X29 if next three fields are valid */ + uint8_t bootSignature; + /** + * A random serial number created when formatting a disk, + * which helps to distinguish between disks. + * Usually generated by combining date and time. + */ + uint32_t volumeSerialNumber; + /** + * A field once used to store the volume label. The volume label + * is now stored as a special file in the root directory. + */ + char volumeLabel[11]; + /** + * A field with a value of either FAT, FAT12 or FAT16, + * depending on the disk format. + */ + char fileSystemType[8]; + /** X86 boot code */ + uint8_t bootCode[448]; + /** must be 0X55 */ + uint8_t bootSectorSig0; + /** must be 0XAA */ + uint8_t bootSectorSig1; } PACKED; /** Type name for FAT Boot Sector */ typedef struct fat_boot fat_boot_t; @@ -260,149 +260,149 @@ typedef struct fat_boot fat_boot_t; * */ struct fat32_boot { - /** - * The first three bytes of the boot sector must be valid, - * executable x 86-based CPU instructions. This includes a - * jump instruction that skips the next nonexecutable bytes. - */ - uint8_t jump[3]; - /** - * This is typically a string of characters that identifies - * the operating system that formatted the volume. - */ - char oemId[8]; - /** - * The size of a hardware sector. Valid decimal values for this - * field are 512, 1024, 2048, and 4096. For most disks used in - * the United States, the value of this field is 512. - */ - uint16_t bytesPerSector; - /** - * Number of sectors per allocation unit. This value must be a - * power of 2 that is greater than 0. The legal values are - * 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided. - */ - uint8_t sectorsPerCluster; - /** - * The number of sectors preceding the start of the first FAT, - * including the boot sector. Must not be zero - */ - uint16_t reservedSectorCount; - /** - * The number of copies of the FAT on the volume. - * The value of this field is always 2. - */ - uint8_t fatCount; - /** - * FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0. - */ - uint16_t rootDirEntryCount; - /** - * For FAT32 volumes, this field must be 0. - */ - uint16_t totalSectors16; - /** - * This dates back to the old MS-DOS 1.x media determination and is - * no longer usually used for anything. 0xF8 is the standard value - * for fixed (nonremovable) media. For removable media, 0xF0 is - * frequently used. Legal values are 0xF0 or 0xF8-0xFF. - */ - uint8_t mediaType; - /** - * On FAT32 volumes this field must be 0, and sectorsPerFat32 - * contains the FAT size count. - */ - uint16_t sectorsPerFat16; - /** Sectors per track for interrupt 0x13. Not used otherwise. */ - uint16_t sectorsPerTrack; - /** Number of heads for interrupt 0x13. Not used otherwise. */ - uint16_t headCount; - /** - * Count of hidden sectors preceding the partition that contains this - * FAT volume. This field is generally only relevant for media - * visible on interrupt 0x13. - */ - uint32_t hidddenSectors; - /** - * Contains the total number of sectors in the FAT32 volume. - */ - uint32_t totalSectors32; - /** - * Count of sectors occupied by one FAT on FAT32 volumes. - */ - uint32_t sectorsPerFat32; - /** - * This field is only defined for FAT32 media and does not exist on - * FAT12 and FAT16 media. - * Bits 0-3 -- Zero-based number of active FAT. - * Only valid if mirroring is disabled. - * Bits 4-6 -- Reserved. - * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs. - * -- 1 means only one FAT is active; it is the one referenced - * in bits 0-3. - * Bits 8-15 -- Reserved. - */ - uint16_t fat32Flags; - /** - * FAT32 version. High byte is major revision number. - * Low byte is minor revision number. Only 0.0 define. - */ - uint16_t fat32Version; - /** - * Cluster number of the first cluster of the root directory for FAT32. - * This usually 2 but not required to be 2. - */ - uint32_t fat32RootCluster; - /** - * Sector number of FSINFO structure in the reserved area of the - * FAT32 volume. Usually 1. - */ - uint16_t fat32FSInfo; - /** - * If nonzero, indicates the sector number in the reserved area - * of the volume of a copy of the boot record. Usually 6. - * No value other than 6 is recommended. - */ - uint16_t fat32BackBootBlock; - /** - * Reserved for future expansion. Code that formats FAT32 volumes - * should always set all of the bytes of this field to 0. - */ - uint8_t fat32Reserved[12]; - /** - * Related to the BIOS physical drive number. Floppy drives are - * identified as 0x00 and physical hard disks are identified as - * 0x80, regardless of the number of physical disk drives. - * Typically, this value is set prior to issuing an INT 13h BIOS - * call to specify the device to access. The value is only - * relevant if the device is a boot device. - */ - uint8_t driveNumber; - /** used by Windows NT - should be zero for FAT */ - uint8_t reserved1; - /** 0X29 if next three fields are valid */ - uint8_t bootSignature; - /** - * A random serial number created when formatting a disk, - * which helps to distinguish between disks. - * Usually generated by combining date and time. - */ - uint32_t volumeSerialNumber; - /** - * A field once used to store the volume label. The volume label - * is now stored as a special file in the root directory. - */ - char volumeLabel[11]; - /** - * A text field with a value of FAT32. - */ - char fileSystemType[8]; - /** X86 boot code */ - uint8_t bootCode[420]; - /** must be 0X55 */ - uint8_t bootSectorSig0; - /** must be 0XAA */ - uint8_t bootSectorSig1; + /** + * The first three bytes of the boot sector must be valid, + * executable x 86-based CPU instructions. This includes a + * jump instruction that skips the next nonexecutable bytes. + */ + uint8_t jump[3]; + /** + * This is typically a string of characters that identifies + * the operating system that formatted the volume. + */ + char oemId[8]; + /** + * The size of a hardware sector. Valid decimal values for this + * field are 512, 1024, 2048, and 4096. For most disks used in + * the United States, the value of this field is 512. + */ + uint16_t bytesPerSector; + /** + * Number of sectors per allocation unit. This value must be a + * power of 2 that is greater than 0. The legal values are + * 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided. + */ + uint8_t sectorsPerCluster; + /** + * The number of sectors preceding the start of the first FAT, + * including the boot sector. Must not be zero + */ + uint16_t reservedSectorCount; + /** + * The number of copies of the FAT on the volume. + * The value of this field is always 2. + */ + uint8_t fatCount; + /** + * FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0. + */ + uint16_t rootDirEntryCount; + /** + * For FAT32 volumes, this field must be 0. + */ + uint16_t totalSectors16; + /** + * This dates back to the old MS-DOS 1.x media determination and is + * no longer usually used for anything. 0xF8 is the standard value + * for fixed (nonremovable) media. For removable media, 0xF0 is + * frequently used. Legal values are 0xF0 or 0xF8-0xFF. + */ + uint8_t mediaType; + /** + * On FAT32 volumes this field must be 0, and sectorsPerFat32 + * contains the FAT size count. + */ + uint16_t sectorsPerFat16; + /** Sectors per track for interrupt 0x13. Not used otherwise. */ + uint16_t sectorsPerTrack; + /** Number of heads for interrupt 0x13. Not used otherwise. */ + uint16_t headCount; + /** + * Count of hidden sectors preceding the partition that contains this + * FAT volume. This field is generally only relevant for media + * visible on interrupt 0x13. + */ + uint32_t hidddenSectors; + /** + * Contains the total number of sectors in the FAT32 volume. + */ + uint32_t totalSectors32; + /** + * Count of sectors occupied by one FAT on FAT32 volumes. + */ + uint32_t sectorsPerFat32; + /** + * This field is only defined for FAT32 media and does not exist on + * FAT12 and FAT16 media. + * Bits 0-3 -- Zero-based number of active FAT. + * Only valid if mirroring is disabled. + * Bits 4-6 -- Reserved. + * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs. + * -- 1 means only one FAT is active; it is the one referenced + * in bits 0-3. + * Bits 8-15 -- Reserved. + */ + uint16_t fat32Flags; + /** + * FAT32 version. High byte is major revision number. + * Low byte is minor revision number. Only 0.0 define. + */ + uint16_t fat32Version; + /** + * Cluster number of the first cluster of the root directory for FAT32. + * This usually 2 but not required to be 2. + */ + uint32_t fat32RootCluster; + /** + * Sector number of FSINFO structure in the reserved area of the + * FAT32 volume. Usually 1. + */ + uint16_t fat32FSInfo; + /** + * If nonzero, indicates the sector number in the reserved area + * of the volume of a copy of the boot record. Usually 6. + * No value other than 6 is recommended. + */ + uint16_t fat32BackBootBlock; + /** + * Reserved for future expansion. Code that formats FAT32 volumes + * should always set all of the bytes of this field to 0. + */ + uint8_t fat32Reserved[12]; + /** + * Related to the BIOS physical drive number. Floppy drives are + * identified as 0x00 and physical hard disks are identified as + * 0x80, regardless of the number of physical disk drives. + * Typically, this value is set prior to issuing an INT 13h BIOS + * call to specify the device to access. The value is only + * relevant if the device is a boot device. + */ + uint8_t driveNumber; + /** used by Windows NT - should be zero for FAT */ + uint8_t reserved1; + /** 0X29 if next three fields are valid */ + uint8_t bootSignature; + /** + * A random serial number created when formatting a disk, + * which helps to distinguish between disks. + * Usually generated by combining date and time. + */ + uint32_t volumeSerialNumber; + /** + * A field once used to store the volume label. The volume label + * is now stored as a special file in the root directory. + */ + char volumeLabel[11]; + /** + * A text field with a value of FAT32. + */ + char fileSystemType[8]; + /** X86 boot code */ + uint8_t bootCode[420]; + /** must be 0X55 */ + uint8_t bootSectorSig0; + /** must be 0XAA */ + uint8_t bootSectorSig1; } PACKED; /** Type name for FAT32 Boot Sector */ typedef struct fat32_boot fat32_boot_t; @@ -418,31 +418,31 @@ uint32_t const FSINFO_STRUCT_SIG = 0x61417272; * */ struct fat32_fsinfo { - /** must be 0X52, 0X52, 0X61, 0X41 */ - uint32_t leadSignature; - /** must be zero */ - uint8_t reserved1[480]; - /** must be 0X72, 0X72, 0X41, 0X61 */ - uint32_t structSignature; - /** - * Contains the last known free cluster count on the volume. - * If the value is 0xFFFFFFFF, then the free count is unknown - * and must be computed. Any other value can be used, but is - * not necessarily correct. It should be range checked at least - * to make sure it is <= volume cluster count. - */ - uint32_t freeCount; - /** - * This is a hint for the FAT driver. It indicates the cluster - * number at which the driver should start looking for free clusters. - * If the value is 0xFFFFFFFF, then there is no hint and the driver - * should start looking at cluster 2. - */ - uint32_t nextFree; - /** must be zero */ - uint8_t reserved2[12]; - /** must be 0X00, 0X00, 0X55, 0XAA */ - uint8_t tailSignature[4]; + /** must be 0X52, 0X52, 0X61, 0X41 */ + uint32_t leadSignature; + /** must be zero */ + uint8_t reserved1[480]; + /** must be 0X72, 0X72, 0X41, 0X61 */ + uint32_t structSignature; + /** + * Contains the last known free cluster count on the volume. + * If the value is 0xFFFFFFFF, then the free count is unknown + * and must be computed. Any other value can be used, but is + * not necessarily correct. It should be range checked at least + * to make sure it is <= volume cluster count. + */ + uint32_t freeCount; + /** + * This is a hint for the FAT driver. It indicates the cluster + * number at which the driver should start looking for free clusters. + * If the value is 0xFFFFFFFF, then there is no hint and the driver + * should start looking at cluster 2. + */ + uint32_t nextFree; + /** must be zero */ + uint8_t reserved2[12]; + /** must be 0X00, 0X00, 0X55, 0XAA */ + uint8_t tailSignature[4]; } PACKED; /** Type name for FAT32 FSINFO Sector */ typedef struct fat32_fsinfo fat32_fsinfo_t; @@ -468,79 +468,79 @@ uint32_t const FAT32MASK = 0X0FFFFFFF; * \brief FAT short directory entry * * Short means short 8.3 name, not the entry size. - * - * Date Format. A FAT directory entry date stamp is a 16-bit field that is + * + * Date Format. A FAT directory entry date stamp is a 16-bit field that is * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the - * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the + * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the * 16-bit word): - * - * Bits 9-15: Count of years from 1980, valid value range 0-127 + * + * Bits 9-15: Count of years from 1980, valid value range 0-127 * inclusive (1980-2107). - * + * * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive. * * Bits 0-4: Day of month, valid value range 1-31 inclusive. * * Time Format. A FAT directory entry time stamp is a 16-bit field that has - * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the + * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the * 16-bit word, bit 15 is the MSB of the 16-bit word). - * + * * Bits 11-15: Hours, valid value range 0-23 inclusive. - * + * * Bits 5-10: Minutes, valid value range 0-59 inclusive. - * + * * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds). - * + * * The valid time range is from Midnight 00:00:00 to 23:59:58. */ struct directoryEntry { - /** Short 8.3 name. - * - * The first eight bytes contain the file name with blank fill. - * The last three bytes contain the file extension with blank fill. - */ - uint8_t name[11]; - /** Entry attributes. - * - * The upper two bits of the attribute byte are reserved and should - * always be set to 0 when a file is created and never modified or - * looked at after that. See defines that begin with DIR_ATT_. - */ - uint8_t attributes; - /** - * Reserved for use by Windows NT. Set value to 0 when a file is - * created and never modify or look at it after that. - */ - uint8_t reservedNT; - /** - * The granularity of the seconds part of creationTime is 2 seconds - * so this field is a count of tenths of a second and its valid - * value range is 0-199 inclusive. (WHG note - seems to be hundredths) - */ - uint8_t creationTimeTenths; - /** Time file was created. */ - uint16_t creationTime; - /** Date file was created. */ - uint16_t creationDate; - /** - * Last access date. Note that there is no last access time, only - * a date. This is the date of last read or write. In the case of - * a write, this should be set to the same date as lastWriteDate. - */ - uint16_t lastAccessDate; - /** - * High word of this entry's first cluster number (always 0 for a - * FAT12 or FAT16 volume). - */ - uint16_t firstClusterHigh; - /** Time of last write. File creation is considered a write. */ - uint16_t lastWriteTime; - /** Date of last write. File creation is considered a write. */ - uint16_t lastWriteDate; - /** Low word of this entry's first cluster number. */ - uint16_t firstClusterLow; - /** 32-bit unsigned holding this file's size in bytes. */ - uint32_t fileSize; + /** Short 8.3 name. + * + * The first eight bytes contain the file name with blank fill. + * The last three bytes contain the file extension with blank fill. + */ + uint8_t name[11]; + /** Entry attributes. + * + * The upper two bits of the attribute byte are reserved and should + * always be set to 0 when a file is created and never modified or + * looked at after that. See defines that begin with DIR_ATT_. + */ + uint8_t attributes; + /** + * Reserved for use by Windows NT. Set value to 0 when a file is + * created and never modify or look at it after that. + */ + uint8_t reservedNT; + /** + * The granularity of the seconds part of creationTime is 2 seconds + * so this field is a count of tenths of a second and its valid + * value range is 0-199 inclusive. (WHG note - seems to be hundredths) + */ + uint8_t creationTimeTenths; + /** Time file was created. */ + uint16_t creationTime; + /** Date file was created. */ + uint16_t creationDate; + /** + * Last access date. Note that there is no last access time, only + * a date. This is the date of last read or write. In the case of + * a write, this should be set to the same date as lastWriteDate. + */ + uint16_t lastAccessDate; + /** + * High word of this entry's first cluster number (always 0 for a + * FAT12 or FAT16 volume). + */ + uint16_t firstClusterHigh; + /** Time of last write. File creation is considered a write. */ + uint16_t lastWriteTime; + /** Date of last write. File creation is considered a write. */ + uint16_t lastWriteDate; + /** Low word of this entry's first cluster number. */ + uint16_t firstClusterLow; + /** 32-bit unsigned holding this file's size in bytes. */ + uint32_t fileSize; } PACKED; /** * \struct directoryVFATEntry @@ -548,31 +548,31 @@ struct directoryEntry { * * directoryVFATEntries are found in the same list as normal directoryEntry. * But have the attribute field set to DIR_ATT_LONG_NAME. - * + * * Long filenames are saved in multiple directoryVFATEntries. * Each entry containing 13 UTF-16 characters. */ struct directoryVFATEntry { - /** - * Sequence number. Consists of 2 parts: - * bit 6: indicates first long filename block for the next file - * bit 0-4: the position of this long filename block (first block is 1) - */ - uint8_t sequenceNumber; - /** First set of UTF-16 characters */ - uint16_t name1[5];//UTF-16 - /** attributes (at the same location as in directoryEntry), always 0x0F */ - uint8_t attributes; - /** Reserved for use by Windows NT. Always 0. */ - uint8_t reservedNT; - /** Checksum of the short 8.3 filename, can be used to checked if the file system as modified by a not-long-filename aware implementation. */ - uint8_t checksum; - /** Second set of UTF-16 characters */ - uint16_t name2[6];//UTF-16 - /** firstClusterLow is always zero for longFilenames */ - uint16_t firstClusterLow; - /** Third set of UTF-16 characters */ - uint16_t name3[2];//UTF-16 + /** + * Sequence number. Consists of 2 parts: + * bit 6: indicates first long filename block for the next file + * bit 0-4: the position of this long filename block (first block is 1) + */ + uint8_t sequenceNumber; + /** First set of UTF-16 characters */ + uint16_t name1[5];//UTF-16 + /** attributes (at the same location as in directoryEntry), always 0x0F */ + uint8_t attributes; + /** Reserved for use by Windows NT. Always 0. */ + uint8_t reservedNT; + /** Checksum of the short 8.3 filename, can be used to checked if the file system as modified by a not-long-filename aware implementation. */ + uint8_t checksum; + /** Second set of UTF-16 characters */ + uint16_t name2[6];//UTF-16 + /** firstClusterLow is always zero for longFilenames */ + uint16_t firstClusterLow; + /** Third set of UTF-16 characters */ + uint16_t name3[2];//UTF-16 } PACKED; //------------------------------------------------------------------------------ // Definitions for directory entries @@ -612,7 +612,7 @@ uint8_t const DIR_ATT_DEFINED_BITS = 0X3F; * \return true if the entry is for part of a long name else false. */ static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) { - return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME; + return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME; } /** Mask for file/subdirectory tests */ uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY); @@ -622,7 +622,7 @@ uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY); * \return true if the entry is for a normal file else false. */ static inline uint8_t DIR_IS_FILE(const dir_t* dir) { - return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0; + return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0; } /** Directory entry is for a subdirectory * \param[in] dir Pointer to a directory entry. @@ -630,7 +630,7 @@ static inline uint8_t DIR_IS_FILE(const dir_t* dir) { * \return true if the entry is for a subdirectory else false. */ static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) { - return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY; + return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY; } /** Directory entry is for a file or subdirectory * \param[in] dir Pointer to a directory entry. @@ -638,7 +638,7 @@ static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) { * \return true if the entry is for a normal file or subdirectory else false. */ static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) { - return (dir->attributes & DIR_ATT_VOLUME_ID) == 0; + return (dir->attributes & DIR_ATT_VOLUME_ID) == 0; } #endif // SdFatStructs_h diff --git a/Firmware/SdFatUtil.cpp b/Firmware/SdFatUtil.cpp index 51da4ee2bf..f007e64862 100755 --- a/Firmware/SdFatUtil.cpp +++ b/Firmware/SdFatUtil.cpp @@ -29,8 +29,8 @@ #ifdef __arm__ extern "C" char* sbrk(int incr); int SdFatUtil::FreeRam() { - char top; - return &top - reinterpret_cast(sbrk(0)); + char top; + return &top - reinterpret_cast(sbrk(0)); } #else // __arm__ extern char *__brkval; @@ -39,32 +39,32 @@ extern char __bss_end; * \return The number of free bytes. */ int SdFatUtil::FreeRam() { - char top; - return __brkval ? &top - __brkval : &top - &__bss_end; + char top; + return __brkval ? &top - __brkval : &top - &__bss_end; } #endif // __arm void SdFatUtil::set_stack_guard() -{ - uint32_t *stack_guard; +{ + uint32_t *stack_guard; - stack_guard = (uint32_t*)&__bss_end; + stack_guard = (uint32_t*)&__bss_end; *stack_guard = STACK_GUARD_TEST_VALUE; } bool SdFatUtil::test_stack_integrity() { - uint32_t* stack_guard = (uint32_t*)&__bss_end; - return (*stack_guard == STACK_GUARD_TEST_VALUE); + uint32_t* stack_guard = (uint32_t*)&__bss_end; + return (*stack_guard == STACK_GUARD_TEST_VALUE); } uint32_t SdFatUtil::get_stack_guard_test_value() { - uint32_t* stack_guard; - uint32_t output; - stack_guard = (uint32_t*)&__bss_end; - output = *stack_guard; - return(output); + uint32_t* stack_guard; + uint32_t output; + stack_guard = (uint32_t*)&__bss_end; + output = *stack_guard; + return(output); } //------------------------------------------------------------------------------ /** %Print a string in flash memory. @@ -73,7 +73,7 @@ uint32_t SdFatUtil::get_stack_guard_test_value() * \param[in] str Pointer to string stored in flash memory. */ void SdFatUtil::print_P( PGM_P str) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) MYSERIAL.write(c); + for (uint8_t c; (c = pgm_read_byte(str)); str++) MYSERIAL.write(c); } //------------------------------------------------------------------------------ /** %Print a string in flash memory followed by a CR/LF. @@ -82,8 +82,8 @@ void SdFatUtil::print_P( PGM_P str) { * \param[in] str Pointer to string stored in flash memory. */ void SdFatUtil::println_P( PGM_P str) { - print_P( str); - MYSERIAL.println(); + print_P( str); + MYSERIAL.println(); } //------------------------------------------------------------------------------ /** %Print a string in flash memory to Serial. @@ -91,7 +91,7 @@ void SdFatUtil::println_P( PGM_P str) { * \param[in] str Pointer to string stored in flash memory. */ void SdFatUtil::SerialPrint_P(PGM_P str) { - print_P(str); + print_P(str); } //------------------------------------------------------------------------------ /** %Print a string in flash memory to Serial followed by a CR/LF. @@ -99,6 +99,6 @@ void SdFatUtil::SerialPrint_P(PGM_P str) { * \param[in] str Pointer to string stored in flash memory. */ void SdFatUtil::SerialPrintln_P(PGM_P str) { - println_P( str); + println_P( str); } #endif diff --git a/Firmware/SdFatUtil.h b/Firmware/SdFatUtil.h index c42b74b1cc..83b61cba15 100755 --- a/Firmware/SdFatUtil.h +++ b/Firmware/SdFatUtil.h @@ -34,14 +34,14 @@ #define PgmPrintln(x) SerialPrintln_P(PSTR(x)) namespace SdFatUtil { - int FreeRam(); - void print_P( PGM_P str); - void println_P( PGM_P str); - void SerialPrint_P(PGM_P str); - void SerialPrintln_P(PGM_P str); - void set_stack_guard(); - bool test_stack_integrity(); - uint32_t get_stack_guard_test_value(); +int FreeRam(); +void print_P( PGM_P str); +void println_P( PGM_P str); +void SerialPrint_P(PGM_P str); +void SerialPrintln_P(PGM_P str); +void set_stack_guard(); +bool test_stack_integrity(); +uint32_t get_stack_guard_test_value(); } using namespace SdFatUtil; // NOLINT diff --git a/Firmware/SdFile.cpp b/Firmware/SdFile.cpp index 2fb4d59438..b312cb7383 100755 --- a/Firmware/SdFile.cpp +++ b/Firmware/SdFile.cpp @@ -47,7 +47,7 @@ SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) { * */ int16_t SdFile::write(const void* buf, uint16_t nbyte) { - return SdBaseFile::write(buf, nbyte); + return SdBaseFile::write(buf, nbyte); } //------------------------------------------------------------------------------ /** Write a byte to a file. Required by the Arduino Print class. @@ -71,7 +71,7 @@ void SdFile::write(uint8_t b) * Use writeError to check for errors. */ void SdFile::write(const char* str) { - SdBaseFile::write(str, strlen(str)); + SdBaseFile::write(str, strlen(str)); } //------------------------------------------------------------------------------ /** Write a PROGMEM string to a file. @@ -79,7 +79,7 @@ void SdFile::write(const char* str) { * Use writeError to check for errors. */ void SdFile::write_P(PGM_P str) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); + for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); } //------------------------------------------------------------------------------ /** Write a PROGMEM string followed by CR/LF to a file. @@ -87,8 +87,8 @@ void SdFile::write_P(PGM_P str) { * Use writeError to check for errors. */ void SdFile::writeln_P(PGM_P str) { - write_P(str); - write_P(PSTR("\r\n")); + write_P(str); + write_P(PSTR("\r\n")); } diff --git a/Firmware/SdFile.h b/Firmware/SdFile.h index 60e2f5debc..ff855dcdf9 100755 --- a/Firmware/SdFile.h +++ b/Firmware/SdFile.h @@ -33,20 +33,20 @@ * \class SdFile * \brief SdBaseFile with Print. */ -class SdFile : public SdBaseFile/*, public Print*/ { - public: - SdFile() {} - SdFile(const char* name, uint8_t oflag); - #if ARDUINO >= 100 - size_t write(uint8_t b); - #else - void write(uint8_t b); - #endif - - int16_t write(const void* buf, uint16_t nbyte); - void write(const char* str); - void write_P(PGM_P str); - void writeln_P(PGM_P str); +class SdFile : public SdBaseFile { /*, public Print*/ +public: + SdFile() {} + SdFile(const char* name, uint8_t oflag); +#if ARDUINO >= 100 + size_t write(uint8_t b); +#else + void write(uint8_t b); +#endif + + int16_t write(const void* buf, uint16_t nbyte); + void write(const char* str); + void write_P(PGM_P str); + void writeln_P(PGM_P str); }; #endif // SdFile_h diff --git a/Firmware/SdInfo.h b/Firmware/SdInfo.h index 93f0943141..368d2e8b04 100755 --- a/Firmware/SdInfo.h +++ b/Firmware/SdInfo.h @@ -98,188 +98,188 @@ uint8_t const DATA_RES_ACCEPTED = 0X05; //------------------------------------------------------------------------------ /** Card IDentification (CID) register */ typedef struct CID { - // byte 0 - /** Manufacturer ID */ - unsigned char mid; - // byte 1-2 - /** OEM/Application ID */ - char oid[2]; - // byte 3-7 - /** Product name */ - char pnm[5]; - // byte 8 - /** Product revision least significant digit */ - unsigned char prv_m : 4; - /** Product revision most significant digit */ - unsigned char prv_n : 4; - // byte 9-12 - /** Product serial number */ - uint32_t psn; - // byte 13 - /** Manufacturing date year low digit */ - unsigned char mdt_year_high : 4; - /** not used */ - unsigned char reserved : 4; - // byte 14 - /** Manufacturing date month */ - unsigned char mdt_month : 4; - /** Manufacturing date year low digit */ - unsigned char mdt_year_low :4; - // byte 15 - /** not used always 1 */ - unsigned char always1 : 1; - /** CRC7 checksum */ - unsigned char crc : 7; -}cid_t; + // byte 0 + /** Manufacturer ID */ + unsigned char mid; + // byte 1-2 + /** OEM/Application ID */ + char oid[2]; + // byte 3-7 + /** Product name */ + char pnm[5]; + // byte 8 + /** Product revision least significant digit */ + unsigned char prv_m : 4; + /** Product revision most significant digit */ + unsigned char prv_n : 4; + // byte 9-12 + /** Product serial number */ + uint32_t psn; + // byte 13 + /** Manufacturing date year low digit */ + unsigned char mdt_year_high : 4; + /** not used */ + unsigned char reserved : 4; + // byte 14 + /** Manufacturing date month */ + unsigned char mdt_month : 4; + /** Manufacturing date year low digit */ + unsigned char mdt_year_low :4; + // byte 15 + /** not used always 1 */ + unsigned char always1 : 1; + /** CRC7 checksum */ + unsigned char crc : 7; +} cid_t; //------------------------------------------------------------------------------ /** CSD for version 1.00 cards */ typedef struct CSDV1 { - // byte 0 - unsigned char reserved1 : 6; - unsigned char csd_ver : 2; - // byte 1 - unsigned char taac; - // byte 2 - unsigned char nsac; - // byte 3 - unsigned char tran_speed; - // byte 4 - unsigned char ccc_high; - // byte 5 - unsigned char read_bl_len : 4; - unsigned char ccc_low : 4; - // byte 6 - unsigned char c_size_high : 2; - unsigned char reserved2 : 2; - unsigned char dsr_imp : 1; - unsigned char read_blk_misalign :1; - unsigned char write_blk_misalign : 1; - unsigned char read_bl_partial : 1; - // byte 7 - unsigned char c_size_mid; - // byte 8 - unsigned char vdd_r_curr_max : 3; - unsigned char vdd_r_curr_min : 3; - unsigned char c_size_low :2; - // byte 9 - unsigned char c_size_mult_high : 2; - unsigned char vdd_w_cur_max : 3; - unsigned char vdd_w_curr_min : 3; - // byte 10 - unsigned char sector_size_high : 6; - unsigned char erase_blk_en : 1; - unsigned char c_size_mult_low : 1; - // byte 11 - unsigned char wp_grp_size : 7; - unsigned char sector_size_low : 1; - // byte 12 - unsigned char write_bl_len_high : 2; - unsigned char r2w_factor : 3; - unsigned char reserved3 : 2; - unsigned char wp_grp_enable : 1; - // byte 13 - unsigned char reserved4 : 5; - unsigned char write_partial : 1; - unsigned char write_bl_len_low : 2; - // byte 14 - unsigned char reserved5: 2; - unsigned char file_format : 2; - unsigned char tmp_write_protect : 1; - unsigned char perm_write_protect : 1; - unsigned char copy : 1; - /** Indicates the file format on the card */ - unsigned char file_format_grp : 1; - // byte 15 - unsigned char always1 : 1; - unsigned char crc : 7; -}csd1_t; + // byte 0 + unsigned char reserved1 : 6; + unsigned char csd_ver : 2; + // byte 1 + unsigned char taac; + // byte 2 + unsigned char nsac; + // byte 3 + unsigned char tran_speed; + // byte 4 + unsigned char ccc_high; + // byte 5 + unsigned char read_bl_len : 4; + unsigned char ccc_low : 4; + // byte 6 + unsigned char c_size_high : 2; + unsigned char reserved2 : 2; + unsigned char dsr_imp : 1; + unsigned char read_blk_misalign :1; + unsigned char write_blk_misalign : 1; + unsigned char read_bl_partial : 1; + // byte 7 + unsigned char c_size_mid; + // byte 8 + unsigned char vdd_r_curr_max : 3; + unsigned char vdd_r_curr_min : 3; + unsigned char c_size_low :2; + // byte 9 + unsigned char c_size_mult_high : 2; + unsigned char vdd_w_cur_max : 3; + unsigned char vdd_w_curr_min : 3; + // byte 10 + unsigned char sector_size_high : 6; + unsigned char erase_blk_en : 1; + unsigned char c_size_mult_low : 1; + // byte 11 + unsigned char wp_grp_size : 7; + unsigned char sector_size_low : 1; + // byte 12 + unsigned char write_bl_len_high : 2; + unsigned char r2w_factor : 3; + unsigned char reserved3 : 2; + unsigned char wp_grp_enable : 1; + // byte 13 + unsigned char reserved4 : 5; + unsigned char write_partial : 1; + unsigned char write_bl_len_low : 2; + // byte 14 + unsigned char reserved5: 2; + unsigned char file_format : 2; + unsigned char tmp_write_protect : 1; + unsigned char perm_write_protect : 1; + unsigned char copy : 1; + /** Indicates the file format on the card */ + unsigned char file_format_grp : 1; + // byte 15 + unsigned char always1 : 1; + unsigned char crc : 7; +} csd1_t; //------------------------------------------------------------------------------ /** CSD for version 2.00 cards */ typedef struct CSDV2 { - // byte 0 - unsigned char reserved1 : 6; - unsigned char csd_ver : 2; - // byte 1 - /** fixed to 0X0E */ - unsigned char taac; - // byte 2 - /** fixed to 0 */ - unsigned char nsac; - // byte 3 - unsigned char tran_speed; - // byte 4 - unsigned char ccc_high; - // byte 5 - /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */ - unsigned char read_bl_len : 4; - unsigned char ccc_low : 4; - // byte 6 - /** not used */ - unsigned char reserved2 : 4; - unsigned char dsr_imp : 1; - /** fixed to 0 */ - unsigned char read_blk_misalign :1; - /** fixed to 0 */ - unsigned char write_blk_misalign : 1; - /** fixed to 0 - no partial read */ - unsigned char read_bl_partial : 1; - // byte 7 - /** not used */ - unsigned char reserved3 : 2; - /** high part of card size */ - unsigned char c_size_high : 6; - // byte 8 - /** middle part of card size */ - unsigned char c_size_mid; - // byte 9 - /** low part of card size */ - unsigned char c_size_low; - // byte 10 - /** sector size is fixed at 64 KB */ - unsigned char sector_size_high : 6; - /** fixed to 1 - erase single is supported */ - unsigned char erase_blk_en : 1; - /** not used */ - unsigned char reserved4 : 1; - // byte 11 - unsigned char wp_grp_size : 7; - /** sector size is fixed at 64 KB */ - unsigned char sector_size_low : 1; - // byte 12 - /** write_bl_len fixed for 512 byte blocks */ - unsigned char write_bl_len_high : 2; - /** fixed value of 2 */ - unsigned char r2w_factor : 3; - /** not used */ - unsigned char reserved5 : 2; - /** fixed value of 0 - no write protect groups */ - unsigned char wp_grp_enable : 1; - // byte 13 - unsigned char reserved6 : 5; - /** always zero - no partial block read*/ - unsigned char write_partial : 1; - /** write_bl_len fixed for 512 byte blocks */ - unsigned char write_bl_len_low : 2; - // byte 14 - unsigned char reserved7: 2; - /** Do not use always 0 */ - unsigned char file_format : 2; - unsigned char tmp_write_protect : 1; - unsigned char perm_write_protect : 1; - unsigned char copy : 1; - /** Do not use always 0 */ - unsigned char file_format_grp : 1; - // byte 15 - /** not used always 1 */ - unsigned char always1 : 1; - /** checksum */ - unsigned char crc : 7; -}csd2_t; + // byte 0 + unsigned char reserved1 : 6; + unsigned char csd_ver : 2; + // byte 1 + /** fixed to 0X0E */ + unsigned char taac; + // byte 2 + /** fixed to 0 */ + unsigned char nsac; + // byte 3 + unsigned char tran_speed; + // byte 4 + unsigned char ccc_high; + // byte 5 + /** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */ + unsigned char read_bl_len : 4; + unsigned char ccc_low : 4; + // byte 6 + /** not used */ + unsigned char reserved2 : 4; + unsigned char dsr_imp : 1; + /** fixed to 0 */ + unsigned char read_blk_misalign :1; + /** fixed to 0 */ + unsigned char write_blk_misalign : 1; + /** fixed to 0 - no partial read */ + unsigned char read_bl_partial : 1; + // byte 7 + /** not used */ + unsigned char reserved3 : 2; + /** high part of card size */ + unsigned char c_size_high : 6; + // byte 8 + /** middle part of card size */ + unsigned char c_size_mid; + // byte 9 + /** low part of card size */ + unsigned char c_size_low; + // byte 10 + /** sector size is fixed at 64 KB */ + unsigned char sector_size_high : 6; + /** fixed to 1 - erase single is supported */ + unsigned char erase_blk_en : 1; + /** not used */ + unsigned char reserved4 : 1; + // byte 11 + unsigned char wp_grp_size : 7; + /** sector size is fixed at 64 KB */ + unsigned char sector_size_low : 1; + // byte 12 + /** write_bl_len fixed for 512 byte blocks */ + unsigned char write_bl_len_high : 2; + /** fixed value of 2 */ + unsigned char r2w_factor : 3; + /** not used */ + unsigned char reserved5 : 2; + /** fixed value of 0 - no write protect groups */ + unsigned char wp_grp_enable : 1; + // byte 13 + unsigned char reserved6 : 5; + /** always zero - no partial block read*/ + unsigned char write_partial : 1; + /** write_bl_len fixed for 512 byte blocks */ + unsigned char write_bl_len_low : 2; + // byte 14 + unsigned char reserved7: 2; + /** Do not use always 0 */ + unsigned char file_format : 2; + unsigned char tmp_write_protect : 1; + unsigned char perm_write_protect : 1; + unsigned char copy : 1; + /** Do not use always 0 */ + unsigned char file_format_grp : 1; + // byte 15 + /** not used always 1 */ + unsigned char always1 : 1; + /** checksum */ + unsigned char crc : 7; +} csd2_t; //------------------------------------------------------------------------------ /** union of old and new style CSD register */ union csd_t { - csd1_t v1; - csd2_t v2; + csd1_t v1; + csd2_t v2; }; #endif // SdInfo_h diff --git a/Firmware/SdVolume.cpp b/Firmware/SdVolume.cpp index 9d6abf3004..c45faf95d2 100755 --- a/Firmware/SdVolume.cpp +++ b/Firmware/SdVolume.cpp @@ -33,244 +33,244 @@ uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT //------------------------------------------------------------------------------ // find a contiguous group of clusters bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { - // start of group - uint32_t bgnCluster; - // end of group - uint32_t endCluster; - // last cluster of FAT - uint32_t fatEnd = clusterCount_ + 1; - - // flag to save place to start next search - bool setStart; - - // set search start cluster - if (*curCluster) { - // try to make file contiguous - bgnCluster = *curCluster + 1; - - // don't save new start location - setStart = false; - } else { - // start at likely place for free cluster - bgnCluster = allocSearchStart_; - - // save next search start if one cluster - setStart = count == 1; - } - // end of group - endCluster = bgnCluster; - - // search the FAT for free clusters - for (uint32_t n = 0;; n++, endCluster++) { - // can't find space checked all clusters - if (n >= clusterCount_) goto fail; - - // past end - start from beginning of FAT - if (endCluster > fatEnd) { - bgnCluster = endCluster = 2; + // start of group + uint32_t bgnCluster; + // end of group + uint32_t endCluster; + // last cluster of FAT + uint32_t fatEnd = clusterCount_ + 1; + + // flag to save place to start next search + bool setStart; + + // set search start cluster + if (*curCluster) { + // try to make file contiguous + bgnCluster = *curCluster + 1; + + // don't save new start location + setStart = false; + } else { + // start at likely place for free cluster + bgnCluster = allocSearchStart_; + + // save next search start if one cluster + setStart = count == 1; } - uint32_t f; - if (!fatGet(endCluster, &f)) goto fail; - - if (f != 0) { - // cluster in use try next cluster as bgnCluster - bgnCluster = endCluster + 1; - } else if ((endCluster - bgnCluster + 1) == count) { - // done - found space - break; + // end of group + endCluster = bgnCluster; + + // search the FAT for free clusters + for (uint32_t n = 0;; n++, endCluster++) { + // can't find space checked all clusters + if (n >= clusterCount_) goto fail; + + // past end - start from beginning of FAT + if (endCluster > fatEnd) { + bgnCluster = endCluster = 2; + } + uint32_t f; + if (!fatGet(endCluster, &f)) goto fail; + + if (f != 0) { + // cluster in use try next cluster as bgnCluster + bgnCluster = endCluster + 1; + } else if ((endCluster - bgnCluster + 1) == count) { + // done - found space + break; + } + } + // mark end of chain + if (!fatPutEOC(endCluster)) goto fail; + + // link clusters + while (endCluster > bgnCluster) { + if (!fatPut(endCluster - 1, endCluster)) goto fail; + endCluster--; } - } - // mark end of chain - if (!fatPutEOC(endCluster)) goto fail; - - // link clusters - while (endCluster > bgnCluster) { - if (!fatPut(endCluster - 1, endCluster)) goto fail; - endCluster--; - } - if (*curCluster != 0) { - // connect chains - if (!fatPut(*curCluster, bgnCluster)) goto fail; - } - // return first cluster number to caller - *curCluster = bgnCluster; - - // remember possible next free cluster - if (setStart) allocSearchStart_ = bgnCluster + 1; - - return true; - - fail: - return false; + if (*curCluster != 0) { + // connect chains + if (!fatPut(*curCluster, bgnCluster)) goto fail; + } + // return first cluster number to caller + *curCluster = bgnCluster; + + // remember possible next free cluster + if (setStart) allocSearchStart_ = bgnCluster + 1; + + return true; + +fail: + return false; } //------------------------------------------------------------------------------ bool SdVolume::cacheFlush() { - if (cacheDirty_) { - if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { - goto fail; - } - // mirror FAT tables - if (cacheMirrorBlock_) { - if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { - goto fail; - } - cacheMirrorBlock_ = 0; + if (cacheDirty_) { + if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { + goto fail; + } + // mirror FAT tables + if (cacheMirrorBlock_) { + if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { + goto fail; + } + cacheMirrorBlock_ = 0; + } + cacheDirty_ = 0; } - cacheDirty_ = 0; - } - return true; + return true; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) { - if (cacheBlockNumber_ != blockNumber) { - if (!cacheFlush()) goto fail; - if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail; - cacheBlockNumber_ = blockNumber; - } - if (dirty) cacheDirty_ = true; - return true; - - fail: - return false; + if (cacheBlockNumber_ != blockNumber) { + if (!cacheFlush()) goto fail; + if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail; + cacheBlockNumber_ = blockNumber; + } + if (dirty) cacheDirty_ = true; + return true; + +fail: + return false; } //------------------------------------------------------------------------------ // return the size in bytes of a cluster chain bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) { - uint32_t s = 0; - do { - if (!fatGet(cluster, &cluster)) goto fail; - s += 512UL << clusterSizeShift_; - } while (!isEOC(cluster)); - *size = s; - return true; - - fail: - return false; + uint32_t s = 0; + do { + if (!fatGet(cluster, &cluster)) goto fail; + s += 512UL << clusterSizeShift_; + } while (!isEOC(cluster)); + *size = s; + return true; + +fail: + return false; } //------------------------------------------------------------------------------ // Fetch a FAT entry bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) { - uint32_t lba; - if (cluster > (clusterCount_ + 1)) goto fail; - if (FAT12_SUPPORT && fatType_ == 12) { - uint16_t index = cluster; - index += index >> 1; - lba = fatStartBlock_ + (index >> 9); - if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; - index &= 0X1FF; - uint16_t tmp = cacheBuffer_.data[index]; - index++; - if (index == 512) { - if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail; - index = 0; + uint32_t lba; + if (cluster > (clusterCount_ + 1)) goto fail; + if (FAT12_SUPPORT && fatType_ == 12) { + uint16_t index = cluster; + index += index >> 1; + lba = fatStartBlock_ + (index >> 9); + if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; + index &= 0X1FF; + uint16_t tmp = cacheBuffer_.data[index]; + index++; + if (index == 512) { + if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail; + index = 0; + } + tmp |= cacheBuffer_.data[index] << 8; + *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF; + return true; + } + if (fatType_ == 16) { + lba = fatStartBlock_ + (cluster >> 8); + } else if (fatType_ == 32) { + lba = fatStartBlock_ + (cluster >> 7); + } else { + goto fail; + } + if (lba != cacheBlockNumber_) { + if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; + } + if (fatType_ == 16) { + *value = cacheBuffer_.fat16[cluster & 0XFF]; + } else { + *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; } - tmp |= cacheBuffer_.data[index] << 8; - *value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF; return true; - } - if (fatType_ == 16) { - lba = fatStartBlock_ + (cluster >> 8); - } else if (fatType_ == 32) { - lba = fatStartBlock_ + (cluster >> 7); - } else { - goto fail; - } - if (lba != cacheBlockNumber_) { - if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail; - } - if (fatType_ == 16) { - *value = cacheBuffer_.fat16[cluster & 0XFF]; - } else { - *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; - } - return true; - - fail: - return false; + +fail: + return false; } //------------------------------------------------------------------------------ // Store a FAT entry bool SdVolume::fatPut(uint32_t cluster, uint32_t value) { - uint32_t lba; - // error if reserved cluster - if (cluster < 2) goto fail; - - // error if not in FAT - if (cluster > (clusterCount_ + 1)) goto fail; - - if (FAT12_SUPPORT && fatType_ == 12) { - uint16_t index = cluster; - index += index >> 1; - lba = fatStartBlock_ + (index >> 9); - if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; - // mirror second FAT - if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; - index &= 0X1FF; - uint8_t tmp = value; - if (cluster & 1) { - tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4; + uint32_t lba; + // error if reserved cluster + if (cluster < 2) goto fail; + + // error if not in FAT + if (cluster > (clusterCount_ + 1)) goto fail; + + if (FAT12_SUPPORT && fatType_ == 12) { + uint16_t index = cluster; + index += index >> 1; + lba = fatStartBlock_ + (index >> 9); + if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; + // mirror second FAT + if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; + index &= 0X1FF; + uint8_t tmp = value; + if (cluster & 1) { + tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4; + } + cacheBuffer_.data[index] = tmp; + index++; + if (index == 512) { + lba++; + index = 0; + if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; + // mirror second FAT + if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; + } + tmp = value >> 4; + if (!(cluster & 1)) { + tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4; + } + cacheBuffer_.data[index] = tmp; + return true; } - cacheBuffer_.data[index] = tmp; - index++; - if (index == 512) { - lba++; - index = 0; - if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; - // mirror second FAT - if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; + if (fatType_ == 16) { + lba = fatStartBlock_ + (cluster >> 8); + } else if (fatType_ == 32) { + lba = fatStartBlock_ + (cluster >> 7); + } else { + goto fail; } - tmp = value >> 4; - if (!(cluster & 1)) { - tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4; + if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; + // store entry + if (fatType_ == 16) { + cacheBuffer_.fat16[cluster & 0XFF] = value; + } else { + cacheBuffer_.fat32[cluster & 0X7F] = value; } - cacheBuffer_.data[index] = tmp; + // mirror second FAT + if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; return true; - } - if (fatType_ == 16) { - lba = fatStartBlock_ + (cluster >> 8); - } else if (fatType_ == 32) { - lba = fatStartBlock_ + (cluster >> 7); - } else { - goto fail; - } - if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail; - // store entry - if (fatType_ == 16) { - cacheBuffer_.fat16[cluster & 0XFF] = value; - } else { - cacheBuffer_.fat32[cluster & 0X7F] = value; - } - // mirror second FAT - if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; - return true; - - fail: - return false; + +fail: + return false; } //------------------------------------------------------------------------------ // free a cluster chain bool SdVolume::freeChain(uint32_t cluster) { - uint32_t next; + uint32_t next; - // clear free cluster location - allocSearchStart_ = 2; + // clear free cluster location + allocSearchStart_ = 2; - do { - if (!fatGet(cluster, &next)) goto fail; + do { + if (!fatGet(cluster, &next)) goto fail; - // free cluster - if (!fatPut(cluster, 0)) goto fail; + // free cluster + if (!fatPut(cluster, 0)) goto fail; - cluster = next; - } while (!isEOC(cluster)); + cluster = next; + } while (!isEOC(cluster)); - return true; + return true; - fail: - return false; +fail: + return false; } //------------------------------------------------------------------------------ /** Volume free space in clusters. @@ -278,33 +278,33 @@ bool SdVolume::freeChain(uint32_t cluster) { * \return Count of free clusters for success or -1 if an error occurs. */ int32_t SdVolume::freeClusterCount() { - uint32_t free = 0; - uint16_t n; - uint32_t todo = clusterCount_ + 2; - - if (fatType_ == 16) { - n = 256; - } else if (fatType_ == 32) { - n = 128; - } else { - // put FAT12 here - return -1; - } - - for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) { - if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1; - if (todo < n) n = todo; + uint32_t free = 0; + uint16_t n; + uint32_t todo = clusterCount_ + 2; + if (fatType_ == 16) { - for (uint16_t i = 0; i < n; i++) { - if (cacheBuffer_.fat16[i] == 0) free++; - } + n = 256; + } else if (fatType_ == 32) { + n = 128; } else { - for (uint16_t i = 0; i < n; i++) { - if (cacheBuffer_.fat32[i] == 0) free++; - } + // put FAT12 here + return -1; + } + + for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) { + if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1; + if (todo < n) n = todo; + if (fatType_ == 16) { + for (uint16_t i = 0; i < n; i++) { + if (cacheBuffer_.fat16[i] == 0) free++; + } + } else { + for (uint16_t i = 0; i < n; i++) { + if (cacheBuffer_.fat32[i] == 0) free++; + } + } } - } - return free; + return free; } //------------------------------------------------------------------------------ /** Initialize a FAT volume. @@ -322,84 +322,84 @@ int32_t SdVolume::freeClusterCount() { * FAT file system in the specified partition or an I/O error. */ bool SdVolume::init(Sd2Card* dev, uint8_t part) { - uint32_t totalBlocks; - uint32_t volumeStartBlock = 0; - fat32_boot_t* fbs; - - sdCard_ = dev; - fatType_ = 0; - allocSearchStart_ = 2; - cacheDirty_ = 0; // cacheFlush() will write block if true - cacheMirrorBlock_ = 0; - cacheBlockNumber_ = 0XFFFFFFFF; - - // if part == 0 assume super floppy with FAT boot sector in block zero - // if part > 0 assume mbr volume with partition table - if (part) { - if (part > 4)goto fail; + uint32_t totalBlocks; + uint32_t volumeStartBlock = 0; + fat32_boot_t* fbs; + + sdCard_ = dev; + fatType_ = 0; + allocSearchStart_ = 2; + cacheDirty_ = 0; // cacheFlush() will write block if true + cacheMirrorBlock_ = 0; + cacheBlockNumber_ = 0XFFFFFFFF; + + // if part == 0 assume super floppy with FAT boot sector in block zero + // if part > 0 assume mbr volume with partition table + if (part) { + if (part > 4)goto fail; + if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; + part_t* p = &cacheBuffer_.mbr.part[part-1]; + if ((p->boot & 0X7F) !=0 || + p->totalSectors < 100 || + p->firstSector == 0) { + // not a valid partition + goto fail; + } + volumeStartBlock = p->firstSector; + } if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; - part_t* p = &cacheBuffer_.mbr.part[part-1]; - if ((p->boot & 0X7F) !=0 || - p->totalSectors < 100 || - p->firstSector == 0) { - // not a valid partition - goto fail; + fbs = &cacheBuffer_.fbs32; + if (fbs->bytesPerSector != 512 || + fbs->fatCount == 0 || + fbs->reservedSectorCount == 0 || + fbs->sectorsPerCluster == 0) { + // not valid FAT volume + goto fail; + } + fatCount_ = fbs->fatCount; + blocksPerCluster_ = fbs->sectorsPerCluster; + // determine shift that is same as multiply by blocksPerCluster_ + clusterSizeShift_ = 0; + while (blocksPerCluster_ != (1 << clusterSizeShift_)) { + // error if not power of 2 + if (clusterSizeShift_++ > 7) goto fail; } - volumeStartBlock = p->firstSector; - } - if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail; - fbs = &cacheBuffer_.fbs32; - if (fbs->bytesPerSector != 512 || - fbs->fatCount == 0 || - fbs->reservedSectorCount == 0 || - fbs->sectorsPerCluster == 0) { - // not valid FAT volume - goto fail; - } - fatCount_ = fbs->fatCount; - blocksPerCluster_ = fbs->sectorsPerCluster; - // determine shift that is same as multiply by blocksPerCluster_ - clusterSizeShift_ = 0; - while (blocksPerCluster_ != (1 << clusterSizeShift_)) { - // error if not power of 2 - if (clusterSizeShift_++ > 7) goto fail; - } - blocksPerFat_ = fbs->sectorsPerFat16 ? + blocksPerFat_ = fbs->sectorsPerFat16 ? fbs->sectorsPerFat16 : fbs->sectorsPerFat32; - fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount; + fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount; - // count for FAT16 zero for FAT32 - rootDirEntryCount_ = fbs->rootDirEntryCount; + // count for FAT16 zero for FAT32 + rootDirEntryCount_ = fbs->rootDirEntryCount; - // directory start for FAT16 dataStart for FAT32 - rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_; + // directory start for FAT16 dataStart for FAT32 + rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_; - // data start for FAT16 and FAT32 - dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512); + // data start for FAT16 and FAT32 + dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512); - // total blocks for FAT16 or FAT32 - totalBlocks = fbs->totalSectors16 ? - fbs->totalSectors16 : fbs->totalSectors32; - // total data blocks - clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); + // total blocks for FAT16 or FAT32 + totalBlocks = fbs->totalSectors16 ? + fbs->totalSectors16 : fbs->totalSectors32; + // total data blocks + clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); - // divide by cluster size to get cluster count - clusterCount_ >>= clusterSizeShift_; + // divide by cluster size to get cluster count + clusterCount_ >>= clusterSizeShift_; - // FAT type is determined by cluster count - if (clusterCount_ < 4085) { - fatType_ = 12; - if (!FAT12_SUPPORT) goto fail; - } else if (clusterCount_ < 65525) { - fatType_ = 16; - } else { - rootDirStart_ = fbs->fat32RootCluster; - fatType_ = 32; - } - return true; + // FAT type is determined by cluster count + if (clusterCount_ < 4085) { + fatType_ = 12; + if (!FAT12_SUPPORT) goto fail; + } else if (clusterCount_ < 65525) { + fatType_ = 16; + } else { + rootDirStart_ = fbs->fat32RootCluster; + fatType_ = 32; + } + return true; - fail: - return false; +fail: + return false; } #endif \ No newline at end of file diff --git a/Firmware/SdVolume.h b/Firmware/SdVolume.h index 2ff2b6eb96..975be86217 100755 --- a/Firmware/SdVolume.h +++ b/Firmware/SdVolume.h @@ -35,22 +35,22 @@ * \brief Cache for an SD data block */ union cache_t { - /** Used to access cached file data blocks. */ - uint8_t data[512]; - /** Used to access cached FAT16 entries. */ - uint16_t fat16[256]; - /** Used to access cached FAT32 entries. */ - uint32_t fat32[128]; - /** Used to access cached directory entries. */ - dir_t dir[16]; - /** Used to access a cached Master Boot Record. */ - mbr_t mbr; - /** Used to access to a cached FAT boot sector. */ - fat_boot_t fbs; - /** Used to access to a cached FAT32 boot sector. */ - fat32_boot_t fbs32; - /** Used to access to a cached FAT32 FSINFO sector. */ - fat32_fsinfo_t fsinfo; + /** Used to access cached file data blocks. */ + uint8_t data[512]; + /** Used to access cached FAT16 entries. */ + uint16_t fat16[256]; + /** Used to access cached FAT32 entries. */ + uint32_t fat32[128]; + /** Used to access cached directory entries. */ + dir_t dir[16]; + /** Used to access a cached Master Boot Record. */ + mbr_t mbr; + /** Used to access to a cached FAT boot sector. */ + fat_boot_t fbs; + /** Used to access to a cached FAT32 boot sector. */ + fat32_boot_t fbs32; + /** Used to access to a cached FAT32 FSINFO sector. */ + fat32_fsinfo_t fsinfo; }; //------------------------------------------------------------------------------ /** @@ -58,156 +58,194 @@ union cache_t { * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards. */ class SdVolume { - public: - /** Create an instance of SdVolume */ - SdVolume() : fatType_(0) {} - /** Clear the cache and returns a pointer to the cache. Used by the WaveRP - * recorder to do raw write to the SD card. Not for normal apps. - * \return A pointer to the cache buffer or zero if an error occurs. - */ - cache_t* cacheClear() { - if (!cacheFlush()) return 0; - cacheBlockNumber_ = 0XFFFFFFFF; - return &cacheBuffer_; - } - /** Initialize a FAT volume. Try partition one first then try super - * floppy format. - * - * \param[in] dev The Sd2Card where the volume is located. - * - * \return The value one, true, is returned for success and - * the value zero, false, is returned for failure. Reasons for - * failure include not finding a valid partition, not finding a valid - * FAT file system or an I/O error. - */ - bool init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);} - bool init(Sd2Card* dev, uint8_t part); +public: + /** Create an instance of SdVolume */ + SdVolume() : fatType_(0) {} + /** Clear the cache and returns a pointer to the cache. Used by the WaveRP + * recorder to do raw write to the SD card. Not for normal apps. + * \return A pointer to the cache buffer or zero if an error occurs. + */ + cache_t* cacheClear() { + if (!cacheFlush()) return 0; + cacheBlockNumber_ = 0XFFFFFFFF; + return &cacheBuffer_; + } + /** Initialize a FAT volume. Try partition one first then try super + * floppy format. + * + * \param[in] dev The Sd2Card where the volume is located. + * + * \return The value one, true, is returned for success and + * the value zero, false, is returned for failure. Reasons for + * failure include not finding a valid partition, not finding a valid + * FAT file system or an I/O error. + */ + bool init(Sd2Card* dev) { + return init(dev, 1) ? true : init(dev, 0); + } + bool init(Sd2Card* dev, uint8_t part); - // inline functions that return volume info - /** \return The volume's cluster size in blocks. */ - uint8_t blocksPerCluster() const {return blocksPerCluster_;} - /** \return The number of blocks in one FAT. */ - uint32_t blocksPerFat() const {return blocksPerFat_;} - /** \return The total number of clusters in the volume. */ - uint32_t clusterCount() const {return clusterCount_;} - /** \return The shift count required to multiply by blocksPerCluster. */ - uint8_t clusterSizeShift() const {return clusterSizeShift_;} - /** \return The logical block number for the start of file data. */ - uint32_t dataStartBlock() const {return dataStartBlock_;} - /** \return The number of FAT structures on the volume. */ - uint8_t fatCount() const {return fatCount_;} - /** \return The logical block number for the start of the first FAT. */ - uint32_t fatStartBlock() const {return fatStartBlock_;} - /** \return The FAT type of the volume. Values are 12, 16 or 32. */ - uint8_t fatType() const {return fatType_;} - int32_t freeClusterCount(); - /** \return The number of entries in the root directory for FAT16 volumes. */ - uint32_t rootDirEntryCount() const {return rootDirEntryCount_;} - /** \return The logical block number for the start of the root directory - on FAT16 volumes or the first cluster number on FAT32 volumes. */ - uint32_t rootDirStart() const {return rootDirStart_;} - /** Sd2Card object for this volume - * \return pointer to Sd2Card object. - */ - Sd2Card* sdCard() {return sdCard_;} - /** Debug access to FAT table - * - * \param[in] n cluster number. - * \param[out] v value of entry - * \return true for success or false for failure - */ - bool dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);} + // inline functions that return volume info + /** \return The volume's cluster size in blocks. */ + uint8_t blocksPerCluster() const { + return blocksPerCluster_; + } + /** \return The number of blocks in one FAT. */ + uint32_t blocksPerFat() const { + return blocksPerFat_; + } + /** \return The total number of clusters in the volume. */ + uint32_t clusterCount() const { + return clusterCount_; + } + /** \return The shift count required to multiply by blocksPerCluster. */ + uint8_t clusterSizeShift() const { + return clusterSizeShift_; + } + /** \return The logical block number for the start of file data. */ + uint32_t dataStartBlock() const { + return dataStartBlock_; + } + /** \return The number of FAT structures on the volume. */ + uint8_t fatCount() const { + return fatCount_; + } + /** \return The logical block number for the start of the first FAT. */ + uint32_t fatStartBlock() const { + return fatStartBlock_; + } + /** \return The FAT type of the volume. Values are 12, 16 or 32. */ + uint8_t fatType() const { + return fatType_; + } + int32_t freeClusterCount(); + /** \return The number of entries in the root directory for FAT16 volumes. */ + uint32_t rootDirEntryCount() const { + return rootDirEntryCount_; + } + /** \return The logical block number for the start of the root directory + on FAT16 volumes or the first cluster number on FAT32 volumes. */ + uint32_t rootDirStart() const { + return rootDirStart_; + } + /** Sd2Card object for this volume + * \return pointer to Sd2Card object. + */ + Sd2Card* sdCard() { + return sdCard_; + } + /** Debug access to FAT table + * + * \param[in] n cluster number. + * \param[out] v value of entry + * \return true for success or false for failure + */ + bool dbgFat(uint32_t n, uint32_t* v) { + return fatGet(n, v); + } //------------------------------------------------------------------------------ - private: - // Allow SdBaseFile access to SdVolume private data. - friend class SdBaseFile; +private: + // Allow SdBaseFile access to SdVolume private data. + friend class SdBaseFile; - // value for dirty argument in cacheRawBlock to indicate read from cache - static bool const CACHE_FOR_READ = false; - // value for dirty argument in cacheRawBlock to indicate write to cache - static bool const CACHE_FOR_WRITE = true; + // value for dirty argument in cacheRawBlock to indicate read from cache + static bool const CACHE_FOR_READ = false; + // value for dirty argument in cacheRawBlock to indicate write to cache + static bool const CACHE_FOR_WRITE = true; #if USE_MULTIPLE_CARDS - cache_t cacheBuffer_; // 512 byte cache for device blocks - uint32_t cacheBlockNumber_; // Logical number of block in the cache - Sd2Card* sdCard_; // Sd2Card object for cache - bool cacheDirty_; // cacheFlush() will write block if true - uint32_t cacheMirrorBlock_; // block number for mirror FAT + cache_t cacheBuffer_; // 512 byte cache for device blocks + uint32_t cacheBlockNumber_; // Logical number of block in the cache + Sd2Card* sdCard_; // Sd2Card object for cache + bool cacheDirty_; // cacheFlush() will write block if true + uint32_t cacheMirrorBlock_; // block number for mirror FAT #else // USE_MULTIPLE_CARDS - static cache_t cacheBuffer_; // 512 byte cache for device blocks - static uint32_t cacheBlockNumber_; // Logical number of block in the cache - static Sd2Card* sdCard_; // Sd2Card object for cache - static bool cacheDirty_; // cacheFlush() will write block if true - static uint32_t cacheMirrorBlock_; // block number for mirror FAT + static cache_t cacheBuffer_; // 512 byte cache for device blocks + static uint32_t cacheBlockNumber_; // Logical number of block in the cache + static Sd2Card* sdCard_; // Sd2Card object for cache + static bool cacheDirty_; // cacheFlush() will write block if true + static uint32_t cacheMirrorBlock_; // block number for mirror FAT #endif // USE_MULTIPLE_CARDS - uint32_t allocSearchStart_; // start cluster for alloc search - uint8_t blocksPerCluster_; // cluster size in blocks - uint32_t blocksPerFat_; // FAT size in blocks - uint32_t clusterCount_; // clusters in one FAT - uint8_t clusterSizeShift_; // shift to convert cluster count to block count - uint32_t dataStartBlock_; // first data block number - uint8_t fatCount_; // number of FATs on volume - uint32_t fatStartBlock_; // start block for first FAT - uint8_t fatType_; // volume type (12, 16, OR 32) - uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir - uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32 - //---------------------------------------------------------------------------- - bool allocContiguous(uint32_t count, uint32_t* curCluster); - uint8_t blockOfCluster(uint32_t position) const { - return (position >> 9) & (blocksPerCluster_ - 1);} - uint32_t clusterStartBlock(uint32_t cluster) const { - return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);} - uint32_t blockNumber(uint32_t cluster, uint32_t position) const { - return clusterStartBlock(cluster) + blockOfCluster(position);} - cache_t *cache() {return &cacheBuffer_;} - uint32_t cacheBlockNumber() {return cacheBlockNumber_;} + uint32_t allocSearchStart_; // start cluster for alloc search + uint8_t blocksPerCluster_; // cluster size in blocks + uint32_t blocksPerFat_; // FAT size in blocks + uint32_t clusterCount_; // clusters in one FAT + uint8_t clusterSizeShift_; // shift to convert cluster count to block count + uint32_t dataStartBlock_; // first data block number + uint8_t fatCount_; // number of FATs on volume + uint32_t fatStartBlock_; // start block for first FAT + uint8_t fatType_; // volume type (12, 16, OR 32) + uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir + uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32 + //---------------------------------------------------------------------------- + bool allocContiguous(uint32_t count, uint32_t* curCluster); + uint8_t blockOfCluster(uint32_t position) const { + return (position >> 9) & (blocksPerCluster_ - 1); + } + uint32_t clusterStartBlock(uint32_t cluster) const { + return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_); + } + uint32_t blockNumber(uint32_t cluster, uint32_t position) const { + return clusterStartBlock(cluster) + blockOfCluster(position); + } + cache_t *cache() { + return &cacheBuffer_; + } + uint32_t cacheBlockNumber() { + return cacheBlockNumber_; + } #if USE_MULTIPLE_CARDS - bool cacheFlush(); - bool cacheRawBlock(uint32_t blockNumber, bool dirty); + bool cacheFlush(); + bool cacheRawBlock(uint32_t blockNumber, bool dirty); #else // USE_MULTIPLE_CARDS - static bool cacheFlush(); - static bool cacheRawBlock(uint32_t blockNumber, bool dirty); + static bool cacheFlush(); + static bool cacheRawBlock(uint32_t blockNumber, bool dirty); #endif // USE_MULTIPLE_CARDS - // used by SdBaseFile write to assign cache to SD location - void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) { - cacheDirty_ = dirty; - cacheBlockNumber_ = blockNumber; - } - void cacheSetDirty() {cacheDirty_ |= CACHE_FOR_WRITE;} - bool chainSize(uint32_t beginCluster, uint32_t* size); - bool fatGet(uint32_t cluster, uint32_t* value); - bool fatPut(uint32_t cluster, uint32_t value); - bool fatPutEOC(uint32_t cluster) { - return fatPut(cluster, 0x0FFFFFFF); - } - bool freeChain(uint32_t cluster); - bool isEOC(uint32_t cluster) const { - if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN; - if (fatType_ == 16) return cluster >= FAT16EOC_MIN; - return cluster >= FAT32EOC_MIN; - } - bool readBlock(uint32_t block, uint8_t* dst) { - return sdCard_->readBlock(block, dst);} - bool writeBlock(uint32_t block, const uint8_t* dst) { - return sdCard_->writeBlock(block, dst); - } + // used by SdBaseFile write to assign cache to SD location + void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) { + cacheDirty_ = dirty; + cacheBlockNumber_ = blockNumber; + } + void cacheSetDirty() { + cacheDirty_ |= CACHE_FOR_WRITE; + } + bool chainSize(uint32_t beginCluster, uint32_t* size); + bool fatGet(uint32_t cluster, uint32_t* value); + bool fatPut(uint32_t cluster, uint32_t value); + bool fatPutEOC(uint32_t cluster) { + return fatPut(cluster, 0x0FFFFFFF); + } + bool freeChain(uint32_t cluster); + bool isEOC(uint32_t cluster) const { + if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN; + if (fatType_ == 16) return cluster >= FAT16EOC_MIN; + return cluster >= FAT32EOC_MIN; + } + bool readBlock(uint32_t block, uint8_t* dst) { + return sdCard_->readBlock(block, dst); + } + bool writeBlock(uint32_t block, const uint8_t* dst) { + return sdCard_->writeBlock(block, dst); + } //------------------------------------------------------------------------------ - // Deprecated functions - suppress cpplint warnings with NOLINT comment + // Deprecated functions - suppress cpplint warnings with NOLINT comment #if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN) - public: - /** \deprecated Use: bool SdVolume::init(Sd2Card* dev); - * \param[in] dev The SD card where the volume is located. - * \return true for success or false for failure. - */ - bool init(Sd2Card& dev) {return init(&dev);} // NOLINT - /** \deprecated Use: bool SdVolume::init(Sd2Card* dev, uint8_t vol); - * \param[in] dev The SD card where the volume is located. - * \param[in] part The partition to be used. - * \return true for success or false for failure. - */ - bool init(Sd2Card& dev, uint8_t part) { // NOLINT - return init(&dev, part); - } +public: + /** \deprecated Use: bool SdVolume::init(Sd2Card* dev); + * \param[in] dev The SD card where the volume is located. + * \return true for success or false for failure. + */ + bool init(Sd2Card& dev) { + return init(&dev); // NOLINT + } + /** \deprecated Use: bool SdVolume::init(Sd2Card* dev, uint8_t vol); + * \param[in] dev The SD card where the volume is located. + * \param[in] part The partition to be used. + * \return true for success or false for failure. + */ + bool init(Sd2Card& dev, uint8_t part) { // NOLINT + return init(&dev, part); + } #endif // ALLOW_DEPRECATED_FUNCTIONS }; #endif // SdVolume diff --git a/Firmware/Servo.cpp b/Firmware/Servo.cpp index 5f8c7efe30..bb74b35792 100755 --- a/Firmware/Servo.cpp +++ b/Firmware/Servo.cpp @@ -41,7 +41,7 @@ detach() - Stops an attached servos from pulsing its i/o pin. */ -#include "Configuration.h" +#include "Configuration.h" #ifdef NUM_SERVOS #include @@ -76,27 +76,27 @@ uint8_t ServoCount = 0; // the total number static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA) { - if( Channel[timer] < 0 ) - *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer - else{ - if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true ) - digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated - } - - Channel[timer]++; // increment to the next channel - if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { - *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks; - if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated - digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high - } - else { - // finished all channels so wait for the refresh period to expire before starting over - if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed - *OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL); - else - *OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed - Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel - } + if( Channel[timer] < 0 ) + *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer + else { + if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true ) + digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated + } + + Channel[timer]++; // increment to the next channel + if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) { + *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks; + if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated + digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high + } + else { + // finished all channels so wait for the refresh period to expire before starting over + if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed + *OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL); + else + *OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed + Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel + } } #ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform @@ -104,28 +104,28 @@ static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t #if defined(_useTimer1) SIGNAL (TIMER1_COMPA_vect) { - handle_interrupts(_timer1, &TCNT1, &OCR1A); + handle_interrupts(_timer1, &TCNT1, &OCR1A); } #endif #if defined(_useTimer3) SIGNAL (TIMER3_COMPA_vect) { - handle_interrupts(_timer3, &TCNT3, &OCR3A); + handle_interrupts(_timer3, &TCNT3, &OCR3A); } #endif #if defined(_useTimer4) SIGNAL (TIMER4_COMPA_vect) { - handle_interrupts(_timer4, &TCNT4, &OCR4A); + handle_interrupts(_timer4, &TCNT4, &OCR4A); } #endif #if defined(_useTimer5) SIGNAL (TIMER5_COMPA_vect) { - handle_interrupts(_timer5, &TCNT5, &OCR5A); + handle_interrupts(_timer5, &TCNT5, &OCR5A); } #endif @@ -134,13 +134,13 @@ SIGNAL (TIMER5_COMPA_vect) #if defined(_useTimer1) void Timer1Service() { - handle_interrupts(_timer1, &TCNT1, &OCR1A); + handle_interrupts(_timer1, &TCNT1, &OCR1A); } #endif #if defined(_useTimer3) void Timer3Service() { - handle_interrupts(_timer3, &TCNT3, &OCR3A); + handle_interrupts(_timer3, &TCNT3, &OCR3A); } #endif #endif @@ -149,60 +149,60 @@ void Timer3Service() static void initISR(timer16_Sequence_t timer) { #if defined (_useTimer1) - if(timer == _timer1) { - TCCR1A = 0; // normal counting mode - TCCR1B = _BV(CS11); // set prescaler of 8 - TCNT1 = 0; // clear the timer count + if(timer == _timer1) { + TCCR1A = 0; // normal counting mode + TCCR1B = _BV(CS11); // set prescaler of 8 + TCNT1 = 0; // clear the timer count #if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__) - TIFR |= _BV(OCF1A); // clear any pending interrupts; - TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt + TIFR |= _BV(OCF1A); // clear any pending interrupts; + TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt #else - // here if not ATmega8 or ATmega128 - TIFR1 |= _BV(OCF1A); // clear any pending interrupts; - TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt + // here if not ATmega8 or ATmega128 + TIFR1 |= _BV(OCF1A); // clear any pending interrupts; + TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt #endif #if defined(WIRING) - timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service); + timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service); #endif - } + } #endif #if defined (_useTimer3) - if(timer == _timer3) { - TCCR3A = 0; // normal counting mode - TCCR3B = _BV(CS31); // set prescaler of 8 - TCNT3 = 0; // clear the timer count + if(timer == _timer3) { + TCCR3A = 0; // normal counting mode + TCCR3B = _BV(CS31); // set prescaler of 8 + TCNT3 = 0; // clear the timer count #if defined(__AVR_ATmega128__) - TIFR |= _BV(OCF3A); // clear any pending interrupts; - ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt + TIFR |= _BV(OCF3A); // clear any pending interrupts; + ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt #else - TIFR3 = _BV(OCF3A); // clear any pending interrupts; - TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt + TIFR3 = _BV(OCF3A); // clear any pending interrupts; + TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt #endif #if defined(WIRING) - timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only + timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only #endif - } + } #endif #if defined (_useTimer4) - if(timer == _timer4) { - TCCR4A = 0; // normal counting mode - TCCR4B = _BV(CS41); // set prescaler of 8 - TCNT4 = 0; // clear the timer count - TIFR4 = _BV(OCF4A); // clear any pending interrupts; - TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt - } + if(timer == _timer4) { + TCCR4A = 0; // normal counting mode + TCCR4B = _BV(CS41); // set prescaler of 8 + TCNT4 = 0; // clear the timer count + TIFR4 = _BV(OCF4A); // clear any pending interrupts; + TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt + } #endif #if defined (_useTimer5) - if(timer == _timer5) { - TCCR5A = 0; // normal counting mode - TCCR5B = _BV(CS51); // set prescaler of 8 - TCNT5 = 0; // clear the timer count - TIFR5 = _BV(OCF5A); // clear any pending interrupts; - TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt - } + if(timer == _timer5) { + TCCR5A = 0; // normal counting mode + TCCR5B = _BV(CS51); // set prescaler of 8 + TCNT5 = 0; // clear the timer count + TIFR5 = _BV(OCF5A); // clear any pending interrupts; + TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt + } #endif } @@ -210,22 +210,22 @@ static void finISR(timer16_Sequence_t timer) { //disable use of the given timer #if defined WIRING // Wiring - if(timer == _timer1) { - #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) - TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt - #else - TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt - #endif - timerDetach(TIMER1OUTCOMPAREA_INT); - } - else if(timer == _timer3) { - #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) - TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt - #else - ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt - #endif - timerDetach(TIMER3OUTCOMPAREA_INT); - } + if(timer == _timer1) { +#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) + TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt +#else + TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt +#endif + timerDetach(TIMER1OUTCOMPAREA_INT); + } + else if(timer == _timer3) { +#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) + TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt +#else + ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt +#endif + timerDetach(TIMER3OUTCOMPAREA_INT); + } #else //For arduino - in future: call here to a currently undefined function to reset the timer #endif @@ -233,12 +233,12 @@ static void finISR(timer16_Sequence_t timer) static boolean isTimerActive(timer16_Sequence_t timer) { - // returns true if any servo is active on this timer - for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) { - if(SERVO(timer,channel).Pin.isActive == true) - return true; - } - return false; + // returns true if any servo is active on this timer + for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) { + if(SERVO(timer,channel).Pin.isActive == true) + return true; + } + return false; } @@ -246,99 +246,100 @@ static boolean isTimerActive(timer16_Sequence_t timer) Servo::Servo() { - if( ServoCount < MAX_SERVOS) { - this->servoIndex = ServoCount++; // assign a servo index to this instance - servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009 - } - else - this->servoIndex = INVALID_SERVO ; // too many servos + if( ServoCount < MAX_SERVOS) { + this->servoIndex = ServoCount++; // assign a servo index to this instance + servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009 + } + else + this->servoIndex = INVALID_SERVO ; // too many servos } uint8_t Servo::attach(int pin) { - return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); + return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH); } uint8_t Servo::attach(int pin, int min, int max) { - if(this->servoIndex < MAX_SERVOS ) { + 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; + 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 - this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS - this->max = (MAX_PULSE_WIDTH - max)/4; - // initialize the timer if it has not already been initialized - timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); - if(isTimerActive(timer) == false) - initISR(timer); - servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive - } - return this->servoIndex ; + 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 + this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS + this->max = (MAX_PULSE_WIDTH - max)/4; + // initialize the timer if it has not already been initialized + timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); + if(isTimerActive(timer) == false) + initISR(timer); + servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive + } + return this->servoIndex ; } void Servo::detach() { - servos[this->servoIndex].Pin.isActive = false; - timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); - if(isTimerActive(timer) == false) { - finISR(timer); - } + servos[this->servoIndex].Pin.isActive = false; + timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex); + if(isTimerActive(timer) == false) { + finISR(timer); + } } void Servo::write(int value) { - if(value < MIN_PULSE_WIDTH) - { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) - if(value < 0) value = 0; - if(value > 180) value = 180; - value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); - } - this->writeMicroseconds(value); + if(value < MIN_PULSE_WIDTH) + { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) + if(value < 0) value = 0; + if(value > 180) value = 180; + value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX()); + } + this->writeMicroseconds(value); } void Servo::writeMicroseconds(int value) { - // calculate and store the values for the given channel - byte channel = this->servoIndex; - if( (channel < MAX_SERVOS) ) // ensure channel is valid - { - if( value < SERVO_MIN() ) // ensure pulse width is valid - value = SERVO_MIN(); - else if( value > SERVO_MAX() ) - value = SERVO_MAX(); - - value = value - TRIM_DURATION; - value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 - - uint8_t oldSREG = SREG; - cli(); - servos[channel].ticks = value; - SREG = oldSREG; - } + // calculate and store the values for the given channel + byte channel = this->servoIndex; + if( (channel < MAX_SERVOS) ) // ensure channel is valid + { + if( value < SERVO_MIN() ) // ensure pulse width is valid + value = SERVO_MIN(); + else if( value > SERVO_MAX() ) + value = SERVO_MAX(); + + value = value - TRIM_DURATION; + value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009 + + uint8_t oldSREG = SREG; + cli(); + servos[channel].ticks = value; + SREG = oldSREG; + } } int Servo::read() // return the value as degrees { - return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); + return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180); } int Servo::readMicroseconds() { - unsigned int pulsewidth; - if( this->servoIndex != INVALID_SERVO ) - pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009 - else - pulsewidth = 0; + unsigned int pulsewidth; + if( this->servoIndex != INVALID_SERVO ) + pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009 + else + pulsewidth = 0; - return pulsewidth; + return pulsewidth; } bool Servo::attached() { - return servos[this->servoIndex].Pin.isActive ; + return servos[this->servoIndex].Pin.isActive ; } #endif diff --git a/Firmware/Servo.h b/Firmware/Servo.h index 204497a4ad..1ceb34b64e 100755 --- a/Firmware/Servo.h +++ b/Firmware/Servo.h @@ -102,34 +102,34 @@ typedef enum { _Nbr_16timers } timer16_Sequence_t ; #define INVALID_SERVO 255 // flag indicating an invalid servo index typedef struct { - uint8_t nbr :6 ; // a pin number from 0 to 63 - uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false + uint8_t nbr :6 ; // a pin number from 0 to 63 + uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false } ServoPin_t ; typedef struct { - ServoPin_t Pin; - unsigned int ticks; + ServoPin_t Pin; + unsigned int ticks; } servo_t; class Servo { public: - Servo(); - 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 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 + Servo(); + 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 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 hardware 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 - int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH - int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH + 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 + int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH }; #endif diff --git a/Firmware/Timer.h b/Firmware/Timer.h index e2e84eff90..9c029c78bb 100755 --- a/Firmware/Timer.h +++ b/Firmware/Timer.h @@ -19,11 +19,17 @@ class Timer public: Timer(); void start(); - void stop(){m_isRunning = false;} - bool running(){return m_isRunning;} + void stop() { + m_isRunning = false; + } + bool running() { + return m_isRunning; + } bool expired(T msPeriod); protected: - T started(){return m_started;} + T started() { + return m_started; + } private: bool m_isRunning; T m_started; diff --git a/Firmware/TimerRemaining.h b/Firmware/TimerRemaining.h index 6d5136dea7..40f0d644ec 100755 --- a/Firmware/TimerRemaining.h +++ b/Firmware/TimerRemaining.h @@ -13,7 +13,7 @@ class TimerRemaining : public LongTimer { public: - TimerRemaining() : m_period(){} + TimerRemaining() : m_period() {} void start() = delete; bool expired(unsigned long msPeriod) = delete; /** @@ -34,10 +34,10 @@ class TimerRemaining : public LongTimer */ unsigned long remaining() { - if (!running()) return 0; - if (expired()) return 0; - const unsigned long now = millis(); - return (started() + m_period - now); + if (!running()) return 0; + if (expired()) return 0; + const unsigned long now = millis(); + return (started() + m_period - now); } /** * @brief Timer has expired. diff --git a/Firmware/adc.c b/Firmware/adc.c index 26728cef5f..c52129bff3 100755 --- a/Firmware/adc.c +++ b/Firmware/adc.c @@ -12,21 +12,21 @@ uint16_t adc_sim_mask; #ifdef ADC_CALLBACK - extern void ADC_CALLBACK(void); +extern void ADC_CALLBACK(void); #endif //ADC_CALLBACK void adc_init(void) { - printf_P(PSTR("adc_init\n")); - adc_sim_mask = 0x00; - ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); - ADMUX |= (1 << REFS0); - ADCSRA |= (1 << ADEN); + printf_P(PSTR("adc_init\n")); + adc_sim_mask = 0x00; + ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); + ADMUX |= (1 << REFS0); + ADCSRA |= (1 << ADEN); // ADCSRA |= (1 << ADIF) | (1 << ADSC); - DIDR0 = (ADC_CHAN_MSK & 0xff); - DIDR2 = (ADC_CHAN_MSK >> 8); - adc_reset(); + DIDR0 = (ADC_CHAN_MSK & 0xff); + DIDR2 = (ADC_CHAN_MSK >> 8); + adc_reset(); // adc_sim_mask = 0b0101; // adc_sim_mask = 0b100101; // adc_values[0] = 1023 * 16; @@ -36,59 +36,60 @@ void adc_init(void) void adc_reset(void) { - adc_state = 0; - adc_count = 0; - uint8_t i; for (i = 0; i < ADC_CHAN_CNT; i++) - if ((adc_sim_mask & (1 << i)) == 0) - adc_values[i] = 0; + adc_state = 0; + adc_count = 0; + uint8_t i; + for (i = 0; i < ADC_CHAN_CNT; i++) + if ((adc_sim_mask & (1 << i)) == 0) + adc_values[i] = 0; } void adc_setmux(uint8_t ch) { - ch &= 0x0f; - if (ch & 0x08) ADCSRB |= (1 << MUX5); - else ADCSRB &= ~(1 << MUX5); - ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07); + ch &= 0x0f; + if (ch & 0x08) ADCSRB |= (1 << MUX5); + else ADCSRB &= ~(1 << MUX5); + ADMUX = (ADMUX & ~(0x07)) | (ch & 0x07); } uint8_t adc_chan(uint8_t index) { - uint8_t chan = 0; - uint16_t mask = 1; - while (mask) - { - if ((mask & ADC_CHAN_MSK) && (index-- == 0)) break; - mask <<= 1; - chan++; - } - return chan; + uint8_t chan = 0; + uint16_t mask = 1; + while (mask) + { + if ((mask & ADC_CHAN_MSK) && (index-- == 0)) break; + mask <<= 1; + chan++; + } + return chan; } void adc_cycle(void) { - if (adc_state & 0x80) - { - uint8_t index = adc_state & 0x0f; - if ((adc_sim_mask & (1 << index)) == 0) - adc_values[index] += ADC; - if (++index >= ADC_CHAN_CNT) - { - index = 0; - adc_count++; - if (adc_count >= ADC_OVRSAMPL) - { + if (adc_state & 0x80) + { + uint8_t index = adc_state & 0x0f; + if ((adc_sim_mask & (1 << index)) == 0) + adc_values[index] += ADC; + if (++index >= ADC_CHAN_CNT) + { + index = 0; + adc_count++; + if (adc_count >= ADC_OVRSAMPL) + { #ifdef ADC_CALLBACK - ADC_CALLBACK(); + ADC_CALLBACK(); #endif //ADC_CALLBACK - adc_reset(); - } - } - adc_setmux(adc_chan(index)); - adc_state = index; - } - else - { - ADCSRA |= (1 << ADSC); //start conversion - adc_state |= 0x80; - } + adc_reset(); + } + } + adc_setmux(adc_chan(index)); + adc_state = index; + } + else + { + ADCSRA |= (1 << ADSC); //start conversion + adc_state |= 0x80; + } } diff --git a/Firmware/bootapp.c b/Firmware/bootapp.c index 4fd67db2b6..1ba641e8d7 100755 --- a/Firmware/bootapp.c +++ b/Firmware/bootapp.c @@ -11,45 +11,45 @@ extern FILE _uartout; void bootapp_print_vars(void) { - fprintf_P(uartout, PSTR("boot_src_addr =0x%08lx\n"), boot_src_addr); - fprintf_P(uartout, PSTR("boot_dst_addr =0x%08lx\n"), boot_dst_addr); - fprintf_P(uartout, PSTR("boot_copy_size =0x%04x\n"), boot_copy_size); - fprintf_P(uartout, PSTR("boot_reserved =0x%02x\n"), boot_reserved); - fprintf_P(uartout, PSTR("boot_app_flags =0x%02x\n"), boot_app_flags); - fprintf_P(uartout, PSTR("boot_app_magic =0x%08lx\n"), boot_app_magic); + fprintf_P(uartout, PSTR("boot_src_addr =0x%08lx\n"), boot_src_addr); + fprintf_P(uartout, PSTR("boot_dst_addr =0x%08lx\n"), boot_dst_addr); + fprintf_P(uartout, PSTR("boot_copy_size =0x%04x\n"), boot_copy_size); + fprintf_P(uartout, PSTR("boot_reserved =0x%02x\n"), boot_reserved); + fprintf_P(uartout, PSTR("boot_app_flags =0x%02x\n"), boot_app_flags); + fprintf_P(uartout, PSTR("boot_app_magic =0x%08lx\n"), boot_app_magic); } void bootapp_ram2flash(uint16_t rptr, uint16_t fptr, uint16_t size) { - cli(); - boot_app_magic = BOOT_APP_MAGIC; - boot_app_flags |= BOOT_APP_FLG_COPY; - boot_app_flags |= BOOT_APP_FLG_ERASE; -/* uint16_t ui; for (ui = 0; ui < size; ui++) - { - uint8_t uc = ram_array[ui+rptr]; - if (pgm_read_byte(ui+fptr) & uc != uc) - { - boot_app_flags |= BOOT_APP_FLG_ERASE; - break; - } - }*/ - boot_copy_size = (uint16_t)size; - boot_src_addr = (uint32_t)rptr; - boot_dst_addr = (uint32_t)fptr; - bootapp_print_vars(); - wdt_enable(WDTO_15MS); - while(1); + cli(); + boot_app_magic = BOOT_APP_MAGIC; + boot_app_flags |= BOOT_APP_FLG_COPY; + boot_app_flags |= BOOT_APP_FLG_ERASE; + /* uint16_t ui; for (ui = 0; ui < size; ui++) + { + uint8_t uc = ram_array[ui+rptr]; + if (pgm_read_byte(ui+fptr) & uc != uc) + { + boot_app_flags |= BOOT_APP_FLG_ERASE; + break; + } + }*/ + boot_copy_size = (uint16_t)size; + boot_src_addr = (uint32_t)rptr; + boot_dst_addr = (uint32_t)fptr; + bootapp_print_vars(); + wdt_enable(WDTO_15MS); + while(1); } void bootapp_reboot_user0(uint8_t reserved) { - cli(); - boot_app_magic = BOOT_APP_MAGIC; - boot_app_flags = BOOT_APP_FLG_USER0; - boot_reserved = reserved; - bootapp_print_vars(); - wdt_enable(WDTO_15MS); - while(1); + cli(); + boot_app_magic = BOOT_APP_MAGIC; + boot_app_flags = BOOT_APP_FLG_USER0; + boot_reserved = reserved; + bootapp_print_vars(); + wdt_enable(WDTO_15MS); + while(1); } diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index eac738c859..a927496ab1 100755 --- a/Firmware/cardreader.cpp +++ b/Firmware/cardreader.cpp @@ -12,52 +12,52 @@ CardReader::CardReader() { - #ifdef SDCARD_SORT_ALPHA - sort_count = 0; - #if SDSORT_GCODE - sort_alpha = true; - sort_folders = FOLDER_SORTING; - //sort_reverse = false; - #endif - #endif - - filesize = 0; - sdpos = 0; - sdprinting = false; - cardOK = false; - paused = 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. - lastnr=0; - //power to SD reader - #if SDPOWER > -1 - SET_OUTPUT(SDPOWER); +#ifdef SDCARD_SORT_ALPHA + sort_count = 0; +#if SDSORT_GCODE + sort_alpha = true; + sort_folders = FOLDER_SORTING; + //sort_reverse = false; +#endif +#endif + + filesize = 0; + sdpos = 0; + sdprinting = false; + cardOK = false; + paused = 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. + lastnr=0; + //power to SD reader +#if SDPOWER > -1 + SET_OUTPUT(SDPOWER); WRITE(SDPOWER,HIGH); - #endif //SDPOWER - - autostart_atmillis=millis()+5000; +#endif //SDPOWER + + 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) + char *pos=buffer; + for (uint8_t i = 0; i < 11; i++) { - *pos++='.'; + if (p.name[i] == ' ')continue; + if (i == 8) + { + *pos++='.'; + } + *pos++=p.name[i]; } - *pos++=p.name[i]; - } - *pos++=0; - return buffer; + *pos++=0; + return buffer; } /** @@ -68,225 +68,230 @@ char *createFilename(char *buffer,const dir_t &p) //buffer>12characters +*/ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) { - dir_t p; - uint8_t cnt = 0; - // Read the next entry from a directory - while (parent.readDir(p, longFilename) > 0) { - // If the entry is a directory and the action is LS_SerialPrint - if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { - // Get the short name for the item, which we know is a folder - char lfilename[FILENAME_LENGTH]; - createFilename(lfilename, p); - // Allocate enough stack space for the full path to a folder, trailing slash, and nul - bool prepend_is_empty = (prepend[0] == '\0'); - int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(lfilename) + 1 + 1; - char path[len]; - // Append the FOLDERNAME12/ to the passed string. - // It contains the full path to the "parent" argument. - // We now have the full path to the item in this folder. - strcpy(path, prepend_is_empty ? "/" : prepend); // root slash if prepend is empty - strcat(path, lfilename); // FILENAME_LENGTH-1 characters maximum - strcat(path, "/"); // 1 character - // Serial.print(path); - // Get a new directory object using the full path - // and dive recursively into it. - SdFile dir; - if (!dir.open(parent, lfilename, O_READ)) { - if (lsAction == LS_SerialPrint) { - //SERIAL_ECHO_START(); - //SERIAL_ECHOPGM(_i("Cannot open subdir"));////MSG_SD_CANT_OPEN_SUBDIR c=0 r=0 - //SERIAL_ECHOLN(lfilename); - } - } - lsDive(path, dir); - // close() is done automatically by destructor of SdFile - } - else { - uint8_t pn0 = p.name[0]; - if (pn0 == DIR_NAME_FREE) break; - if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue; - if (longFilename[0] == '.') continue; - if (!DIR_IS_FILE_OR_SUBDIR(&p) || (p.attributes & DIR_ATT_HIDDEN)) continue; - filenameIsDir = DIR_IS_SUBDIR(&p); - if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue; - switch (lsAction) { - case LS_Count: - nrFiles++; - break; - - case LS_SerialPrint: - createFilename(filename, p); - SERIAL_PROTOCOL(prepend); - SERIAL_PROTOCOL(filename); - MYSERIAL.write(' '); - SERIAL_PROTOCOLLN(p.fileSize); - break; - - case LS_GetFilename: - //SERIAL_ECHOPGM("File: "); - createFilename(filename, p); - cluster = parent.curCluster(); - position = parent.curPosition(); - /*MYSERIAL.println(filename); - SERIAL_ECHOPGM("Write date: "); - writeDate = p.lastWriteDate; - MYSERIAL.println(writeDate); - writeTime = p.lastWriteTime; - SERIAL_ECHOPGM("Creation date: "); - MYSERIAL.println(p.creationDate); - SERIAL_ECHOPGM("Access date: "); - MYSERIAL.println(p.lastAccessDate); - SERIAL_ECHOLNPGM("");*/ - creationDate = p.creationDate; - creationTime = p.creationTime; - //writeDate = p.lastAccessDate; - if (match != NULL) { - if (strcasecmp(match, filename) == 0) return; - } - else if (cnt == nrFiles) return; - cnt++; - break; - } - } - } // while readDir -} - -void CardReader::ls() + dir_t p; + uint8_t cnt = 0; + // Read the next entry from a directory + while (parent.readDir(p, longFilename) > 0) { + // If the entry is a directory and the action is LS_SerialPrint + if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { + // Get the short name for the item, which we know is a folder + char lfilename[FILENAME_LENGTH]; + createFilename(lfilename, p); + // Allocate enough stack space for the full path to a folder, trailing slash, and nul + bool prepend_is_empty = (prepend[0] == '\0'); + int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(lfilename) + 1 + 1; + char path[len]; + // Append the FOLDERNAME12/ to the passed string. + // It contains the full path to the "parent" argument. + // We now have the full path to the item in this folder. + strcpy(path, prepend_is_empty ? "/" : prepend); // root slash if prepend is empty + strcat(path, lfilename); // FILENAME_LENGTH-1 characters maximum + strcat(path, "/"); // 1 character + // Serial.print(path); + // Get a new directory object using the full path + // and dive recursively into it. + SdFile dir; + if (!dir.open(parent, lfilename, O_READ)) { + if (lsAction == LS_SerialPrint) { + //SERIAL_ECHO_START(); + //SERIAL_ECHOPGM(_i("Cannot open subdir"));////MSG_SD_CANT_OPEN_SUBDIR c=0 r=0 + //SERIAL_ECHOLN(lfilename); + } + } + lsDive(path, dir); + // close() is done automatically by destructor of SdFile + } + else { + uint8_t pn0 = p.name[0]; + if (pn0 == DIR_NAME_FREE) break; + if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue; + if (longFilename[0] == '.') continue; + if (!DIR_IS_FILE_OR_SUBDIR(&p) || (p.attributes & DIR_ATT_HIDDEN)) continue; + filenameIsDir = DIR_IS_SUBDIR(&p); + if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue; + switch (lsAction) { + case LS_Count: + nrFiles++; + break; + + case LS_SerialPrint: + createFilename(filename, p); + SERIAL_PROTOCOL(prepend); + SERIAL_PROTOCOL(filename); + MYSERIAL.write(' '); + SERIAL_PROTOCOLLN(p.fileSize); + break; + + case LS_GetFilename: + //SERIAL_ECHOPGM("File: "); + createFilename(filename, p); + cluster = parent.curCluster(); + position = parent.curPosition(); + /*MYSERIAL.println(filename); + SERIAL_ECHOPGM("Write date: "); + writeDate = p.lastWriteDate; + MYSERIAL.println(writeDate); + writeTime = p.lastWriteTime; + SERIAL_ECHOPGM("Creation date: "); + MYSERIAL.println(p.creationDate); + SERIAL_ECHOPGM("Access date: "); + MYSERIAL.println(p.lastAccessDate); + SERIAL_ECHOLNPGM("");*/ + creationDate = p.creationDate; + creationTime = p.creationTime; + //writeDate = p.lastAccessDate; + if (match != NULL) { + if (strcasecmp(match, filename) == 0) return; + } + else if (cnt == nrFiles) return; + cnt++; + break; + } + } + } // while readDir +} + +void CardReader::ls() { - lsAction=LS_SerialPrint; - //if(lsAction==LS_Count) - //nrFiles=0; + lsAction=LS_SerialPrint; + //if(lsAction==LS_Count) + //nrFiles=0; - root.rewind(); - lsDive("",root); + root.rewind(); + lsDive("",root); } void CardReader::initsd() { - cardOK = false; - if(root.isOpen()) - root.close(); + 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 - ) + 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) - #endif - ) -#endif - { - //if (!card.init(SPI_HALF_SPEED,SDSS)) - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM(_i("SD init fail"));////MSG_SD_INIT_FAIL c=0 r=0 - } - else if (!volume.init(&card)) - { - SERIAL_ERROR_START; - SERIAL_ERRORLNRPGM(_i("volume.init failed"));////MSG_SD_VOL_INIT_FAIL c=0 r=0 - } - else if (!root.openRoot(&volume)) - { - SERIAL_ERROR_START; - SERIAL_ERRORLNRPGM(_i("openRoot failed"));////MSG_SD_OPENROOT_FAIL c=0 r=0 - } - else - { - cardOK = true; - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM(_i("SD card ok"));////MSG_SD_CARD_OK c=0 r=0 - } - workDir=root; - curDir=&root; - - #ifdef SDCARD_SORT_ALPHA - presort(); - #endif - - /* - if(!workDir.openRoot(&volume)) - { - SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL); - } - */ - + if (!card.init(SPI_FULL_SPEED,SDSS) +#if defined(LCD_SDSS) && (LCD_SDSS != SDSS) + && !card.init(SPI_FULL_SPEED,LCD_SDSS) +#endif + ) +#endif + { + //if (!card.init(SPI_HALF_SPEED,SDSS)) + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(_i("SD init fail"));////MSG_SD_INIT_FAIL c=0 r=0 + } + else if (!volume.init(&card)) + { + SERIAL_ERROR_START; + SERIAL_ERRORLNRPGM(_i("volume.init failed"));////MSG_SD_VOL_INIT_FAIL c=0 r=0 + } + else if (!root.openRoot(&volume)) + { + SERIAL_ERROR_START; + SERIAL_ERRORLNRPGM(_i("openRoot failed"));////MSG_SD_OPENROOT_FAIL c=0 r=0 + } + else + { + cardOK = true; + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(_i("SD card ok"));////MSG_SD_CARD_OK c=0 r=0 + } + workDir=root; + curDir=&root; + +#ifdef SDCARD_SORT_ALPHA + presort(); +#endif + + /* + if(!workDir.openRoot(&volume)) + { + SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL); + } + */ + } void CardReader::setroot() { - /*if(!workDir.openRoot(&volume)) - { - SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL); - }*/ - workDir=root; - - curDir=&workDir; - #ifdef SDCARD_SORT_ALPHA - presort(); - #endif + /*if(!workDir.openRoot(&volume)) + { + SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL); + }*/ + workDir=root; + + curDir=&workDir; +#ifdef SDCARD_SORT_ALPHA + presort(); +#endif } void CardReader::release() { - sdprinting = false; - cardOK = false; + sdprinting = false; + cardOK = false; } void CardReader::startFileprint() { - if(cardOK) - { - sdprinting = true; - paused = false; - #ifdef SDCARD_SORT_ALPHA - //flush_presort(); - #endif - } + if(cardOK) + { + sdprinting = true; + paused = false; +#ifdef SDCARD_SORT_ALPHA + //flush_presort(); +#endif + } } void CardReader::pauseSDPrint() { - if(sdprinting) - { - sdprinting = false; - paused = true; - } + if(sdprinting) + { + sdprinting = false; + paused = true; + } } void CardReader::openLogFile(const char* name) { - logging = true; - openFile(name, false); + logging = true; + openFile(name, false); } void CardReader::getDirName(char* name, uint8_t level) -{ - workDirParents[level].getFilename(name); +{ + workDirParents[level].getFilename(name); } uint16_t CardReader::getWorkDirDepth() { - return workDirDepth; + return workDirDepth; } void CardReader::getAbsFilename(char *t) { - uint8_t cnt=0; - *t='/';t++;cnt++; - for(uint8_t i=0;i(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("", 1); - 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 + if(!cardOK) + return; + if(file.isOpen()) //replacing current file by new file, or subfile call { - SERIAL_ECHO_START; - SERIAL_ECHOPGM("Now doing file: "); - SERIAL_ECHOLN(name); + if(!replace_current) + { + if((int)file_subcall_ctr>(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("", 1); + 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(); } - 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; - paused = false; - - - SdFile myDir; - const char *fname=name; - diveSubfolder(fname,myDir); - - if(read) - { - if (file.open(curDir, fname, O_READ)) + else //opening fresh file { - filesize = file.fileSize(); - SERIAL_PROTOCOLRPGM(_N("File opened: "));////MSG_SD_FILE_OPENED c=0 r=0 - SERIAL_PROTOCOL(fname); - SERIAL_PROTOCOLRPGM(_n(" Size: "));////MSG_SD_SIZE c=0 r=0 - SERIAL_PROTOCOLLN(filesize); - sdpos = 0; - - SERIAL_PROTOCOLLNRPGM(_N("File selected"));////MSG_SD_FILE_SELECTED c=0 r=0 - getfilename(0, fname); - lcd_setstatus(longFilename[0] ? longFilename : fname); - lcd_setstatus("SD-PRINTING "); + 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); } - else - { - SERIAL_PROTOCOLRPGM(_T(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)) + sdprinting = false; + paused = false; + + + SdFile myDir; + const char *fname=name; + diveSubfolder(fname,myDir); + + if(read) { - SERIAL_PROTOCOLRPGM(_T(MSG_SD_OPEN_FILE_FAIL)); - SERIAL_PROTOCOL(fname); - SERIAL_PROTOCOLLNPGM("."); + if (file.open(curDir, fname, O_READ)) + { + filesize = file.fileSize(); + SERIAL_PROTOCOLRPGM(_N("File opened: "));////MSG_SD_FILE_OPENED c=0 r=0 + SERIAL_PROTOCOL(fname); + SERIAL_PROTOCOLRPGM(_n(" Size: "));////MSG_SD_SIZE c=0 r=0 + SERIAL_PROTOCOLLN(filesize); + sdpos = 0; + + SERIAL_PROTOCOLLNRPGM(_N("File selected"));////MSG_SD_FILE_SELECTED c=0 r=0 + getfilename(0, fname); + lcd_setstatus(longFilename[0] ? longFilename : fname); + lcd_setstatus("SD-PRINTING "); + } + else + { + SERIAL_PROTOCOLRPGM(_T(MSG_SD_OPEN_FILE_FAIL)); + SERIAL_PROTOCOL(fname); + SERIAL_PROTOCOLLNPGM("."); + } } else - { - saving = true; - SERIAL_PROTOCOLRPGM(_N("Writing to file: "));////MSG_SD_WRITE_TO_FILE c=0 r=0 - SERIAL_PROTOCOLLN(name); - lcd_setstatus(fname); + { //write + if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) + { + SERIAL_PROTOCOLRPGM(_T(MSG_SD_OPEN_FILE_FAIL)); + SERIAL_PROTOCOL(fname); + SERIAL_PROTOCOLLNPGM("."); + } + else + { + saving = true; + SERIAL_PROTOCOLRPGM(_N("Writing to file: "));////MSG_SD_WRITE_TO_FILE c=0 r=0 + SERIAL_PROTOCOLLN(name); + lcd_setstatus(fname); + } } - } - + } void CardReader::removeFile(const char* name) @@ -465,231 +470,231 @@ void CardReader::removeFile(const char* name) const char *fname=name; diveSubfolder(fname,myDir); - if (file.remove(curDir, fname)) + if (file.remove(curDir, fname)) { - SERIAL_PROTOCOLPGM("File deleted:"); - SERIAL_PROTOCOLLN(fname); - sdpos = 0; - #ifdef SDCARD_SORT_ALPHA - presort(); - #endif + SERIAL_PROTOCOLPGM("File deleted:"); + SERIAL_PROTOCOLLN(fname); + sdpos = 0; +#ifdef SDCARD_SORT_ALPHA + presort(); +#endif } else { - SERIAL_PROTOCOLPGM("Deletion failed, File: "); - SERIAL_PROTOCOL(fname); - SERIAL_PROTOCOLLNPGM("."); + SERIAL_PROTOCOLPGM("Deletion failed, File: "); + SERIAL_PROTOCOL(fname); + SERIAL_PROTOCOLLNPGM("."); } - + } uint32_t CardReader::getFileSize() { - return filesize; + return filesize; } void CardReader::getStatus() { - if(sdprinting){ - SERIAL_PROTOCOL(longFilename); - SERIAL_PROTOCOLPGM("\n"); - SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE c=0 r=0 - SERIAL_PROTOCOL(sdpos); - SERIAL_PROTOCOLPGM("/"); - SERIAL_PROTOCOLLN(filesize); - uint16_t time = millis()/60000 - starttime/60000; - SERIAL_PROTOCOL(itostr2(time/60)); - SERIAL_PROTOCOL(':'); - SERIAL_PROTOCOL(itostr2(time%60)); - SERIAL_PROTOCOLPGM("\n"); - } - else if (paused) { - SERIAL_PROTOCOLLNPGM("SD print paused"); - } - else if (saved_printing) { - SERIAL_PROTOCOLLNPGM("Print saved"); - } - else { - SERIAL_PROTOCOLLNPGM("Not SD printing"); - } + if(sdprinting) { + SERIAL_PROTOCOL(longFilename); + SERIAL_PROTOCOLPGM("\n"); + SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE c=0 r=0 + SERIAL_PROTOCOL(sdpos); + SERIAL_PROTOCOLPGM("/"); + SERIAL_PROTOCOLLN(filesize); + uint16_t time = millis()/60000 - starttime/60000; + SERIAL_PROTOCOL(itostr2(time/60)); + SERIAL_PROTOCOL(':'); + SERIAL_PROTOCOL(itostr2(time%60)); + SERIAL_PROTOCOLPGM("\n"); + } + else if (paused) { + SERIAL_PROTOCOLLNPGM("SD print paused"); + } + else if (saved_printing) { + SERIAL_PROTOCOLLNPGM("Print saved"); + } + else { + SERIAL_PROTOCOLLNPGM("Not SD printing"); + } } 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) - { - begin = strchr(npos, ' ') + 1; - end = strchr(npos, '*') - 1; - } - end[1] = '\r'; - end[2] = '\n'; - end[3] = '\0'; - file.write(begin); - if (file.writeError) - { - SERIAL_ERROR_START; - SERIAL_ERRORLNRPGM(_T(MSG_SD_ERR_WRITE_TO_FILE)); - } + char* begin = buf; + char* npos = 0; + char* end = buf + strlen(buf) - 1; + + file.writeError = false; + if((npos = strchr(buf, 'N')) != NULL) + { + begin = strchr(npos, ' ') + 1; + end = strchr(npos, '*') - 1; + } + end[1] = '\r'; + end[2] = '\n'; + end[3] = '\0'; + file.write(begin); + if (file.writeError) + { + SERIAL_ERROR_START; + SERIAL_ERRORLNRPGM(_T(MSG_SD_ERR_WRITE_TO_FILE)); + } } #define CHUNK_SIZE 64 void CardReader::write_command_no_newline(char *buf) { - file.write(buf, CHUNK_SIZE); - if (file.writeError) - { - SERIAL_ERROR_START; - SERIAL_ERRORLNRPGM(_T(MSG_SD_ERR_WRITE_TO_FILE)); - MYSERIAL.println("An error while writing to the SD Card."); - } + file.write(buf, CHUNK_SIZE); + if (file.writeError) + { + SERIAL_ERROR_START; + SERIAL_ERRORLNRPGM(_T(MSG_SD_ERR_WRITE_TO_FILE)); + MYSERIAL.println("An error while writing to the SD Card."); + } } void CardReader::checkautostart(bool force) { - if(!force) - { - if(!autostart_stilltocheck) - return; - if(autostart_atmillis 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) + if(!force) { - char cmd[30]; - // M23: Select SD file - sprintf_P(cmd, PSTR("M23 %s"), autoname); - enquecommand(cmd); - // M24: Start/resume SD print - enquecommand_P(PSTR("M24")); - found=true; + if(!autostart_stilltocheck) + return; + if(autostart_atmillis 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]; + // M23: Select SD file + sprintf_P(cmd, PSTR("M23 %s"), autoname); + enquecommand(cmd); + // M24: Start/resume SD print + enquecommand_P(PSTR("M24")); + found=true; + } + } + if(!found) + lastnr=-1; + else + lastnr++; } 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 continuing a stopped print - // so one can unplug the printer and continue printing the next day. - - } + file.sync(); + file.close(); + saving = false; + 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; - curDir->rewind(); - lsDive("",*curDir,match); - + curDir=&workDir; + lsAction=LS_GetFilename; + nrFiles=nr; + curDir->rewind(); + lsDive("",*curDir,match); + } void CardReader::getfilename_simple(uint32_t position, const char * const match/*=NULL*/) { - curDir = &workDir; - lsAction = LS_GetFilename; - nrFiles = 0; - curDir->seekSet(position); - lsDive("", *curDir, match); + curDir = &workDir; + lsAction = LS_GetFilename; + nrFiles = 0; + curDir->seekSet(position); + lsDive("", *curDir, match); } uint16_t CardReader::getnrfilenames() { - curDir=&workDir; - lsAction=LS_Count; - nrFiles=0; - curDir->rewind(); - lsDive("",*curDir); - //SERIAL_ECHOLN(nrFiles); - return nrFiles; + curDir=&workDir; + lsAction=LS_Count; + nrFiles=0; + curDir->rewind(); + lsDive("",*curDir); + //SERIAL_ECHOLN(nrFiles); + return nrFiles; } 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_ECHORPGM(_i("Cannot enter subdir: "));////MSG_SD_CANT_ENTER_SUBDIR c=0 r=0 - SERIAL_ECHOLN(relpath); - } - else - { - if (workDirDepth < MAX_DIR_DEPTH) { - for (int d = ++workDirDepth; d--;) - workDirParents[d+1] = workDirParents[d]; - workDirParents[0]=*parent; - } - workDir=newfile; - #ifdef SDCARD_SORT_ALPHA - presort(); - #endif - } + SdFile newfile; + SdFile *parent=&root; + + if(workDir.isOpen()) + parent=&workDir; + + if(!newfile.open(*parent,relpath, O_READ)) + { + SERIAL_ECHO_START; + SERIAL_ECHORPGM(_i("Cannot enter subdir: "));////MSG_SD_CANT_ENTER_SUBDIR c=0 r=0 + SERIAL_ECHOLN(relpath); + } + else + { + if (workDirDepth < MAX_DIR_DEPTH) { + for (int d = ++workDirDepth; d--;) + workDirParents[d+1] = workDirParents[d]; + workDirParents[0]=*parent; + } + workDir=newfile; +#ifdef SDCARD_SORT_ALPHA + presort(); +#endif + } } void CardReader::updir() { - if(workDirDepth > 0) - { - --workDirDepth; - workDir = workDirParents[0]; - for (unsigned int d = 0; d < workDirDepth; d++) + if(workDirDepth > 0) { - workDirParents[d] = workDirParents[d+1]; + --workDirDepth; + workDir = workDirParents[0]; + for (unsigned int d = 0; d < workDirDepth; d++) + { + workDirParents[d] = workDirParents[d+1]; + } +#ifdef SDCARD_SORT_ALPHA + presort(); +#endif } - #ifdef SDCARD_SORT_ALPHA - presort(); - #endif - } } #ifdef SDCARD_SORT_ALPHA @@ -698,12 +703,12 @@ void CardReader::updir() * Get the name of a file in the current directory by sort-index */ void CardReader::getfilename_sorted(const uint16_t nr) { - getfilename( - #if SDSORT_GCODE - sort_alpha && - #endif - (nr < sort_count) ? sort_order[nr] : nr - ); + getfilename( +#if SDSORT_GCODE + sort_alpha && +#endif + (nr < sort_count) ? sort_order[nr] : nr + ); } /** @@ -715,269 +720,269 @@ void CardReader::getfilename_sorted(const uint16_t nr) { * - Most RAM: Buffer the directory and return filenames from RAM */ void CardReader::presort() { - if (farm_mode || IS_SD_INSERTED == false) return; //sorting is not used in farm mode - uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT); - - if (sdSort == SD_SORT_NONE) return; //sd sort is turned off - - #if SDSORT_GCODE - if (!sort_alpha) return; - #endif - KEEPALIVE_STATE(IN_HANDLER); - - // Throw away old sort index - flush_presort(); - - // If there are files, sort up to the limit - uint16_t fileCnt = getnrfilenames(); - if (fileCnt > 0) { - - // Never sort more than the max allowed - // If you use folders to organize, 20 may be enough - if (fileCnt > SDSORT_LIMIT) { - lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=4 - fileCnt = SDSORT_LIMIT; - } - lcd_clear(); - #if !SDSORT_USES_RAM - lcd_set_progress(); - #endif - lcd_puts_at_P(0, 1, _i("Sorting files"));////MSG_SORTING c=20 r=1 - - // Sort order is always needed. May be static or dynamic. - #if SDSORT_DYNAMIC_RAM - sort_order = new uint8_t[fileCnt]; - #endif - - // Use RAM to store the entire directory during pre-sort. - // SDSORT_LIMIT should be set to prevent over-allocation. - #if SDSORT_USES_RAM - - // If using dynamic ram for names, allocate on the heap. - #if SDSORT_CACHE_NAMES - #if SDSORT_DYNAMIC_RAM - sortshort = new char*[fileCnt]; - sortnames = new char*[fileCnt]; - #endif - #elif SDSORT_USES_STACK - char sortnames[fileCnt][LONG_FILENAME_LENGTH]; - uint16_t creation_time[fileCnt]; - uint16_t creation_date[fileCnt]; - #endif - - // Folder sorting needs 1 bit per entry for flags. - #if HAS_FOLDER_SORTING - #if SDSORT_DYNAMIC_RAM - isDir = new uint8_t[(fileCnt + 7) >> 3]; - #elif SDSORT_USES_STACK - uint8_t isDir[(fileCnt + 7) >> 3]; - #endif - #endif - - #else // !SDSORT_USES_RAM - - uint32_t positions[fileCnt]; - - // By default re-read the names from SD for every compare - // retaining only two filenames at a time. This is very - // slow but is safest and uses minimal RAM. - char name1[LONG_FILENAME_LENGTH + 1]; - uint16_t creation_time_bckp; - uint16_t creation_date_bckp; - - #endif - position = 0; - if (fileCnt > 1) { - // Init sort order. - for (uint16_t i = 0; i < fileCnt; i++) { - if (!IS_SD_INSERTED) return; - manage_heater(); - sort_order[i] = i; - positions[i] = position; - getfilename(i); - // If using RAM then read all filenames now. - #if SDSORT_USES_RAM - getfilename(i); - #if SDSORT_DYNAMIC_RAM - // Use dynamic method to copy long filename - sortnames[i] = strdup(LONGEST_FILENAME); - #if SDSORT_CACHE_NAMES - // When caching also store the short name, since - // we're replacing the getfilename() behavior. - sortshort[i] = strdup(filename); - #endif - #else - // Copy filenames into the static array - strcpy(sortnames[i], LONGEST_FILENAME); - creation_time[i] = creationTime; - creation_date[i] = creationDate; - #if SDSORT_CACHE_NAMES - strcpy(sortshort[i], filename); - #endif - #endif - // char out[30]; - // sprintf_P(out, PSTR("---- %i %s %s"), i, filenameIsDir ? "D" : " ", sortnames[i]); - // SERIAL_ECHOLN(out); - #if HAS_FOLDER_SORTING - const uint16_t bit = i & 0x07, ind = i >> 3; - if (bit == 0) isDir[ind] = 0x00; - if (filenameIsDir) isDir[ind] |= _BV(bit); - #endif - #endif - } + if (farm_mode || IS_SD_INSERTED == false) return; //sorting is not used in farm mode + uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT); + + if (sdSort == SD_SORT_NONE) return; //sd sort is turned off + +#if SDSORT_GCODE + if (!sort_alpha) return; +#endif + KEEPALIVE_STATE(IN_HANDLER); + + // Throw away old sort index + flush_presort(); + + // If there are files, sort up to the limit + uint16_t fileCnt = getnrfilenames(); + if (fileCnt > 0) { + + // Never sort more than the max allowed + // If you use folders to organize, 20 may be enough + if (fileCnt > SDSORT_LIMIT) { + lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=4 + fileCnt = SDSORT_LIMIT; + } + lcd_clear(); +#if !SDSORT_USES_RAM + lcd_set_progress(); +#endif + lcd_puts_at_P(0, 1, _i("Sorting files"));////MSG_SORTING c=20 r=1 + + // Sort order is always needed. May be static or dynamic. +#if SDSORT_DYNAMIC_RAM + sort_order = new uint8_t[fileCnt]; +#endif + + // Use RAM to store the entire directory during pre-sort. + // SDSORT_LIMIT should be set to prevent over-allocation. +#if SDSORT_USES_RAM + + // If using dynamic ram for names, allocate on the heap. +#if SDSORT_CACHE_NAMES +#if SDSORT_DYNAMIC_RAM + sortshort = new char*[fileCnt]; + sortnames = new char*[fileCnt]; +#endif +#elif SDSORT_USES_STACK + char sortnames[fileCnt][LONG_FILENAME_LENGTH]; + uint16_t creation_time[fileCnt]; + uint16_t creation_date[fileCnt]; +#endif + + // Folder sorting needs 1 bit per entry for flags. +#if HAS_FOLDER_SORTING +#if SDSORT_DYNAMIC_RAM + isDir = new uint8_t[(fileCnt + 7) >> 3]; +#elif SDSORT_USES_STACK + uint8_t isDir[(fileCnt + 7) >> 3]; +#endif +#endif + +#else // !SDSORT_USES_RAM + + uint32_t positions[fileCnt]; + + // By default re-read the names from SD for every compare + // retaining only two filenames at a time. This is very + // slow but is safest and uses minimal RAM. + char name1[LONG_FILENAME_LENGTH + 1]; + uint16_t creation_time_bckp; + uint16_t creation_date_bckp; + +#endif + position = 0; + if (fileCnt > 1) { + // Init sort order. + for (uint16_t i = 0; i < fileCnt; i++) { + if (!IS_SD_INSERTED) return; + manage_heater(); + sort_order[i] = i; + positions[i] = position; + getfilename(i); + // If using RAM then read all filenames now. +#if SDSORT_USES_RAM + getfilename(i); +#if SDSORT_DYNAMIC_RAM + // Use dynamic method to copy long filename + sortnames[i] = strdup(LONGEST_FILENAME); +#if SDSORT_CACHE_NAMES + // When caching also store the short name, since + // we're replacing the getfilename() behavior. + sortshort[i] = strdup(filename); +#endif +#else + // Copy filenames into the static array + strcpy(sortnames[i], LONGEST_FILENAME); + creation_time[i] = creationTime; + creation_date[i] = creationDate; +#if SDSORT_CACHE_NAMES + strcpy(sortshort[i], filename); +#endif +#endif + // char out[30]; + // sprintf_P(out, PSTR("---- %i %s %s"), i, filenameIsDir ? "D" : " ", sortnames[i]); + // SERIAL_ECHOLN(out); +#if HAS_FOLDER_SORTING + const uint16_t bit = i & 0x07, ind = i >> 3; + if (bit == 0) isDir[ind] = 0x00; + if (filenameIsDir) isDir[ind] |= _BV(bit); +#endif +#endif + } #ifdef QUICKSORT - quicksort(0, fileCnt - 1); + quicksort(0, fileCnt - 1); #else //Qicksort not defined, use Bubble Sort - uint32_t counter = 0; - uint16_t total = 0.5*(fileCnt - 1)*(fileCnt); + uint32_t counter = 0; + uint16_t total = 0.5*(fileCnt - 1)*(fileCnt); - // Compare names from the array or just the two buffered names - #if SDSORT_USES_RAM - #define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0) - #define _SORT_CMP_TIME_NODIR() (((creation_date[o1] == creation_date[o2]) && (creation_time[o1] < creation_time[o2])) || \ + // Compare names from the array or just the two buffered names +#if SDSORT_USES_RAM +#define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0) +#define _SORT_CMP_TIME_NODIR() (((creation_date[o1] == creation_date[o2]) && (creation_time[o1] < creation_time[o2])) || \ (creation_date[o1] < creation_date [o2])) - #else - #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0) //true if lowercase(name1) > lowercase(name2) - #define _SORT_CMP_TIME_NODIR() (((creation_date_bckp == creationDate) && (creation_time_bckp > creationTime)) || \ +#else +#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0) //true if lowercase(name1) > lowercase(name2) +#define _SORT_CMP_TIME_NODIR() (((creation_date_bckp == creationDate) && (creation_time_bckp > creationTime)) || \ (creation_date_bckp > creationDate)) - #endif +#endif - #if HAS_FOLDER_SORTING - #if SDSORT_USES_RAM - // Folder sorting needs an index and bit to test for folder-ness. - const uint8_t ind1 = o1 >> 3, bit1 = o1 & 0x07, - ind2 = o2 >> 3, bit2 = o2 & 0x07; - #define _SORT_CMP_DIR(fs) \ +#if HAS_FOLDER_SORTING +#if SDSORT_USES_RAM + // Folder sorting needs an index and bit to test for folder-ness. + const uint8_t ind1 = o1 >> 3, bit1 = o1 & 0x07, + ind2 = o2 >> 3, bit2 = o2 & 0x07; +#define _SORT_CMP_DIR(fs) \ (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \ ? _SORT_CMP_NODIR() \ : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0) - #define _SORT_CMP_TIME_DIR(fs) \ +#define _SORT_CMP_TIME_DIR(fs) \ (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \ ? _SORT_CMP_TIME_NODIR() \ : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0) - #else - #define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1)) - #define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1)) - #endif - #endif - - for (uint16_t i = fileCnt; --i;) { - if (!IS_SD_INSERTED) return; - bool didSwap = false; - - #if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used - int8_t percent = (counter * 100) / total;//((counter * 100) / pow((fileCnt-1),2)); - for (int column = 0; column < 20; column++) { - if (column < (percent / 5)) - { - lcd_set_cursor(column, 2); - lcd_print('\x01'); //simple progress bar - } - } - counter++; - #endif - - //MYSERIAL.println(int(i)); - for (uint16_t j = 0; j < i; ++j) { - if (!IS_SD_INSERTED) return; - manage_heater(); - const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1]; - - // The most economical method reads names as-needed - // throughout the loop. Slow if there are many. - #if !SDSORT_USES_RAM - counter++; - getfilename_simple(positions[o1]); - strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) - creation_date_bckp = creationDate; - creation_time_bckp = creationTime; - #if HAS_FOLDER_SORTING - bool dir1 = filenameIsDir; - #endif - getfilename_simple(positions[o2]); - char *name2 = LONGEST_FILENAME; // use the string in-place - - #endif // !SDSORT_USES_RAM - - // Sort the current pair according to settings. - if ( - #if HAS_FOLDER_SORTING - (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_DIR(FOLDER_SORTING)) - #else - (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_NODIR()) - #endif - ) - { - sort_order[j] = o2; - sort_order[j + 1] = o1; - didSwap = true; - } - } - if (!didSwap) break; - } //end of bubble sort loop -#endif - // Using RAM but not keeping names around - #if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES) - #if SDSORT_DYNAMIC_RAM - for (uint16_t i = 0; i < fileCnt; ++i) free(sortnames[i]); - #if HAS_FOLDER_SORTING - free(isDir); - #endif - #endif - #endif - } - else { - sort_order[0] = 0; - #if (SDSORT_USES_RAM && SDSORT_CACHE_NAMES) - getfilename(0); - #if SDSORT_DYNAMIC_RAM - sortnames = new char*[1]; - sortnames[0] = strdup(LONGEST_FILENAME); // malloc - sortshort = new char*[1]; - sortshort[0] = strdup(filename); // malloc - isDir = new uint8_t[1]; - #else - strcpy(sortnames[0], LONGEST_FILENAME); - strcpy(sortshort[0], filename); - #endif - isDir[0] = filenameIsDir ? 0x01 : 0x00; - #endif - } - - sort_count = fileCnt; - } +#else +#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1)) +#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1)) +#endif +#endif + + for (uint16_t i = fileCnt; --i;) { + if (!IS_SD_INSERTED) return; + bool didSwap = false; + #if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used - for (int column = 0; column <= 19; column++) - { - lcd_set_cursor(column, 2); - lcd_print('\x01'); //simple progress bar - } - delay(300); - lcd_set_degree(); - lcd_clear(); + int8_t percent = (counter * 100) / total;//((counter * 100) / pow((fileCnt-1),2)); + for (int column = 0; column < 20; column++) { + if (column < (percent / 5)) + { + lcd_set_cursor(column, 2); + lcd_print('\x01'); //simple progress bar + } + } + counter++; +#endif + + //MYSERIAL.println(int(i)); + for (uint16_t j = 0; j < i; ++j) { + if (!IS_SD_INSERTED) return; + manage_heater(); + const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1]; + + // The most economical method reads names as-needed + // throughout the loop. Slow if there are many. +#if !SDSORT_USES_RAM + counter++; + getfilename_simple(positions[o1]); + strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) + creation_date_bckp = creationDate; + creation_time_bckp = creationTime; +#if HAS_FOLDER_SORTING + bool dir1 = filenameIsDir; #endif - lcd_update(2); - KEEPALIVE_STATE(NOT_BUSY); - lcd_timeoutToStatus.start(); + getfilename_simple(positions[o2]); + char *name2 = LONGEST_FILENAME; // use the string in-place + +#endif // !SDSORT_USES_RAM + + // Sort the current pair according to settings. + if ( +#if HAS_FOLDER_SORTING + (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_DIR(FOLDER_SORTING)) +#else + (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_NODIR()) +#endif + ) + { + sort_order[j] = o2; + sort_order[j + 1] = o1; + didSwap = true; + } + } + if (!didSwap) break; + } //end of bubble sort loop +#endif + // Using RAM but not keeping names around +#if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES) +#if SDSORT_DYNAMIC_RAM + for (uint16_t i = 0; i < fileCnt; ++i) free(sortnames[i]); +#if HAS_FOLDER_SORTING + free(isDir); +#endif +#endif +#endif + } + else { + sort_order[0] = 0; +#if (SDSORT_USES_RAM && SDSORT_CACHE_NAMES) + getfilename(0); +#if SDSORT_DYNAMIC_RAM + sortnames = new char*[1]; + sortnames[0] = strdup(LONGEST_FILENAME); // malloc + sortshort = new char*[1]; + sortshort[0] = strdup(filename); // malloc + isDir = new uint8_t[1]; +#else + strcpy(sortnames[0], LONGEST_FILENAME); + strcpy(sortshort[0], filename); +#endif + isDir[0] = filenameIsDir ? 0x01 : 0x00; +#endif + } + + sort_count = fileCnt; + } +#if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used + for (int column = 0; column <= 19; column++) + { + lcd_set_cursor(column, 2); + lcd_print('\x01'); //simple progress bar + } + delay(300); + lcd_set_degree(); + lcd_clear(); +#endif + lcd_update(2); + KEEPALIVE_STATE(NOT_BUSY); + lcd_timeoutToStatus.start(); } void CardReader::flush_presort() { - if (sort_count > 0) { - #if SDSORT_DYNAMIC_RAM - delete sort_order; - #if SDSORT_CACHE_NAMES - for (uint8_t i = 0; i < sort_count; ++i) { - free(sortshort[i]); // strdup - free(sortnames[i]); // strdup - } - delete sortshort; - delete sortnames; - #endif - #endif - sort_count = 0; - } + if (sort_count > 0) { +#if SDSORT_DYNAMIC_RAM + delete sort_order; +#if SDSORT_CACHE_NAMES + for (uint8_t i = 0; i < sort_count; ++i) { + free(sortshort[i]); // strdup + free(sortnames[i]); // strdup + } + delete sortshort; + delete sortnames; +#endif +#endif + sort_count = 0; + } } #endif // SDCARD_SORT_ALPHA @@ -989,26 +994,26 @@ 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(); + 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(); - //enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); - } - autotempShutdown(); - #ifdef SDCARD_SORT_ALPHA - //presort(); - #endif + quickStop(); + file.close(); + sdprinting = false; + if(SD_FINISHED_STEPPERRELEASE) + { + finishAndDisableSteppers(); + //enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); + } + autotempShutdown(); +#ifdef SDCARD_SORT_ALPHA + //presort(); +#endif } } diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h index f287a44f4b..a1e75908fc 100755 --- a/Firmware/cardreader.h +++ b/Firmware/cardreader.h @@ -10,162 +10,192 @@ enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename}; class CardReader { public: - CardReader(); - - void initsd(); - void write_command(char *buf); - void write_command_no_newline(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 openFile(const char* name,bool read,bool replace_current=true); - void openLogFile(const char* name); - void removeFile(const char* name); - void closefile(bool store_location=false); - void release(); - void startFileprint(); - void pauseSDPrint(); - uint32_t getFileSize(); - void getStatus(); - void printingHasFinished(); - - void getfilename(uint16_t nr, const char* const match=NULL); - void getfilename_simple(uint32_t position, const char * const match = NULL); - uint16_t getnrfilenames(); - - void getAbsFilename(char *t); - void getDirName(char* name, uint8_t level); - uint16_t getWorkDirDepth(); - - - void ls(); - void chdir(const char * relpath); - void updir(); - void setroot(); - - #ifdef SDCARD_SORT_ALPHA - void presort(); - #ifdef SDSORT_QUICKSORT - void swap(uint8_t left, uint8_t right); - void quicksort(uint8_t left, uint8_t right); - #endif //SDSORT_QUICKSORT - void getfilename_sorted(const uint16_t nr); - #if SDSORT_GCODE - FORCE_INLINE void setSortOn(bool b) { sort_alpha = b; presort(); } - FORCE_INLINE void setSortFolders(int i) { sort_folders = i; presort(); } - //FORCE_INLINE void setSortReverse(bool b) { sort_reverse = b; } - #endif - #endif - - 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 uint32_t get_sdpos() { if (!isFileOpen()) return 0; else return(sdpos); }; - - bool ToshibaFlashAir_isEnabled() const { return card.getFlashAirCompatible(); } - void ToshibaFlashAir_enable(bool enable) { card.setFlashAirCompatible(enable); } - bool ToshibaFlashAir_GetIP(uint8_t *ip); + CardReader(); + + void initsd(); + void write_command(char *buf); + void write_command_no_newline(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 openFile(const char* name,bool read,bool replace_current=true); + void openLogFile(const char* name); + void removeFile(const char* name); + void closefile(bool store_location=false); + void release(); + void startFileprint(); + void pauseSDPrint(); + uint32_t getFileSize(); + void getStatus(); + void printingHasFinished(); + + void getfilename(uint16_t nr, const char* const match=NULL); + void getfilename_simple(uint32_t position, const char * const match = NULL); + uint16_t getnrfilenames(); + + void getAbsFilename(char *t); + void getDirName(char* name, uint8_t level); + uint16_t getWorkDirDepth(); + + + void ls(); + void chdir(const char * relpath); + void updir(); + void setroot(); + +#ifdef SDCARD_SORT_ALPHA + void presort(); +#ifdef SDSORT_QUICKSORT + void swap(uint8_t left, uint8_t right); + void quicksort(uint8_t left, uint8_t right); +#endif //SDSORT_QUICKSORT + void getfilename_sorted(const uint16_t nr); +#if SDSORT_GCODE + FORCE_INLINE void setSortOn(bool b) { + sort_alpha = b; + presort(); + } + FORCE_INLINE void setSortFolders(int i) { + sort_folders = i; + presort(); + } + //FORCE_INLINE void setSortReverse(bool b) { sort_reverse = b; } +#endif +#endif + + 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 uint32_t get_sdpos() { + if (!isFileOpen()) return 0; + else return(sdpos); + }; + + bool ToshibaFlashAir_isEnabled() const { + return card.getFlashAirCompatible(); + } + void ToshibaFlashAir_enable(bool enable) { + card.setFlashAirCompatible(enable); + } + bool ToshibaFlashAir_GetIP(uint8_t *ip); public: - bool saving; - bool logging; - bool sdprinting ; - bool cardOK ; - bool paused ; - char filename[13]; - uint16_t creationTime, creationDate; - uint32_t cluster, position; - char longFilename[LONG_FILENAME_LENGTH]; - bool filenameIsDir; - int lastnr; //last number of the autostart; + bool saving; + bool logging; + bool sdprinting ; + bool cardOK ; + bool paused ; + char filename[13]; + uint16_t creationTime, creationDate; + uint32_t cluster, position; + char longFilename[LONG_FILENAME_LENGTH]; + bool filenameIsDir; + int lastnr; //last number of the autostart; private: - SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH]; - uint16_t workDirDepth; + SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH]; + uint16_t workDirDepth; - // Sort files and folders alphabetically. + // Sort files and folders alphabetically. #ifdef SDCARD_SORT_ALPHA - uint16_t sort_count; // Count of sorted items in the current directory - #if SDSORT_GCODE - bool sort_alpha; // Flag to enable / disable the feature - int sort_folders; // Flag to enable / disable folder sorting - //bool sort_reverse; // Flag to enable / disable reverse sorting - #endif - - // By default the sort index is static - #if SDSORT_DYNAMIC_RAM - uint8_t *sort_order; - #else - uint8_t sort_order[SDSORT_LIMIT]; - #endif - // Cache filenames to speed up SD menus. - #if SDSORT_USES_RAM - - // If using dynamic ram for names, allocate on the heap. - #if SDSORT_CACHE_NAMES - #if SDSORT_DYNAMIC_RAM - char **sortshort, **sortnames; - #else - char sortshort[SDSORT_LIMIT][FILENAME_LENGTH]; - char sortnames[SDSORT_LIMIT][FILENAME_LENGTH]; - #endif - #elif !SDSORT_USES_STACK + uint16_t sort_count; // Count of sorted items in the current directory +#if SDSORT_GCODE + bool sort_alpha; // Flag to enable / disable the feature + int sort_folders; // Flag to enable / disable folder sorting + //bool sort_reverse; // Flag to enable / disable reverse sorting +#endif + + // By default the sort index is static +#if SDSORT_DYNAMIC_RAM + uint8_t *sort_order; +#else + uint8_t sort_order[SDSORT_LIMIT]; +#endif + // Cache filenames to speed up SD menus. +#if SDSORT_USES_RAM + + // If using dynamic ram for names, allocate on the heap. +#if SDSORT_CACHE_NAMES +#if SDSORT_DYNAMIC_RAM + char **sortshort, **sortnames; +#else + char sortshort[SDSORT_LIMIT][FILENAME_LENGTH]; + char sortnames[SDSORT_LIMIT][FILENAME_LENGTH]; +#endif +#elif !SDSORT_USES_STACK char sortnames[SDSORT_LIMIT][FILENAME_LENGTH]; uint16_t creation_time[SDSORT_LIMIT]; uint16_t creation_date[SDSORT_LIMIT]; - #endif +#endif - // Folder sorting uses an isDir array when caching items. - #if HAS_FOLDER_SORTING - #if SDSORT_DYNAMIC_RAM - uint8_t *isDir; - #elif (SDSORT_CACHE_NAMES) || !(SDSORT_USES_STACK) - uint8_t isDir[(SDSORT_LIMIT + 7) >> 3]; - #endif - #endif + // Folder sorting uses an isDir array when caching items. +#if HAS_FOLDER_SORTING +#if SDSORT_DYNAMIC_RAM + uint8_t *isDir; +#elif (SDSORT_CACHE_NAMES) || !(SDSORT_USES_STACK) + uint8_t isDir[(SDSORT_LIMIT + 7) >> 3]; +#endif +#endif - #endif // SDSORT_USES_RAM +#endif // SDSORT_USES_RAM #endif // SDCARD_SORT_ALPHA #ifdef DEBUG_SD_SPEED_TEST public: #endif //DEBUG_SD_SPEED_TEST - Sd2Card card; + Sd2Card card; private: - 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; - 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. - char* diveDirName; - - void diveSubfolder (const char *fileName, SdFile& dir); - void lsDive(const char *prepend, SdFile parent, const char * const match=NULL); + 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; + 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. + char* diveDirName; + + void diveSubfolder (const char *fileName, SdFile& dir); + void lsDive(const char *prepend, SdFile parent, const char * const match=NULL); #ifdef SDCARD_SORT_ALPHA - void flush_presort(); + void flush_presort(); #endif }; extern CardReader card; #define IS_SD_PRINTING (card.sdprinting) #if (SDCARDDETECT > -1) -# ifdef SDCARDDETECTINVERTED +# ifdef SDCARDDETECTINVERTED # define IS_SD_INSERTED (READ(SDCARDDETECT)!=0) # else # define IS_SD_INSERTED (READ(SDCARDDETECT)==0) diff --git a/Firmware/cmdqueue.cpp b/Firmware/cmdqueue.cpp index 6bb7e42f61..fe7c9e7f69 100755 --- a/Firmware/cmdqueue.cpp +++ b/Firmware/cmdqueue.cpp @@ -222,7 +222,7 @@ void cmdqueue_dump_to_serial_single_line(int nr, const char *p) SERIAL_ECHOPGM(", type: "); SERIAL_ECHO(int(*p)); SERIAL_ECHOPGM(", cmd: "); - SERIAL_ECHO(p+1); + SERIAL_ECHO(p+1); SERIAL_ECHOLNPGM(""); } @@ -312,7 +312,7 @@ void enquecommand(const char *cmd, bool from_progmem) bool cmd_buffer_empty() { - return (buflen == 0); + return (buflen == 0); } void enquecommand_front(const char *cmd, bool from_progmem) @@ -352,7 +352,7 @@ void enquecommand_front(const char *cmd, bool from_progmem) void repeatcommand_front() { cmdbuffer_front_already_processed = true; -} +} bool is_buffer_empty() { @@ -361,265 +361,265 @@ bool is_buffer_empty() } void proc_commands() { - if (buflen) - { - process_commands(); - if (!cmdbuffer_front_already_processed) - cmdqueue_pop_front(); - cmdbuffer_front_already_processed = false; - } + if (buflen) + { + process_commands(); + if (!cmdbuffer_front_already_processed) + cmdqueue_pop_front(); + cmdbuffer_front_already_processed = false; + } } void get_command() { // Test and reserve space for the new command string. if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE - 1, true)) - return; - - if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size - MYSERIAL.flush(); - SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed - } - - // start of serial line processing loop - while (MYSERIAL.available() > 0 && !saved_printing) { //is print is saved (crash detection or filament detection), dont process data from serial line - - char serial_char = MYSERIAL.read(); -/* if (selectedSerialPort == 1) - { - selectedSerialPort = 0; - MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode - selectedSerialPort = 1; - } */ //RP - removed - TimeSent = millis(); - TimeNow = millis(); - - if (serial_char < 0) - // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names - // and Marlin does not support such file names anyway. - // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading - // to a hang-up of the print process from an SD card. - continue; - if(serial_char == '\n' || - serial_char == '\r' || - serial_count >= (MAX_CMD_SIZE - 1) ) - { - if(!serial_count) { //if empty line - comment_mode = false; //for new command return; - } - cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string - if(!comment_mode){ - - gcode_N = 0; - - // Line numbers must be first in buffer - - if ((strstr(cmdbuffer+bufindw+CMDHDRSIZE, "PRUSA") == NULL) && - (cmdbuffer[bufindw+CMDHDRSIZE] == 'N')) { - - // Line number met. When sending a G-code over a serial line, each line may be stamped with its index, - // and Marlin tests, whether the successive lines are stamped with an increasing line number ID - gcode_N = (strtol(cmdbuffer+bufindw+CMDHDRSIZE+1, NULL, 10)); - if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) { - // M110 - set current line number. - // Line numbers not sent in succession. - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(_n("Line Number is not Last Line Number+1, Last Line: "));////MSG_ERR_LINE_NO c=0 r=0 - SERIAL_ERRORLN(gcode_LastN); - //Serial.println(gcode_N); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL) - { - byte checksum = 0; - char *p = cmdbuffer+bufindw+CMDHDRSIZE; - while (p != strchr_pointer) - checksum = checksum^(*p++); - if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) { - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(_i("checksum mismatch, Last Line: "));////MSG_ERR_CHECKSUM_MISMATCH c=0 r=0 - SERIAL_ERRORLN(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - // If no errors, remove the checksum and continue parsing. - *strchr_pointer = 0; - } - else - { - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(_i("No Checksum with line number, Last Line: "));////MSG_ERR_NO_CHECKSUM c=0 r=0 - SERIAL_ERRORLN(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - - // Don't parse N again with code_seen('N') - cmdbuffer[bufindw + CMDHDRSIZE] = '$'; - //if no errors, continue parsing - gcode_LastN = gcode_N; - } - // if we don't receive 'N' but still see '*' - if ((cmdbuffer[bufindw + CMDHDRSIZE] != 'N') && (cmdbuffer[bufindw + CMDHDRSIZE] != '$') && (strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL)) - { - SERIAL_ERROR_START; - SERIAL_ERRORRPGM(_n("No Line Number with checksum, Last Line: "));////MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM c=0 r=0 - SERIAL_ERRORLN(gcode_LastN); - FlushSerialRequestResend(); - serial_count = 0; - return; - } - if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) { - if (! IS_SD_PRINTING) { - usb_printing_counter = 10; - is_usb_printing = true; - } - if (Stopped == true) { - int gcode = strtol(strchr_pointer+1, NULL, 10); - if (gcode >= 0 && gcode <= 3) { - SERIAL_ERRORLNRPGM(_T(MSG_ERR_STOPPED)); - LCD_MESSAGERPGM(_T(MSG_STOPPED)); - } + if (MYSERIAL.available() == RX_BUFFER_SIZE - 1) { //compare number of chars buffered in rx buffer with rx buffer size + MYSERIAL.flush(); + SERIAL_ECHOLNPGM("Full RX Buffer"); //if buffer was full, there is danger that reading of last gcode will not be completed + } + + // start of serial line processing loop + while (MYSERIAL.available() > 0 && !saved_printing) { //is print is saved (crash detection or filament detection), dont process data from serial line + + char serial_char = MYSERIAL.read(); + /* if (selectedSerialPort == 1) + { + selectedSerialPort = 0; + MYSERIAL.write(serial_char); // for debuging serial line 2 in farm_mode + selectedSerialPort = 1; + } */ //RP - removed + TimeSent = millis(); + TimeNow = millis(); + + if (serial_char < 0) + // Ignore extended ASCII characters. These characters have no meaning in the G-code apart from the file names + // and Marlin does not support such file names anyway. + // Serial characters with a highest bit set to 1 are generated when the USB cable is unplugged, leading + // to a hang-up of the print process from an SD card. + continue; + if(serial_char == '\n' || + serial_char == '\r' || + serial_count >= (MAX_CMD_SIZE - 1) ) + { + if(!serial_count) { //if empty line + comment_mode = false; //for new command + return; } - } // end of 'G' command - - //If command was e-stop process now - if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0) - kill("", 2); - - // Store the current line into buffer, move to the next line. - // Store type of entry - cmdbuffer[bufindw] = gcode_N ? CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR : CMDBUFFER_CURRENT_TYPE_USB; + cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string + if(!comment_mode) { + + gcode_N = 0; + + // Line numbers must be first in buffer + + if ((strstr(cmdbuffer+bufindw+CMDHDRSIZE, "PRUSA") == NULL) && + (cmdbuffer[bufindw+CMDHDRSIZE] == 'N')) { + + // Line number met. When sending a G-code over a serial line, each line may be stamped with its index, + // and Marlin tests, whether the successive lines are stamped with an increasing line number ID + gcode_N = (strtol(cmdbuffer+bufindw+CMDHDRSIZE+1, NULL, 10)); + if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer+bufindw+CMDHDRSIZE, PSTR("M110")) == NULL) ) { + // M110 - set current line number. + // Line numbers not sent in succession. + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(_n("Line Number is not Last Line Number+1, Last Line: "));////MSG_ERR_LINE_NO c=0 r=0 + SERIAL_ERRORLN(gcode_LastN); + //Serial.println(gcode_N); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + if((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*')) != NULL) + { + byte checksum = 0; + char *p = cmdbuffer+bufindw+CMDHDRSIZE; + while (p != strchr_pointer) + checksum = checksum^(*p++); + if (int(strtol(strchr_pointer+1, NULL, 10)) != int(checksum)) { + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(_i("checksum mismatch, Last Line: "));////MSG_ERR_CHECKSUM_MISMATCH c=0 r=0 + SERIAL_ERRORLN(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + // If no errors, remove the checksum and continue parsing. + *strchr_pointer = 0; + } + else + { + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(_i("No Checksum with line number, Last Line: "));////MSG_ERR_NO_CHECKSUM c=0 r=0 + SERIAL_ERRORLN(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + + // Don't parse N again with code_seen('N') + cmdbuffer[bufindw + CMDHDRSIZE] = '$'; + //if no errors, continue parsing + gcode_LastN = gcode_N; + } + // if we don't receive 'N' but still see '*' + if ((cmdbuffer[bufindw + CMDHDRSIZE] != 'N') && (cmdbuffer[bufindw + CMDHDRSIZE] != '$') && (strchr(cmdbuffer+bufindw+CMDHDRSIZE, '*') != NULL)) + { + + SERIAL_ERROR_START; + SERIAL_ERRORRPGM(_n("No Line Number with checksum, Last Line: "));////MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM c=0 r=0 + SERIAL_ERRORLN(gcode_LastN); + FlushSerialRequestResend(); + serial_count = 0; + return; + } + if ((strchr_pointer = strchr(cmdbuffer+bufindw+CMDHDRSIZE, 'G')) != NULL) { + if (! IS_SD_PRINTING) { + usb_printing_counter = 10; + is_usb_printing = true; + } + if (Stopped == true) { + int gcode = strtol(strchr_pointer+1, NULL, 10); + if (gcode >= 0 && gcode <= 3) { + SERIAL_ERRORLNRPGM(_T(MSG_ERR_STOPPED)); + LCD_MESSAGERPGM(_T(MSG_STOPPED)); + } + } + } // end of 'G' command + + //If command was e-stop process now + if(strcmp(cmdbuffer+bufindw+CMDHDRSIZE, "M112") == 0) + kill("", 2); + + // Store the current line into buffer, move to the next line. + // Store type of entry + cmdbuffer[bufindw] = gcode_N ? CMDBUFFER_CURRENT_TYPE_USB_WITH_LINENR : CMDBUFFER_CURRENT_TYPE_USB; #ifdef CMDBUFFER_DEBUG - SERIAL_ECHO_START; - SERIAL_ECHOPGM("Storing a command line to buffer: "); - SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE); - SERIAL_ECHOLNPGM(""); + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Storing a command line to buffer: "); + SERIAL_ECHO(cmdbuffer+bufindw+CMDHDRSIZE); + SERIAL_ECHOLNPGM(""); #endif /* CMDBUFFER_DEBUG */ - bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); - if (bufindw == sizeof(cmdbuffer)) - bufindw = 0; - ++ buflen; + bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); + if (bufindw == sizeof(cmdbuffer)) + bufindw = 0; + ++ buflen; #ifdef CMDBUFFER_DEBUG - SERIAL_ECHOPGM("Number of commands in the buffer: "); - SERIAL_ECHO(buflen); - SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Number of commands in the buffer: "); + SERIAL_ECHO(buflen); + SERIAL_ECHOLNPGM(""); #endif /* CMDBUFFER_DEBUG */ - } // end of 'not comment mode' - serial_count = 0; //clear buffer - // Don't call cmdqueue_could_enqueue_back if there are no characters waiting - // in the queue, as this function will reserve the memory. - if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true)) - return; - } // end of "end of line" processing - else { - // Not an "end of line" symbol. Store the new character into a buffer. - if(serial_char == ';') comment_mode = true; - if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; - } - } // end of serial line processing loop + } // end of 'not comment mode' + serial_count = 0; //clear buffer + // Don't call cmdqueue_could_enqueue_back if there are no characters waiting + // in the queue, as this function will reserve the memory. + if (MYSERIAL.available() == 0 || ! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true)) + return; + } // end of "end of line" processing + else { + // Not an "end of line" symbol. Store the new character into a buffer. + if(serial_char == ';') comment_mode = true; + if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; + } + } // end of serial line processing loop - if(farm_mode){ + if(farm_mode) { TimeNow = millis(); if ( ((TimeNow - TimeSent) > 800) && (serial_count > 0) ) { cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; - + bufindw += strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); if (bufindw == sizeof(cmdbuffer)) bufindw = 0; ++ buflen; - + serial_count = 0; - + SERIAL_ECHOPGM("TIMEOUT:"); //memset(cmdbuffer, 0 , sizeof(cmdbuffer)); return; } } - #ifdef SDSUPPORT - if(!card.sdprinting || serial_count!=0){ - // If there is a half filled buffer from serial line, wait until return before - // continuing with the serial line. - return; - } - - //'#' 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; - union { - struct { - char lo; - char hi; - } lohi; - uint16_t value; - } sd_count; - sd_count.value = 0; - // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer. - while( !card.eof() && !stop_buffering) { - int16_t n=card.get(); - char 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) - { - if(card.eof()){ - SERIAL_PROTOCOLLNRPGM(_n("Done printing file"));////MSG_FILE_PRINTED c=0 r=0 - stoptime=millis(); - char time[30]; - unsigned long t=(stoptime-starttime-pause_time)/1000; - pause_time = 0; - int hours, minutes; - minutes=(t/60)%60; - hours=t/60/60; - save_statistics(total_filament_used, t); - sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes); - SERIAL_ECHO_START; - SERIAL_ECHOLN(time); - lcd_setstatus(time); - card.printingHasFinished(); - card.checkautostart(true); +#ifdef SDSUPPORT + if(!card.sdprinting || serial_count!=0) { + // If there is a half filled buffer from serial line, wait until return before + // continuing with the serial line. + return; + } + + //'#' 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 - if (farm_mode) + static bool stop_buffering=false; + if(buflen==0) stop_buffering=false; + union { + struct { + char lo; + char hi; + } lohi; + uint16_t value; + } sd_count; + sd_count.value = 0; + // Reads whole lines from the SD card. Never leaves a half-filled line in the cmdbuffer. + while( !card.eof() && !stop_buffering) { + int16_t n=card.get(); + char 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) { - prusa_statistics(6); - lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM; - } + if(card.eof()) { + SERIAL_PROTOCOLLNRPGM(_n("Done printing file"));////MSG_FILE_PRINTED c=0 r=0 + stoptime=millis(); + char time[30]; + unsigned long t=(stoptime-starttime-pause_time)/1000; + pause_time = 0; + int hours, minutes; + minutes=(t/60)%60; + hours=t/60/60; + save_statistics(total_filament_used, t); + sprintf_P(time, PSTR("%i hours %i minutes"),hours, minutes); + SERIAL_ECHO_START; + SERIAL_ECHOLN(time); + lcd_setstatus(time); + card.printingHasFinished(); + card.checkautostart(true); + + if (farm_mode) + { + prusa_statistics(6); + lcd_commands_type = LCD_COMMAND_FARM_MODE_CONFIRM; + } - } - if(serial_char=='#') - stop_buffering=true; - - if(!serial_count) - { - // This is either an empty line, or a line with just a comment. - // Continue to the following line, and continue accumulating the number of bytes - // read from the sdcard into sd_count, - // so that the lenght of the already read empty lines and comments will be added - // to the following non-empty line. - comment_mode = false; - continue; //if empty line - } - // The new command buffer could be updated non-atomically, because it is not yet considered - // to be inside the active queue. - sd_count.value = (card.get_sdpos()+1) - sdpos_atomic; - cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD; - cmdbuffer[bufindw+1] = sd_count.lohi.lo; - cmdbuffer[bufindw+2] = sd_count.lohi.hi; - cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string - // Calculate the length before disabling the interrupts. - uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); + } + if(serial_char=='#') + stop_buffering=true; + + if(!serial_count) + { + // This is either an empty line, or a line with just a comment. + // Continue to the following line, and continue accumulating the number of bytes + // read from the sdcard into sd_count, + // so that the lenght of the already read empty lines and comments will be added + // to the following non-empty line. + comment_mode = false; + continue; //if empty line + } + // The new command buffer could be updated non-atomically, because it is not yet considered + // to be inside the active queue. + sd_count.value = (card.get_sdpos()+1) - sdpos_atomic; + cmdbuffer[bufindw] = CMDBUFFER_CURRENT_TYPE_SDCARD; + cmdbuffer[bufindw+1] = sd_count.lohi.lo; + cmdbuffer[bufindw+2] = sd_count.lohi.hi; + cmdbuffer[bufindw+serial_count+CMDHDRSIZE] = 0; //terminate string + // Calculate the length before disabling the interrupts. + uint8_t len = strlen(cmdbuffer+bufindw+CMDHDRSIZE) + (1 + CMDHDRSIZE); // SERIAL_ECHOPGM("SD cmd("); // MYSERIAL.print(sd_count.value, DEC); @@ -629,34 +629,34 @@ void get_command() // MYSERIAL.print(cmdbuffer); // SERIAL_ECHOPGM("buflen:"); // MYSERIAL.print(buflen+1); - sd_count.value = 0; - - cli(); - // This block locks the interrupts globally for 3.56 us, - // which corresponds to a maximum repeat frequency of 280.70 kHz. - // This blocking is safe in the context of a 10kHz stepper driver interrupt - // or a 115200 Bd serial line receive interrupt, which will not trigger faster than 12kHz. - ++ buflen; - bufindw += len; - sdpos_atomic = card.get_sdpos()+1; - if (bufindw == sizeof(cmdbuffer)) - bufindw = 0; - sei(); - - comment_mode = false; //for new command - serial_count = 0; //clear buffer - // The following line will reserve buffer space if available. - if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true)) - return; - } - else - { - if(serial_char == ';') comment_mode = true; - else if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; + sd_count.value = 0; + + cli(); + // This block locks the interrupts globally for 3.56 us, + // which corresponds to a maximum repeat frequency of 280.70 kHz. + // This blocking is safe in the context of a 10kHz stepper driver interrupt + // or a 115200 Bd serial line receive interrupt, which will not trigger faster than 12kHz. + ++ buflen; + bufindw += len; + sdpos_atomic = card.get_sdpos()+1; + if (bufindw == sizeof(cmdbuffer)) + bufindw = 0; + sei(); + + comment_mode = false; //for new command + serial_count = 0; //clear buffer + // The following line will reserve buffer space if available. + if (! cmdqueue_could_enqueue_back(MAX_CMD_SIZE-1, true)) + return; + } + else + { + if(serial_char == ';') comment_mode = true; + else if(!comment_mode) cmdbuffer[bufindw+CMDHDRSIZE+serial_count++] = serial_char; + } } - } - #endif //SDSUPPORT +#endif //SDSUPPORT } uint16_t cmdqueue_calc_sd_length() diff --git a/Firmware/cmdqueue.h b/Firmware/cmdqueue.h index 6c81db2966..3f7fe93925 100755 --- a/Firmware/cmdqueue.h +++ b/Firmware/cmdqueue.h @@ -6,9 +6,9 @@ // String circular buffer. Commands may be pushed to the buffer from both sides: -// Chained commands will be pushed to the front, interactive (from LCD menu) +// Chained commands will be pushed to the front, interactive (from LCD menu) // and printing commands (from serial line or from SD card) are pushed to the tail. -// First character of each entry indicates the type of the entry: +// First character of each entry indicates the type of the entry: #define CMDBUFFER_CURRENT_TYPE_UNKNOWN 0 // Command in cmdbuffer was sent over USB. #define CMDBUFFER_CURRENT_TYPE_USB 1 @@ -18,8 +18,8 @@ #define CMDBUFFER_CURRENT_TYPE_UI 3 // Command in cmdbuffer was generated by another G-code. #define CMDBUFFER_CURRENT_TYPE_CHAINED 4 -// Command has been processed and its SD card length has been possibly pushed -// to the planner queue, but not yet removed from the cmdqueue. +// Command has been processed and its SD card length has been possibly pushed +// to the planner queue, but not yet removed from the cmdqueue. // This is a temporary state to reduce stepper interrupt locking time. #define CMDBUFFER_CURRENT_TYPE_TO_BE_REMOVED 5 //Command in cmdbuffer was sent over USB and contains line number @@ -71,12 +71,24 @@ extern void get_command(); extern uint16_t cmdqueue_calc_sd_length(); // Return True if a character was found -static inline bool code_seen(char code) { return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; } -static inline bool code_seen(const char *code) { return (strchr_pointer = strstr(CMDBUFFER_CURRENT_STRING, code)) != NULL; } -static inline float code_value() { return strtod(strchr_pointer+1, NULL);} -static inline long code_value_long() { return strtol(strchr_pointer+1, NULL, 10); } -static inline int16_t code_value_short() { return int16_t(strtol(strchr_pointer+1, NULL, 10)); }; -static inline uint8_t code_value_uint8() { return uint8_t(strtol(strchr_pointer+1, NULL, 10)); }; +static inline bool code_seen(char code) { + return (strchr_pointer = strchr(CMDBUFFER_CURRENT_STRING, code)) != NULL; +} +static inline bool code_seen(const char *code) { + return (strchr_pointer = strstr(CMDBUFFER_CURRENT_STRING, code)) != NULL; +} +static inline float code_value() { + return strtod(strchr_pointer+1, NULL); +} +static inline long code_value_long() { + return strtol(strchr_pointer+1, NULL, 10); +} +static inline int16_t code_value_short() { + return int16_t(strtol(strchr_pointer+1, NULL, 10)); +}; +static inline uint8_t code_value_uint8() { + return uint8_t(strtol(strchr_pointer+1, NULL, 10)); +}; static inline float code_value_float() { diff --git a/Firmware/configuration_prusa.h b/Firmware/configuration_prusa.h deleted file mode 100755 index 4655107c04..0000000000 --- a/Firmware/configuration_prusa.h +++ /dev/null @@ -1,618 +0,0 @@ -#ifndef CONFIGURATION_PRUSA_H -#define CONFIGURATION_PRUSA_H - -/*------------------------------------ - GENERAL SETTINGS - *------------------------------------*/ - -// Printer revision -#define PRINTER_TYPE PRINTER_MK3 -#define FILAMENT_SIZE "1_75mm_MK3" -#define NOZZLE_TYPE "E3Dv6full" - -// Developer flag -#define DEVELOPER - -// Printer name -#define CUSTOM_MENDEL_NAME "Prusa i3 MK3" - -// Electronics -#define MOTHERBOARD BOARD_EINSY_1_0a -#define STEEL_SHEET -#define HAS_SECOND_SERIAL_PORT - - -// Uncomment the below for the E3D PT100 temperature sensor (with or without PT100 Amplifier) -//#define E3D_PT100_EXTRUDER_WITH_AMP -//#define E3D_PT100_EXTRUDER_NO_AMP -//#define E3D_PT100_BED_WITH_AMP -//#define E3D_PT100_BED_NO_AMP - - -/*------------------------------------ - AXIS SETTINGS - *------------------------------------*/ - -// Steps per unit {X,Y,Z,E} -//#define DEFAULT_AXIS_STEPS_PER_UNIT {100,100,3200/8,140} -#define DEFAULT_AXIS_STEPS_PER_UNIT {100,100,3200/8,280} -//#define DEFAULT_AXIS_STEPS_PER_UNIT {100,100,3200/8,560} - -// Endstop inverting -#define X_MIN_ENDSTOP_INVERTING 0 // set to 1 to invert the logic of the endstop. -#define Y_MIN_ENDSTOP_INVERTING 0 // set to 1 to invert the logic of the endstop. -#define Z_MIN_ENDSTOP_INVERTING 0 // set to 1 to invert the logic of the endstop. - -// Direction inverting -#define INVERT_X_DIR 1 // for Mendel set to 0, for Orca set to 1 -#define INVERT_Y_DIR 0 // for Mendel set to 1, for Orca set to 0 -#define INVERT_Z_DIR 1 // for Mendel set to 0, for Orca set to 1 -#define INVERT_E0_DIR 0 // for direct drive extruder v9 set to 1, for geared extruder set to 0 -#define INVERT_E1_DIR 0 // for direct drive extruder v9 set to 1, for geared extruder set to 0 -#define INVERT_E2_DIR 0 // for direct drive extruder v9 set to 1, for geared extruder set to 0 - -// Home position -#define MANUAL_X_HOME_POS 0 -#define MANUAL_Y_HOME_POS -2.2 -#define MANUAL_Z_HOME_POS 0.2 - -// Travel limits after homing -#define X_MAX_POS 255 -#define X_MIN_POS 0 -#define Y_MAX_POS 212.5 -#define Y_MIN_POS -4 //orig -4 -#define Z_MAX_POS 210 -#define Z_MIN_POS 0.15 - -// Canceled home position -#define X_CANCEL_POS 50 -#define Y_CANCEL_POS 190 - -//Pause print position -#define X_PAUSE_POS 50 -#define Y_PAUSE_POS 190 -#define Z_PAUSE_LIFT 20 - -#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E -#define HOMING_FEEDRATE {3000, 3000, 800, 0} // set the homing speeds (mm/min) // 3000 is also valid for stallGuard homing. Valid range: 2200 - 3000 - -//#define DEFAULT_Y_OFFSET 4.f // Default distance of Y_MIN_POS point from endstop, when the printer is not calibrated. -/** - * [0,0] steel sheet print area point X coordinate in bed print area coordinates - */ -#define SHEET_PRINT_ZERO_REF_X 0.f -/** - * [0,0] steel sheet print area point Y coordinate in bed print area coordinates - */ -#define SHEET_PRINT_ZERO_REF_Y -2.f - -#define DEFAULT_MAX_FEEDRATE {200, 200, 12, 120} // (mm/sec) max feedrate (M203) -#define DEFAULT_MAX_FEEDRATE_SILENT {100, 100, 12, 120} // (mm/sec) max feedrate (M203), silent mode - -#define DEFAULT_MAX_ACCELERATION {1000, 1000, 200, 5000} // (mm/sec^2) max acceleration (M201) -#define DEFAULT_MAX_ACCELERATION_SILENT {960, 960, 200, 5000} // (mm/sec^2) max acceleration (M201), silent mode - - -#define DEFAULT_ACCELERATION 1250 // X, Y, Z and E max acceleration in mm/s^2 for printing moves (M204S) -#define DEFAULT_RETRACT_ACCELERATION 1250 // X, Y, Z and E max acceleration in mm/s^2 for retracts (M204T) - -#define MANUAL_FEEDRATE {2700, 2700, 1000, 100} // set the speeds for manual moves (mm/min) - -//Silent mode limits -#define SILENT_MAX_ACCEL_XY 960ul // max acceleration in silent mode in mm/s^2 -#define SILENT_MAX_FEEDRATE_XY 100 // max feedrate in mm/s - -//Normal mode limits -#define NORMAL_MAX_ACCEL_XY 2500ul // max acceleration in normal mode in mm/s^2 -#define NORMAL_MAX_FEEDRATE_XY 200 // max feedrate in mm/s - -//number of bytes from end of the file to start check -#define END_FILE_SECTION 20000 - -#define Z_AXIS_ALWAYS_ON 1 - -//Crash detection -#define CRASHDET_TIMER 45 //seconds -#define CRASHDET_COUNTER_MAX 3 - -// New XYZ calibration -#define NEW_XYZCAL - -// Watchdog support -#define WATCHDOG - -// Power panic -#define UVLO_SUPPORT - -// Fan check -#define FANCHECK - -// Safety timer -#define SAFETYTIMER -#define DEFAULT_SAFETYTIMER_TIME_MINS 30 - -// Filament sensor -#define PAT9125 -#define FILAMENT_SENSOR - -// Backlash - -//#define BACKLASH_X -//#define BACKLASH_Y - - -// Minimum ambient temperature limit to start triggering MINTEMP errors [C] -// this value is litlebit higher that real limit, because ambient termistor is on the board and is temperated from it, -// temperature inside the case is around 31C for ambient temperature 25C, when the printer is powered on long time and idle -// the real limit is 15C (same as MINTEMP limit), this is because 15C is end of scale for both used thermistors (bed, heater) -#define MINTEMP_MINAMBIENT 25 -#define MINTEMP_MINAMBIENT_RAW 978 - -#define DEBUG_DCODE3 - -//#define DEBUG_BUILD -//#define DEBUG_SEC_LANG //secondary language debug output at startup -//#define DEBUG_W25X20CL //debug external spi flash -#ifdef DEBUG_BUILD -//#define _NO_ASM -#define DEBUG_DCODES //D codes -#define DEBUG_STACK_MONITOR //Stack monitor in stepper ISR -//#define DEBUG_FSENSOR_LOG //Reports fsensor status to serial -//#define DEBUG_CRASHDET_COUNTERS //Display crash-detection counters on LCD -//#define DEBUG_RESUME_PRINT //Resume/save print debug enable -//#define DEBUG_UVLO_AUTOMATIC_RECOVER // Power panic automatic recovery debug output -//#define DEBUG_DISABLE_XMINLIMIT //x min limit ignored -//#define DEBUG_DISABLE_XMAXLIMIT //x max limit ignored -//#define DEBUG_DISABLE_YMINLIMIT //y min limit ignored -//#define DEBUG_DISABLE_YMAXLIMIT //y max limit ignored -//#define DEBUG_DISABLE_ZMINLIMIT //z min limit ignored -//#define DEBUG_DISABLE_ZMAXLIMIT //z max limit ignored -#define DEBUG_DISABLE_STARTMSGS //no startup messages -//#define DEBUG_DISABLE_MINTEMP //mintemp error ignored -//#define DEBUG_DISABLE_SWLIMITS //sw limits ignored -//#define DEBUG_DISABLE_LCD_STATUS_LINE //empty four lcd line -//#define DEBUG_DISABLE_PREVENT_EXTRUDER //cold extrusion and long extrusion allowed -//#define DEBUG_DISABLE_PRUSA_STATISTICS //disable prusa_statistics() mesages -//#define DEBUG_DISABLE_FORCE_SELFTEST //disable force selftest -//#define DEBUG_XSTEP_DUP_PIN 21 //duplicate x-step output to pin 21 (SCL on P3) -//#define DEBUG_YSTEP_DUP_PIN 21 //duplicate y-step output to pin 21 (SCL on P3) -//#define DEBUG_DISABLE_FANCHECK //disable fan check (no ISR INT7, check disabled) -//#define DEBUG_DISABLE_FSENSORCHECK //disable fsensor check (no ISR INT7, check disabled) -#define DEBUG_DUMP_TO_2ND_SERIAL //dump received characters to 2nd serial line -#define DEBUG_STEPPER_TIMER_MISSED // Stop on stepper timer overflow, beep and display a message. -#define PLANNER_DIAGNOSTICS // Show the planner queue status on printer display. -#define CMD_DIAGNOSTICS //Show cmd queue length on printer display -#endif /* DEBUG_BUILD */ - -//#define FSENSOR_QUALITY - - -#define LINEARITY_CORRECTION -#define TMC2130_LINEARITY_CORRECTION -#define TMC2130_LINEARITY_CORRECTION_XYZ -//#define TMC2130_VARIABLE_RESOLUTION - - - -/*------------------------------------ - TMC2130 default settings - *------------------------------------*/ - -#define TMC2130_FCLK 12000000 // fclk = 12MHz - -#define TMC2130_USTEPS_XY 16 // microstep resolution for XY axes -#define TMC2130_USTEPS_Z 16 // microstep resolution for Z axis -#define TMC2130_USTEPS_E 32 // microstep resolution for E axis -#define TMC2130_INTPOL_XY 1 // extrapolate 256 for XY axes -#define TMC2130_INTPOL_Z 1 // extrapolate 256 for Z axis -#define TMC2130_INTPOL_E 1 // extrapolate 256 for E axis - -#define TMC2130_PWM_GRAD_X 2 // PWMCONF -#define TMC2130_PWM_AMPL_X 230 // PWMCONF -#define TMC2130_PWM_AUTO_X 1 // PWMCONF -#define TMC2130_PWM_FREQ_X 2 // PWMCONF - -#define TMC2130_PWM_GRAD_Y 2 // PWMCONF -#define TMC2130_PWM_AMPL_Y 235 // PWMCONF -#define TMC2130_PWM_AUTO_Y 1 // PWMCONF -#define TMC2130_PWM_FREQ_Y 2 // PWMCONF - -#define TMC2130_PWM_GRAD_Z 4 // PWMCONF -#define TMC2130_PWM_AMPL_Z 200 // PWMCONF -#define TMC2130_PWM_AUTO_Z 1 // PWMCONF -#define TMC2130_PWM_FREQ_Z 2 // PWMCONF - -#define TMC2130_PWM_GRAD_E 4 // PWMCONF -#define TMC2130_PWM_AMPL_E 240 // PWMCONF -#define TMC2130_PWM_AUTO_E 1 // PWMCONF -#define TMC2130_PWM_FREQ_E 2 // PWMCONF - -#define TMC2130_TOFF_XYZ 3 // CHOPCONF // fchop = 27.778kHz -#define TMC2130_TOFF_E 3 // CHOPCONF // fchop = 27.778kHz -//#define TMC2130_TOFF_E 4 // CHOPCONF // fchop = 21.429kHz -//#define TMC2130_TOFF_E 5 // CHOPCONF // fchop = 17.442kHz - -//#define TMC2130_STEALTH_E // Extruder stealthChop mode -//#define TMC2130_CNSTOFF_E // Extruder constant-off-time mode (similar to MK2) - -//#define TMC2130_PWM_DIV 683 // PWM frequency divider (1024, 683, 512, 410) -#define TMC2130_PWM_DIV 512 // PWM frequency divider (1024, 683, 512, 410) -#define TMC2130_PWM_CLK (2 * TMC2130_FCLK / TMC2130_PWM_DIV) // PWM frequency (23.4kHz, 35.1kHz, 46.9kHz, 58.5kHz for 12MHz fclk) - -#define TMC2130_TPWMTHRS 0 // TPWMTHRS - Sets the switching speed threshold based on TSTEP from stealthChop to spreadCycle mode -#define TMC2130_THIGH 0 // THIGH - unused - -//#define TMC2130_TCOOLTHRS_X 450 // TCOOLTHRS - coolstep treshold -//#define TMC2130_TCOOLTHRS_Y 450 // TCOOLTHRS - coolstep treshold -#define TMC2130_TCOOLTHRS_X 430 // TCOOLTHRS - coolstep treshold -#define TMC2130_TCOOLTHRS_Y 430 // TCOOLTHRS - coolstep treshold -#define TMC2130_TCOOLTHRS_Z 500 // TCOOLTHRS - coolstep treshold -#define TMC2130_TCOOLTHRS_E 500 // TCOOLTHRS - coolstep treshold - -#define TMC2130_SG_HOMING 1 // stallguard homing -#define TMC2130_SG_THRS_X 3 // stallguard sensitivity for X axis -#define TMC2130_SG_THRS_Y 3 // stallguard sensitivity for Y axis -#define TMC2130_SG_THRS_Z 4 // stallguard sensitivity for Z axis -#define TMC2130_SG_THRS_E 3 // stallguard sensitivity for E axis - -//new settings is possible for vsense = 1, running current value > 31 set vsense to zero and shift both currents by 1 bit right (Z axis only) -#define TMC2130_CURRENTS_H {16, 20, 35, 30} // default holding currents for all axes -#define TMC2130_CURRENTS_R {16, 20, 35, 30} // default running currents for all axes -#define TMC2130_UNLOAD_CURRENT_R 12 // lowe current for M600 to protect filament sensor - -#define TMC2130_STEALTH_Z - -//#define TMC2130_SERVICE_CODES_M910_M918 - -//#define TMC2130_DEBUG -//#define TMC2130_DEBUG_WR -//#define TMC2130_DEBUG_RD - - -/*------------------------------------ - EXTRUDER SETTINGS - *------------------------------------*/ - -// Mintemps -#define HEATER_0_MINTEMP 15 -#define HEATER_1_MINTEMP 5 -#define HEATER_2_MINTEMP 5 -#define BED_MINTEMP 15 - -// Maxtemps -#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) -#define HEATER_0_MAXTEMP 410 -#else -#define HEATER_0_MAXTEMP 305 -#endif -#define HEATER_1_MAXTEMP 305 -#define HEATER_2_MAXTEMP 305 -#define BED_MAXTEMP 125 - -#if defined(E3D_PT100_EXTRUDER_WITH_AMP) || defined(E3D_PT100_EXTRUDER_NO_AMP) -// Define PID constants for extruder with PT100 -#define DEFAULT_Kp 21.70 -#define DEFAULT_Ki 1.60 -#define DEFAULT_Kd 73.76 -#else -// Define PID constants for extruder -//#define DEFAULT_Kp 40.925 -//#define DEFAULT_Ki 4.875 -//#define DEFAULT_Kd 86.085 -#define DEFAULT_Kp 16.13 -#define DEFAULT_Ki 1.1625 -#define DEFAULT_Kd 56.23 -#endif - -// Extrude mintemp -#define EXTRUDE_MINTEMP 175 - -// Extruder cooling fans -#define EXTRUDER_0_AUTO_FAN_PIN 8 -#define EXTRUDER_1_AUTO_FAN_PIN -1 -#define EXTRUDER_2_AUTO_FAN_PIN -1 -#define EXTRUDER_AUTO_FAN_TEMPERATURE 50 -#define EXTRUDER_AUTO_FAN_SPEED 255 // == full speed - - - -/*------------------------------------ - LOAD/UNLOAD FILAMENT SETTINGS - *------------------------------------*/ - -// Load filament commands -#define LOAD_FILAMENT_0 "M83" -#define LOAD_FILAMENT_1 "G1 E70 F400" -#define LOAD_FILAMENT_2 "G1 E40 F100" - -// Unload filament commands -#define UNLOAD_FILAMENT_0 "M83" -#define UNLOAD_FILAMENT_1 "G1 E-80 F7000" - -/*------------------------------------ - CHANGE FILAMENT SETTINGS - *------------------------------------*/ - -// Filament change configuration -#define FILAMENTCHANGEENABLE -#ifdef FILAMENTCHANGEENABLE -#define FILAMENTCHANGE_XPOS 211 -#define FILAMENTCHANGE_YPOS 0 -#define FILAMENTCHANGE_ZADD 2 -#define FILAMENTCHANGE_FIRSTRETRACT -2 -#define FILAMENTCHANGE_FINALRETRACT -80 - -#define FILAMENTCHANGE_FIRSTFEED 70 //E distance in mm for fast filament loading sequence used used in filament change (M600) -#define FILAMENTCHANGE_FINALFEED 25 //E distance in mm for slow filament loading sequence used used in filament change (M600) and filament load (M701) -#define FILAMENTCHANGE_RECFEED 5 - -#define FILAMENTCHANGE_XYFEED 50 -#define FILAMENTCHANGE_EFEED_FIRST 20 // feedrate in mm/s for fast filament loading sequence used in filament change (M600) -#define FILAMENTCHANGE_EFEED_FINAL 3.3f // feedrate in mm/s for slow filament loading sequence used in filament change (M600) and filament load (M701) -//#define FILAMENTCHANGE_RFEED 400 -#define FILAMENTCHANGE_RFEED 7000 / 60 -#define FILAMENTCHANGE_EXFEED 2 -#define FILAMENTCHANGE_ZFEED 15 - -#endif - -/*------------------------------------ - ADDITIONAL FEATURES SETTINGS - *------------------------------------*/ - -// Define Prusa filament runout sensor -//#define FILAMENT_RUNOUT_SUPPORT - -#ifdef FILAMENT_RUNOUT_SUPPORT -#define FILAMENT_RUNOUT_SENSOR 1 -#endif - -// temperature runaway -#define TEMP_RUNAWAY_BED_HYSTERESIS 5 -#define TEMP_RUNAWAY_BED_TIMEOUT 360 - -#define TEMP_RUNAWAY_EXTRUDER_HYSTERESIS 15 -#define TEMP_RUNAWAY_EXTRUDER_TIMEOUT 45 - -/*------------------------------------ - MOTOR CURRENT SETTINGS - *------------------------------------*/ - -// Motor Current settings for Einsy/tmc = 0..63 -#define MOTOR_CURRENT_PWM_RANGE 63 - -/*------------------------------------ - BED SETTINGS - *------------------------------------*/ - -// Define Mesh Bed Leveling system to enable it -#define MESH_BED_LEVELING -#ifdef MESH_BED_LEVELING - -#define MBL_Z_STEP 0.01 - -// Mesh definitions -#define MESH_MIN_X 35 -#define MESH_MAX_X 238 -#define MESH_MIN_Y 6 -#define MESH_MAX_Y 202 - -// Mesh upsample definition -#define MESH_NUM_X_POINTS 7 -#define MESH_NUM_Y_POINTS 7 -// Mesh measure definition -#define MESH_MEAS_NUM_X_POINTS 3 -#define MESH_MEAS_NUM_Y_POINTS 3 - -#define MESH_HOME_Z_CALIB 0.2 -#define MESH_HOME_Z_SEARCH 5 //Z lift for homing, mesh bed leveling etc. - -#define X_PROBE_OFFSET_FROM_EXTRUDER 23 // Z probe to nozzle X offset: -left +right -#define Y_PROBE_OFFSET_FROM_EXTRUDER 5 // Z probe to nozzle Y offset: -front +behind -#define Z_PROBE_OFFSET_FROM_EXTRUDER -0.4 // Z probe to nozzle Z offset: -below (always!) -#endif - -// 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 - -// Bed temperature compensation settings -#define BED_OFFSET 10 -#define BED_OFFSET_START 40 -#define BED_OFFSET_CENTER 50 - - -#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) -#if defined(E3D_PT100_BED_WITH_AMP) || defined(E3D_PT100_BED_NO_AMP) -// Define PID constants for extruder with PT100 -#define DEFAULT_bedKp 21.70 -#define DEFAULT_bedKi 1.60 -#define DEFAULT_bedKd 73.76 -#else -#define DEFAULT_bedKp 126.13 -#define DEFAULT_bedKi 4.30 -#define DEFAULT_bedKd 924.76 -#endif - -//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 - -//connect message when communication with monitoring broken -//#define FARM_CONNECT_MESSAGE - -/*----------------------------------- - PREHEAT SETTINGS - *------------------------------------*/ - -#define FARM_PREHEAT_HOTEND_TEMP 250 -#define FARM_PREHEAT_HPB_TEMP 60 -#define FARM_PREHEAT_FAN_SPEED 0 - -#define PLA_PREHEAT_HOTEND_TEMP 215 -#define PLA_PREHEAT_HPB_TEMP 60 -#define PLA_PREHEAT_FAN_SPEED 0 - -#define ABS_PREHEAT_HOTEND_TEMP 255 -#define ABS_PREHEAT_HPB_TEMP 100 -#define ABS_PREHEAT_FAN_SPEED 0 - -#define HIPS_PREHEAT_HOTEND_TEMP 220 -#define HIPS_PREHEAT_HPB_TEMP 100 -#define HIPS_PREHEAT_FAN_SPEED 0 - -#define PP_PREHEAT_HOTEND_TEMP 254 -#define PP_PREHEAT_HPB_TEMP 100 -#define PP_PREHEAT_FAN_SPEED 0 - -#define PET_PREHEAT_HOTEND_TEMP 230 -#define PET_PREHEAT_HPB_TEMP 85 -#define PET_PREHEAT_FAN_SPEED 0 - -#define FLEX_PREHEAT_HOTEND_TEMP 240 -#define FLEX_PREHEAT_HPB_TEMP 50 -#define FLEX_PREHEAT_FAN_SPEED 0 - -/*------------------------------------ - THERMISTORS 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) -// 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 -// -// 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 -// 148 is E3D Pt100 with 4k7 pullup and no PT100 Amplifier on a MiniRambo 1.3a -// 247 is Pt100 with 4k7 pullup and PT100 Amplifier -// 110 is Pt100 with 1k pullup (non standard) - -#if defined(E3D_PT100_EXTRUDER_WITH_AMP) -#define TEMP_SENSOR_0 247 -#elif defined(E3D_PT100_EXTRUDER_NO_AMP) -#define TEMP_SENSOR_0 148 -#else -#define TEMP_SENSOR_0 5 -#endif -#define TEMP_SENSOR_1 0 -#define TEMP_SENSOR_2 0 -#if defined(E3D_PT100_BED_WITH_AMP) -#define TEMP_SENSOR_BED 247 -#elif defined(E3D_PT100_BED_NO_AMP) -#define TEMP_SENSOR_BED 148 -#else -#define TEMP_SENSOR_BED 1 -#endif -#define TEMP_SENSOR_PINDA 1 -#define TEMP_SENSOR_AMBIENT 2000 - -#define STACK_GUARD_TEST_VALUE 0xA2A2 - -#define MAX_BED_TEMP_CALIBRATION 50 -#define MAX_HOTEND_TEMP_CALIBRATION 50 - -#define MAX_E_STEPS_PER_UNIT 250 -#define MIN_E_STEPS_PER_UNIT 100 - -#define Z_BABYSTEP_MIN -3999 -#define Z_BABYSTEP_MAX 0 - -#define PINDA_PREHEAT_X 20 -#define PINDA_PREHEAT_Y 60 -#define PINDA_PREHEAT_Z 0.15 -/* -#define PINDA_PREHEAT_X 70 -#define PINDA_PREHEAT_Y -3 -#define PINDA_PREHEAT_Z 1*/ -#define PINDA_HEAT_T 120 //time in s - -#define PINDA_MIN_T 50 -#define PINDA_STEP_T 10 -#define PINDA_MAX_T 100 - -#define PING_TIME 60 //time in s -#define PING_TIME_LONG 600 //10 min; used when length of commands buffer > 0 to avoid 0 triggering when dealing with long gcodes -#define PING_ALLERT_PERIOD 60 //time in s - -#define NC_TIME 10 //time in s for periodic important status messages sending which needs reponse from monitoring -#define NC_BUTTON_LONG_PRESS 15 //time in s - -#define LONG_PRESS_TIME 1000 //time in ms for button long press -#define BUTTON_BLANKING_TIME 200 //time in ms for blanking after button release - -#define DEFAULT_PID_TEMP 210 - -#define MIN_PRINT_FAN_SPEED 75 - - -// How much shall the print head be lifted on power panic? -// Ideally the Z axis will reach a zero phase of the stepper driver on power outage. To simplify this, -// UVLO_Z_AXIS_SHIFT shall be an integer multiply of the stepper driver cycle, that is 4x full step. -// For example, the Prusa i3 MK2 with 16 microsteps per full step has Z stepping of 400 microsteps per mm. -// At 400 microsteps per mm, a full step lifts the Z axis by 0.04mm, and a stepper driver cycle is 0.16mm. -// The following example, 12 * (4 * 16 / 400) = 12 * 0.16mm = 1.92mm. -//#define UVLO_Z_AXIS_SHIFT 1.92 -#define UVLO_Z_AXIS_SHIFT 0.64 -// If power panic occured, and the current temperature is higher then target temperature before interrupt minus this offset, print will be recovered automatically. -#define AUTOMATIC_UVLO_BED_TEMP_OFFSET 5 - -#define HEATBED_V2 - -#define M600_TIMEOUT 600 //seconds - -//#define SUPPORT_VERBOSITY - -#define MMU_REQUIRED_FW_BUILDNR 83 -#define MMU_HWRESET -//#define MMU_DEBUG //print communication between MMU2 and printer on serial - -#endif //__CONFIGURATION_PRUSA_H diff --git a/Firmware/conv2str.cpp b/Firmware/conv2str.cpp index 10aa711e43..a8947a19dc 100755 --- a/Firmware/conv2str.cpp +++ b/Firmware/conv2str.cpp @@ -9,110 +9,110 @@ char conv[8]; char *ftostr3(const float &x) { - return itostr3((int)x); + return itostr3((int)x); } char *itostr2(const uint8_t &x) { - //sprintf(conv,"%5.1f",x); - int xx = x; - conv[0] = (xx / 10) % 10 + '0'; - conv[1] = (xx) % 10 + '0'; - conv[2] = 0; - return conv; + //sprintf(conv,"%5.1f",x); + int xx = x; + conv[0] = (xx / 10) % 10 + '0'; + conv[1] = (xx) % 10 + '0'; + conv[2] = 0; + return conv; } // Convert float to string with 123.4 format, dropping sign char *ftostr31(const float &x) { - int xx = x * 10; - conv[0] = (xx >= 0) ? '+' : '-'; - xx = abs(xx); - conv[1] = (xx / 1000) % 10 + '0'; - conv[2] = (xx / 100) % 10 + '0'; - conv[3] = (xx / 10) % 10 + '0'; - conv[4] = '.'; - conv[5] = (xx) % 10 + '0'; - conv[6] = 0; - return conv; + int xx = x * 10; + conv[0] = (xx >= 0) ? '+' : '-'; + xx = abs(xx); + conv[1] = (xx / 1000) % 10 + '0'; + conv[2] = (xx / 100) % 10 + '0'; + conv[3] = (xx / 10) % 10 + '0'; + conv[4] = '.'; + conv[5] = (xx) % 10 + '0'; + conv[6] = 0; + return conv; } // Convert float to string with 123.4 format char *ftostr31ns(const float &x) { - int xx = x * 10; - //conv[0]=(xx>=0)?'+':'-'; - xx = abs(xx); - conv[0] = (xx / 1000) % 10 + '0'; - conv[1] = (xx / 100) % 10 + '0'; - conv[2] = (xx / 10) % 10 + '0'; - conv[3] = '.'; - conv[4] = (xx) % 10 + '0'; - conv[5] = 0; - return conv; + int xx = x * 10; + //conv[0]=(xx>=0)?'+':'-'; + xx = abs(xx); + conv[0] = (xx / 1000) % 10 + '0'; + conv[1] = (xx / 100) % 10 + '0'; + conv[2] = (xx / 10) % 10 + '0'; + conv[3] = '.'; + conv[4] = (xx) % 10 + '0'; + conv[5] = 0; + return conv; } char *ftostr32(const float &x) { - long xx = x * 100; - if (xx >= 0) - conv[0] = (xx / 10000) % 10 + '0'; - else - conv[0] = '-'; - xx = abs(xx); - conv[1] = (xx / 1000) % 10 + '0'; - conv[2] = (xx / 100) % 10 + '0'; - conv[3] = '.'; - conv[4] = (xx / 10) % 10 + '0'; - conv[5] = (xx) % 10 + '0'; - conv[6] = 0; - return conv; + long xx = x * 100; + if (xx >= 0) + conv[0] = (xx / 10000) % 10 + '0'; + else + conv[0] = '-'; + xx = abs(xx); + conv[1] = (xx / 1000) % 10 + '0'; + conv[2] = (xx / 100) % 10 + '0'; + conv[3] = '.'; + conv[4] = (xx / 10) % 10 + '0'; + conv[5] = (xx) % 10 + '0'; + conv[6] = 0; + return conv; } //// Convert float to rj string with 123.45 format char *ftostr32ns(const float &x) { - long xx = abs(x); - conv[0] = xx >= 10000 ? (xx / 10000) % 10 + '0' : ' '; - conv[1] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' '; - conv[2] = xx >= 100 ? (xx / 100) % 10 + '0' : '0'; - conv[3] = '.'; - conv[4] = (xx / 10) % 10 + '0'; - conv[5] = xx % 10 + '0'; - return conv; + long xx = abs(x); + conv[0] = xx >= 10000 ? (xx / 10000) % 10 + '0' : ' '; + conv[1] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' '; + conv[2] = xx >= 100 ? (xx / 100) % 10 + '0' : '0'; + conv[3] = '.'; + conv[4] = (xx / 10) % 10 + '0'; + conv[5] = xx % 10 + '0'; + return conv; } // Convert float to string with 1.234 format char *ftostr43(const float &x, uint8_t offset) { - const size_t maxOffset = sizeof(conv)/sizeof(conv[0]) - 6; - if (offset>maxOffset) offset = maxOffset; - long xx = x * 1000; - if (xx >= 0) - conv[offset] = (xx / 1000) % 10 + '0'; - else - conv[offset] = '-'; - xx = abs(xx); - conv[offset + 1] = '.'; - conv[offset + 2] = (xx / 100) % 10 + '0'; - conv[offset + 3] = (xx / 10) % 10 + '0'; - conv[offset + 4] = (xx) % 10 + '0'; - conv[offset + 5] = 0; - return conv; + const size_t maxOffset = sizeof(conv)/sizeof(conv[0]) - 6; + if (offset>maxOffset) offset = maxOffset; + long xx = x * 1000; + if (xx >= 0) + conv[offset] = (xx / 1000) % 10 + '0'; + else + conv[offset] = '-'; + xx = abs(xx); + conv[offset + 1] = '.'; + conv[offset + 2] = (xx / 100) % 10 + '0'; + conv[offset + 3] = (xx / 10) % 10 + '0'; + conv[offset + 4] = (xx) % 10 + '0'; + conv[offset + 5] = 0; + return conv; } //Float to string with 1.23 format char *ftostr12ns(const float &x) { - long xx = x * 100; + long xx = x * 100; - xx = abs(xx); - conv[0] = (xx / 100) % 10 + '0'; - conv[1] = '.'; - conv[2] = (xx / 10) % 10 + '0'; - conv[3] = (xx) % 10 + '0'; - conv[4] = 0; - return conv; + xx = abs(xx); + conv[0] = (xx / 100) % 10 + '0'; + conv[1] = '.'; + conv[2] = (xx / 10) % 10 + '0'; + conv[3] = (xx) % 10 + '0'; + conv[4] = 0; + return conv; } //Float to string with 1.234 format @@ -135,158 +135,158 @@ char *ftostr13ns(const float &x) // convert float to space-padded string with -_23.4_ format char *ftostr32sp(const float &x) { - long xx = abs(x * 100); - uint8_t dig; + long xx = abs(x * 100); + uint8_t dig; - if (x < 0) { // negative val = -_0 - conv[0] = '-'; - dig = (xx / 1000) % 10; - conv[1] = dig ? '0' + dig : ' '; - } - else { // positive val = __0 - dig = (xx / 10000) % 10; - if (dig) { - conv[0] = '0' + dig; - conv[1] = '0' + (xx / 1000) % 10; + if (x < 0) { // negative val = -_0 + conv[0] = '-'; + dig = (xx / 1000) % 10; + conv[1] = dig ? '0' + dig : ' '; } - else { - conv[0] = ' '; - dig = (xx / 1000) % 10; - conv[1] = dig ? '0' + dig : ' '; + else { // positive val = __0 + dig = (xx / 10000) % 10; + if (dig) { + conv[0] = '0' + dig; + conv[1] = '0' + (xx / 1000) % 10; + } + else { + conv[0] = ' '; + dig = (xx / 1000) % 10; + conv[1] = dig ? '0' + dig : ' '; + } } - } - conv[2] = '0' + (xx / 100) % 10; // lsd always + conv[2] = '0' + (xx / 100) % 10; // lsd always - dig = xx % 10; - if (dig) { // 2 decimal places - conv[5] = '0' + dig; - conv[4] = '0' + (xx / 10) % 10; - conv[3] = '.'; - } - else { // 1 or 0 decimal place - dig = (xx / 10) % 10; - if (dig) { - conv[4] = '0' + dig; - conv[3] = '.'; + dig = xx % 10; + if (dig) { // 2 decimal places + conv[5] = '0' + dig; + conv[4] = '0' + (xx / 10) % 10; + conv[3] = '.'; } - else { - conv[3] = conv[4] = ' '; + else { // 1 or 0 decimal place + dig = (xx / 10) % 10; + if (dig) { + conv[4] = '0' + dig; + conv[3] = '.'; + } + else { + conv[3] = conv[4] = ' '; + } + conv[5] = ' '; } - conv[5] = ' '; - } - conv[6] = '\0'; - return conv; + conv[6] = '\0'; + return conv; } char *itostr31(const int &xx) { - conv[0] = (xx >= 0) ? '+' : '-'; - conv[1] = (xx / 1000) % 10 + '0'; - conv[2] = (xx / 100) % 10 + '0'; - conv[3] = (xx / 10) % 10 + '0'; - conv[4] = '.'; - conv[5] = (xx) % 10 + '0'; - conv[6] = 0; - return conv; + conv[0] = (xx >= 0) ? '+' : '-'; + conv[1] = (xx / 1000) % 10 + '0'; + conv[2] = (xx / 100) % 10 + '0'; + conv[3] = (xx / 10) % 10 + '0'; + conv[4] = '.'; + conv[5] = (xx) % 10 + '0'; + conv[6] = 0; + return conv; } // Convert int to rj string with 123 or -12 format char *itostr3(const int &x) { - int xx = x; - if (xx < 0) { - conv[0] = '-'; - xx = -xx; - } else if (xx >= 100) - conv[0] = (xx / 100) % 10 + '0'; - else - conv[0] = ' '; - if (xx >= 10) - conv[1] = (xx / 10) % 10 + '0'; - else - conv[1] = ' '; - conv[2] = (xx) % 10 + '0'; - conv[3] = 0; - return conv; + int xx = x; + if (xx < 0) { + conv[0] = '-'; + xx = -xx; + } else if (xx >= 100) + conv[0] = (xx / 100) % 10 + '0'; + else + conv[0] = ' '; + if (xx >= 10) + conv[1] = (xx / 10) % 10 + '0'; + else + conv[1] = ' '; + conv[2] = (xx) % 10 + '0'; + conv[3] = 0; + return conv; } // Convert int to lj string with 123 format char *itostr3left(const int &xx) { - if (xx >= 100) - { - conv[0] = (xx / 100) % 10 + '0'; - conv[1] = (xx / 10) % 10 + '0'; - conv[2] = (xx) % 10 + '0'; - conv[3] = 0; - } - else if (xx >= 10) - { - conv[0] = (xx / 10) % 10 + '0'; - conv[1] = (xx) % 10 + '0'; - conv[2] = 0; - } - else - { - conv[0] = (xx) % 10 + '0'; - conv[1] = 0; - } - return conv; + if (xx >= 100) + { + conv[0] = (xx / 100) % 10 + '0'; + conv[1] = (xx / 10) % 10 + '0'; + conv[2] = (xx) % 10 + '0'; + conv[3] = 0; + } + else if (xx >= 10) + { + conv[0] = (xx / 10) % 10 + '0'; + conv[1] = (xx) % 10 + '0'; + conv[2] = 0; + } + else + { + conv[0] = (xx) % 10 + '0'; + conv[1] = 0; + } + return conv; } // Convert int to rj string with 1234 format char *itostr4(const int &xx) { - conv[0] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' '; - conv[1] = xx >= 100 ? (xx / 100) % 10 + '0' : ' '; - conv[2] = xx >= 10 ? (xx / 10) % 10 + '0' : ' '; - conv[3] = xx % 10 + '0'; - conv[4] = 0; - return conv; + conv[0] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' '; + conv[1] = xx >= 100 ? (xx / 100) % 10 + '0' : ' '; + conv[2] = xx >= 10 ? (xx / 10) % 10 + '0' : ' '; + conv[3] = xx % 10 + '0'; + conv[4] = 0; + return conv; } // Convert float to rj string with 12345 format char *ftostr5(const float &x) { - long xx = abs(x); - conv[0] = xx >= 10000 ? (xx / 10000) % 10 + '0' : ' '; - conv[1] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' '; - conv[2] = xx >= 100 ? (xx / 100) % 10 + '0' : ' '; - conv[3] = xx >= 10 ? (xx / 10) % 10 + '0' : ' '; - conv[4] = xx % 10 + '0'; - conv[5] = 0; - return conv; + long xx = abs(x); + conv[0] = xx >= 10000 ? (xx / 10000) % 10 + '0' : ' '; + conv[1] = xx >= 1000 ? (xx / 1000) % 10 + '0' : ' '; + conv[2] = xx >= 100 ? (xx / 100) % 10 + '0' : ' '; + conv[3] = xx >= 10 ? (xx / 10) % 10 + '0' : ' '; + conv[4] = xx % 10 + '0'; + conv[5] = 0; + return conv; } // Convert float to string with +1234.5 format char *ftostr51(const float &x) { - long xx = x * 10; - conv[0] = (xx >= 0) ? '+' : '-'; - xx = abs(xx); - conv[1] = (xx / 10000) % 10 + '0'; - conv[2] = (xx / 1000) % 10 + '0'; - conv[3] = (xx / 100) % 10 + '0'; - conv[4] = (xx / 10) % 10 + '0'; - conv[5] = '.'; - conv[6] = (xx) % 10 + '0'; - conv[7] = 0; - return conv; + long xx = x * 10; + conv[0] = (xx >= 0) ? '+' : '-'; + xx = abs(xx); + conv[1] = (xx / 10000) % 10 + '0'; + conv[2] = (xx / 1000) % 10 + '0'; + conv[3] = (xx / 100) % 10 + '0'; + conv[4] = (xx / 10) % 10 + '0'; + conv[5] = '.'; + conv[6] = (xx) % 10 + '0'; + conv[7] = 0; + return conv; } // Convert float to string with +123.45 format char *ftostr52(const float &x) { - long xx = x * 100; - conv[0] = (xx >= 0) ? '+' : '-'; - xx = abs(xx); - conv[1] = (xx / 10000) % 10 + '0'; - conv[2] = (xx / 1000) % 10 + '0'; - conv[3] = (xx / 100) % 10 + '0'; - conv[4] = '.'; - conv[5] = (xx / 10) % 10 + '0'; - conv[6] = (xx) % 10 + '0'; - conv[7] = 0; - return conv; + long xx = x * 100; + conv[0] = (xx >= 0) ? '+' : '-'; + xx = abs(xx); + conv[1] = (xx / 10000) % 10 + '0'; + conv[2] = (xx / 1000) % 10 + '0'; + conv[3] = (xx / 100) % 10 + '0'; + conv[4] = '.'; + conv[5] = (xx / 10) % 10 + '0'; + conv[6] = (xx) % 10 + '0'; + conv[7] = 0; + return conv; } diff --git a/Firmware/eeprom.h b/Firmware/eeprom.h index da003990fd..04dff25f4c 100755 --- a/Firmware/eeprom.h +++ b/Firmware/eeprom.h @@ -47,7 +47,7 @@ #define EEPROM_UVLO_TARGET_HOTEND (EEPROM_UVLO_CURRENT_POSITION_Z - 1) #define EEPROM_UVLO_TARGET_BED (EEPROM_UVLO_TARGET_HOTEND - 1) #define EEPROM_UVLO_FEEDRATE (EEPROM_UVLO_TARGET_BED - 2) -#define EEPROM_UVLO_FAN_SPEED (EEPROM_UVLO_FEEDRATE - 1) +#define EEPROM_UVLO_FAN_SPEED (EEPROM_UVLO_FEEDRATE - 1) #define EEPROM_FAN_CHECK_ENABLED (EEPROM_UVLO_FAN_SPEED - 1) #define EEPROM_UVLO_MESH_BED_LEVELING (EEPROM_FAN_CHECK_ENABLED - 9*2) @@ -55,11 +55,11 @@ #define EEPROM_UVLO_E_ABS (EEPROM_UVLO_Z_MICROSTEPS - 1) #define EEPROM_UVLO_CURRENT_POSITION_E (EEPROM_UVLO_E_ABS - 4) //float for current position in E -// Crash detection mode EEPROM setting +// Crash detection mode EEPROM setting #define EEPROM_CRASH_DET (EEPROM_UVLO_CURRENT_POSITION_E - 5) // float (orig EEPROM_UVLO_MESH_BED_LEVELING-12) // Crash detection counter Y (last print) #define EEPROM_CRASH_COUNT_Y (EEPROM_CRASH_DET - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-15) -// Filament sensor on/off EEPROM setting +// Filament sensor on/off EEPROM setting #define EEPROM_FSENSOR (EEPROM_CRASH_COUNT_Y - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-14) // Crash detection counter X (last print) #define EEPROM_CRASH_COUNT_X (EEPROM_FSENSOR - 1) // uint8 (orig EEPROM_UVLO_MESH_BED_LEVELING-15) @@ -90,7 +90,7 @@ #define EEPROM_POWER_COUNT_TOT (EEPROM_FERROR_COUNT_TOT - 2) // uint16 //////////////////////////////////////// -// TMC2130 Accurate sensorless homing +// TMC2130 Accurate sensorless homing // X-axis home origin (stepper phase in microsteps, 0..63 for 16ustep resolution) #define EEPROM_TMC2130_HOME_X_ORIGIN (EEPROM_POWER_COUNT_TOT - 1) // uint8 diff --git a/Firmware/fastio.h b/Firmware/fastio.h index e4f25ed8b5..99e3967d70 100755 --- a/Firmware/fastio.h +++ b/Firmware/fastio.h @@ -69,7 +69,7 @@ /// Write to a pin wrapper, non critical. /// This macro is cheaper than WRITE(IO,v) on ports H,I,J,K,L, as _WRITE_C disables / enables interrupts /// and stores the old CPU flags on the stack. -/// This macro should only be called, where it cannot be interrupted. +/// This macro should only be called, where it cannot be interrupted. #define WRITE_NC(IO, v) _WRITE_NC(IO, v) /// toggle a pin wrapper @@ -2074,7 +2074,7 @@ pins pins */ -//#define AT90USBxx_TEENSYPP_ASSIGNMENTS // Use Teensy++ 2.0 assignments +//#define AT90USBxx_TEENSYPP_ASSIGNMENTS // Use Teensy++ 2.0 assignments #ifndef AT90USBxx_TEENSYPP_ASSIGNMENTS // Use traditional Marlin pin assignments #define DIO0_PIN PINA0 @@ -2714,8 +2714,8 @@ pins /* -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 +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. diff --git a/Firmware/fsensor.cpp b/Firmware/fsensor.cpp index ebcbc27625..2c927a2404 100644 --- a/Firmware/fsensor.cpp +++ b/Firmware/fsensor.cpp @@ -177,7 +177,7 @@ bool fsensor_enable(void) fsensor_not_responding = false; else fsensor_not_responding = true; - fsensor_enabled = true; + fsensor_enabled = pat9125 ? true : false; fsensor_autoload_set(true); fsensor_autoload_enabled = false; fsensor_oq_meassure = false; @@ -198,17 +198,17 @@ void fsensor_disable(void) void fsensor_autoload_set(bool State) { - if (!State) fsensor_autoload_check_stop(); - fsensor_autoload_enabled = State; - eeprom_update_byte((unsigned char *)EEPROM_FSENS_AUTOLOAD_ENABLED, fsensor_autoload_enabled); + if (!State) fsensor_autoload_check_stop(); + fsensor_autoload_enabled = State; + eeprom_update_byte((unsigned char *)EEPROM_FSENS_AUTOLOAD_ENABLED, fsensor_autoload_enabled); } void pciSetup(byte pin) { // !!! "digitalPinTo?????bit()" does not provide the correct results for some MCU pins - *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin - PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt - PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group + *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin + PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt + PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group } void fsensor_autoload_check_start(void) @@ -291,12 +291,13 @@ bool fsensor_check_autoload(void) if (fsensor_autoload_c != fsensor_autoload_c_old) printf_P(PSTR("fsensor_check_autoload dy=%d c=%d sum=%d\n"), dy, fsensor_autoload_c, fsensor_autoload_sum); #endif -// if ((fsensor_autoload_c >= 15) && (fsensor_autoload_sum > 30)) if ((fsensor_autoload_c >= 12) && (fsensor_autoload_sum > 20)) { - if (mmu_enabled) mmu_command(MMU_CMD_FS); - fsensor_autoload_check_stop(); - fsensor_autoload_enabled = false; + if (mmu_enabled) { + mmu_command(MMU_CMD_FS); + fsensor_autoload_check_stop(); + fsensor_autoload_enabled = false; + } return true; } return false; @@ -378,73 +379,73 @@ bool fsensor_oq_result(void) ISR(FSENSOR_INT_PIN_VECT) { - if (!((fsensor_int_pin_old ^ FSENSOR_INT_PIN_PIN_REG) & FSENSOR_INT_PIN_MASK)) return; - fsensor_int_pin_old = FSENSOR_INT_PIN_PIN_REG; - static bool _lock = false; - if (_lock) return; - _lock = true; - int st_cnt = fsensor_st_cnt; - fsensor_st_cnt = 0; - sei(); - uint8_t old_err_cnt = fsensor_err_cnt; - uint8_t pat9125_res = fsensor_oq_meassure?pat9125_update():pat9125_update_y(); - if (!pat9125_res) - { - fsensor_disable(); - fsensor_not_responding = true; - printf_P(ERRMSG_PAT9125_NOT_RESP, 1); - } - if (st_cnt != 0) - { //movement - if (st_cnt > 0) //positive movement + if (!((fsensor_int_pin_old ^ FSENSOR_INT_PIN_PIN_REG) & FSENSOR_INT_PIN_MASK)) return; + fsensor_int_pin_old = FSENSOR_INT_PIN_PIN_REG; + static bool _lock = false; + if (_lock) return; + _lock = true; + int st_cnt = fsensor_st_cnt; + fsensor_st_cnt = 0; + sei(); + uint8_t old_err_cnt = fsensor_err_cnt; + uint8_t pat9125_res = fsensor_oq_meassure?pat9125_update():pat9125_update_y(); + if (!pat9125_res) { - if (pat9125_y < 0) - { - if (fsensor_err_cnt) - fsensor_err_cnt += 2; - else - fsensor_err_cnt++; - } - else if (pat9125_y > 0) - { - if (fsensor_err_cnt) - fsensor_err_cnt--; - } - else //(pat9125_y == 0) - if (((fsensor_dy_old <= 0) || (fsensor_err_cnt)) && (st_cnt > (fsensor_chunk_len >> 1))) - fsensor_err_cnt++; - if (fsensor_oq_meassure) - { - if (fsensor_oq_skipchunk) + fsensor_disable(); + fsensor_not_responding = true; + printf_P(ERRMSG_PAT9125_NOT_RESP, 1); + } + if (st_cnt != 0) + { //movement + if (st_cnt > 0) //positive movement { - fsensor_oq_skipchunk--; - fsensor_err_cnt = 0; + if (pat9125_y < 0) + { + if (fsensor_err_cnt) + fsensor_err_cnt += 2; + else + fsensor_err_cnt++; + } + else if (pat9125_y > 0) + { + if (fsensor_err_cnt) + fsensor_err_cnt--; + } + else //(pat9125_y == 0) + if (((fsensor_dy_old <= 0) || (fsensor_err_cnt)) && (st_cnt > (fsensor_chunk_len >> 1))) + fsensor_err_cnt++; + if (fsensor_oq_meassure) + { + if (fsensor_oq_skipchunk) + { + fsensor_oq_skipchunk--; + fsensor_err_cnt = 0; + } + else + { + if (st_cnt == fsensor_chunk_len) + { + if (pat9125_y > 0) if (fsensor_oq_yd_min > pat9125_y) fsensor_oq_yd_min = (fsensor_oq_yd_min + pat9125_y) / 2; + if (pat9125_y >= 0) if (fsensor_oq_yd_max < pat9125_y) fsensor_oq_yd_max = (fsensor_oq_yd_max + pat9125_y) / 2; + } + fsensor_oq_samples++; + fsensor_oq_st_sum += st_cnt; + if (pat9125_y > 0) fsensor_oq_yd_sum += pat9125_y; + if (fsensor_err_cnt > old_err_cnt) + fsensor_oq_er_sum += (fsensor_err_cnt - old_err_cnt); + if (fsensor_oq_er_max < fsensor_err_cnt) + fsensor_oq_er_max = fsensor_err_cnt; + fsensor_oq_sh_sum += pat9125_s; + } + } } - else + else //negative movement { - if (st_cnt == fsensor_chunk_len) - { - if (pat9125_y > 0) if (fsensor_oq_yd_min > pat9125_y) fsensor_oq_yd_min = (fsensor_oq_yd_min + pat9125_y) / 2; - if (pat9125_y >= 0) if (fsensor_oq_yd_max < pat9125_y) fsensor_oq_yd_max = (fsensor_oq_yd_max + pat9125_y) / 2; - } - fsensor_oq_samples++; - fsensor_oq_st_sum += st_cnt; - if (pat9125_y > 0) fsensor_oq_yd_sum += pat9125_y; - if (fsensor_err_cnt > old_err_cnt) - fsensor_oq_er_sum += (fsensor_err_cnt - old_err_cnt); - if (fsensor_oq_er_max < fsensor_err_cnt) - fsensor_oq_er_max = fsensor_err_cnt; - fsensor_oq_sh_sum += pat9125_s; } - } } - else //negative movement - { + else + { //no movement } - } - else - { //no movement - } #ifdef DEBUG_FSENSOR_LOG if (fsensor_log) @@ -463,26 +464,34 @@ ISR(FSENSOR_INT_PIN_VECT) void fsensor_st_block_begin(block_t* bl) { - if (!fsensor_enabled) return; - if (((fsensor_st_cnt > 0) && (bl->direction_bits & 0x8)) || - ((fsensor_st_cnt < 0) && !(bl->direction_bits & 0x8))) - { + if (!fsensor_enabled) return; + if (((fsensor_st_cnt > 0) && (bl->direction_bits & 0x8)) || + ((fsensor_st_cnt < 0) && !(bl->direction_bits & 0x8))) + { // !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins - if (PIN_GET(FSENSOR_INT_PIN)) {PIN_VAL(FSENSOR_INT_PIN, LOW);} - else {PIN_VAL(FSENSOR_INT_PIN, HIGH);} - } + if (PIN_GET(FSENSOR_INT_PIN)) { + PIN_VAL(FSENSOR_INT_PIN, LOW); + } + else { + PIN_VAL(FSENSOR_INT_PIN, HIGH); + } + } } void fsensor_st_block_chunk(block_t* bl, int cnt) { - if (!fsensor_enabled) return; - fsensor_st_cnt += (bl->direction_bits & 0x8)?-cnt:cnt; - if ((fsensor_st_cnt >= fsensor_chunk_len) || (fsensor_st_cnt <= -fsensor_chunk_len)) - { + if (!fsensor_enabled) return; + fsensor_st_cnt += (bl->direction_bits & 0x8)?-cnt:cnt; + if ((fsensor_st_cnt >= fsensor_chunk_len) || (fsensor_st_cnt <= -fsensor_chunk_len)) + { // !!! bit toggling (PINxn <- 1) (for PinChangeInterrupt) does not work for some MCU pins - if (PIN_GET(FSENSOR_INT_PIN)) {PIN_VAL(FSENSOR_INT_PIN, LOW);} - else {PIN_VAL(FSENSOR_INT_PIN, HIGH);} - } + if (PIN_GET(FSENSOR_INT_PIN)) { + PIN_VAL(FSENSOR_INT_PIN, LOW); + } + else { + PIN_VAL(FSENSOR_INT_PIN, HIGH); + } + } } //! @brief filament sensor update (perform M600 on filament runout) @@ -551,10 +560,10 @@ void fsensor_setup_interrupt(void) digitalWrite(FSENSOR_INT_PIN, LOW); fsensor_int_pin_old = 0; - //pciSetup(FSENSOR_INT_PIN); + //pciSetup(FSENSOR_INT_PIN); // !!! "pciSetup()" does not provide the correct results for some MCU pins // so interrupt registers settings: - FSENSOR_INT_PIN_PCMSK_REG |= bit(FSENSOR_INT_PIN_PCMSK_BIT); // enable corresponding PinChangeInterrupt (individual pin) - PCIFR |= bit(FSENSOR_INT_PIN_PCICR_BIT); // clear previous occasional interrupt (set of pins) - PCICR |= bit(FSENSOR_INT_PIN_PCICR_BIT); // enable corresponding PinChangeInterrupt (set of pins) + FSENSOR_INT_PIN_PCMSK_REG |= bit(FSENSOR_INT_PIN_PCMSK_BIT); // enable corresponding PinChangeInterrupt (individual pin) + PCIFR |= bit(FSENSOR_INT_PIN_PCICR_BIT); // clear previous occasional interrupt (set of pins) + PCICR |= bit(FSENSOR_INT_PIN_PCICR_BIT); // enable corresponding PinChangeInterrupt (set of pins) } diff --git a/Firmware/language.c b/Firmware/language.c index 3c168638ec..7ae9d2f4c9 100755 --- a/Firmware/language.c +++ b/Firmware/language.c @@ -17,12 +17,22 @@ uint8_t lang_selected = 0; #if (LANG_MODE == 0) //primary language only -uint8_t lang_select(uint8_t lang) { return 0; } -uint8_t lang_get_count() { return 1; } -uint16_t lang_get_code(uint8_t lang) { return LANG_CODE_EN; } -const char* lang_get_name_by_code(uint16_t code) { return _n("English"); } +uint8_t lang_select(uint8_t lang) { + return 0; +} +uint8_t lang_get_count() { + return 1; +} +uint16_t lang_get_code(uint8_t lang) { + return LANG_CODE_EN; +} +const char* lang_get_name_by_code(uint16_t code) { + return _n("English"); +} void lang_reset(void) { } -uint8_t lang_is_selected(void) { return 1; } +uint8_t lang_is_selected(void) { + return 1; +} #else //(LANG_MODE == 0) //secondary languages in progmem or xflash @@ -37,227 +47,235 @@ lang_table_t* lang_table = 0; const char* lang_get_translation(const char* s) { - if (lang_selected == 0) return s + 2; //primary language selected, return orig. str. - if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str. - uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id - if (ui == 0xffff) return s + 2; //translation not found, return orig. str. - ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset - if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character - return s + 2;//zero length string == not translated, return orig. str. - return (const char*)((char*)lang_table + ui); //return calculated pointer + if (lang_selected == 0) return s + 2; //primary language selected, return orig. str. + if (lang_table == 0) return s + 2; //sec. lang table not found, return orig. str. + uint16_t ui = pgm_read_word(((uint16_t*)s)); //read string id + if (ui == 0xffff) return s + 2; //translation not found, return orig. str. + ui = pgm_read_word(((uint16_t*)(((char*)lang_table + 16 + ui*2)))); //read relative offset + if (pgm_read_byte(((uint8_t*)((char*)lang_table + ui))) == 0) //read first character + return s + 2;//zero length string == not translated, return orig. str. + return (const char*)((char*)lang_table + ui); //return calculated pointer } uint8_t lang_select(uint8_t lang) { - if (lang == LANG_ID_PRI) //primary language - { - lang_table = 0; - lang_selected = lang; - } + if (lang == LANG_ID_PRI) //primary language + { + lang_table = 0; + lang_selected = lang; + } #ifdef W25X20CL - if (lang_get_code(lang) == lang_get_code(LANG_ID_SEC)) lang = LANG_ID_SEC; - if (lang == LANG_ID_SEC) //current secondary language - { - if (pgm_read_dword(((uint32_t*)_SEC_LANG_TABLE)) == LANG_MAGIC) //magic valid - { - if (lang_check(_SEC_LANG_TABLE)) - if (pgm_read_dword(((uint32_t*)(_SEC_LANG_TABLE + 12))) == pgm_read_dword(((uint32_t*)(_PRI_LANG_SIGNATURE)))) //signature valid - { - lang_table = (lang_table_t*)(_SEC_LANG_TABLE); // set table pointer - lang_selected = lang; // set language id - } - } - } + if (lang_get_code(lang) == lang_get_code(LANG_ID_SEC)) lang = LANG_ID_SEC; + if (lang == LANG_ID_SEC) //current secondary language + { + if (pgm_read_dword(((uint32_t*)_SEC_LANG_TABLE)) == LANG_MAGIC) //magic valid + { + if (lang_check(_SEC_LANG_TABLE)) + if (pgm_read_dword(((uint32_t*)(_SEC_LANG_TABLE + 12))) == pgm_read_dword(((uint32_t*)(_PRI_LANG_SIGNATURE)))) //signature valid + { + lang_table = (lang_table_t*)(_SEC_LANG_TABLE); // set table pointer + lang_selected = lang; // set language id + } + } + } #else //W25X20CL - if (lang == LANG_ID_SEC) - { - uint16_t table = _SEC_LANG_TABLE; - if (pgm_read_dword(((uint32_t*)table)) == LANG_MAGIC) //magic valid - { - if (lang_check(table)) - if (pgm_read_dword(((uint32_t*)(table + 12))) == pgm_read_dword(((uint32_t*)(_PRI_LANG_SIGNATURE)))) //signature valid - { - lang_table = table; // set table pointer - lang_selected = lang; // set language id - } - } - } + if (lang == LANG_ID_SEC) + { + uint16_t table = _SEC_LANG_TABLE; + if (pgm_read_dword(((uint32_t*)table)) == LANG_MAGIC) //magic valid + { + if (lang_check(table)) + if (pgm_read_dword(((uint32_t*)(table + 12))) == pgm_read_dword(((uint32_t*)(_PRI_LANG_SIGNATURE)))) //signature valid + { + lang_table = table; // set table pointer + lang_selected = lang; // set language id + } + } + } #endif //W25X20CL - if (lang_selected == lang) - { - eeprom_update_byte((unsigned char*)EEPROM_LANG, lang_selected); - return 1; - } - return 0; + if (lang_selected == lang) + { + eeprom_update_byte((unsigned char*)EEPROM_LANG, lang_selected); + return 1; + } + return 0; } uint8_t lang_check(uint16_t addr) { - uint16_t sum = 0; - uint16_t size = pgm_read_word((uint16_t*)(addr + 4)); - uint16_t lt_sum = pgm_read_word((uint16_t*)(addr + 8)); - uint16_t i; for (i = 0; i < size; i++) - sum += (uint16_t)pgm_read_byte((uint8_t*)(addr + i)) << ((i & 1)?0:8); - sum -= lt_sum; //subtract checksum - sum = (sum >> 8) | ((sum & 0xff) << 8); //swap bytes - return (sum == lt_sum); + uint16_t sum = 0; + uint16_t size = pgm_read_word((uint16_t*)(addr + 4)); + uint16_t lt_sum = pgm_read_word((uint16_t*)(addr + 8)); + uint16_t i; + for (i = 0; i < size; i++) + sum += (uint16_t)pgm_read_byte((uint8_t*)(addr + i)) << ((i & 1)?0:8); + sum -= lt_sum; //subtract checksum + sum = (sum >> 8) | ((sum & 0xff) << 8); //swap bytes + return (sum == lt_sum); } uint8_t lang_get_count() { - if (pgm_read_dword(((uint32_t*)(_PRI_LANG_SIGNATURE))) == 0xffffffff) - return 1; //signature not set - only primary language will be available + if (pgm_read_dword(((uint32_t*)(_PRI_LANG_SIGNATURE))) == 0xffffffff) + return 1; //signature not set - only primary language will be available #ifdef W25X20CL - W25X20CL_SPI_ENTER(); - uint8_t count = 2; //count = 1+n (primary + secondary + all in xflash) - uint32_t addr = 0x00000; //start of xflash - lang_table_header_t header; //table header structure - while (1) - { - w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); //read table header from xflash - if (header.magic != LANG_MAGIC) break; //break if magic not valid - addr += header.size; //calc address of next table - count++; //inc counter - } + W25X20CL_SPI_ENTER(); + uint8_t count = 2; //count = 1+n (primary + secondary + all in xflash) + uint32_t addr = 0x00000; //start of xflash + lang_table_header_t header; //table header structure + while (1) + { + w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); //read table header from xflash + if (header.magic != LANG_MAGIC) break; //break if magic not valid + addr += header.size; //calc address of next table + count++; //inc counter + } #else //W25X20CL - uint16_t table = _SEC_LANG_TABLE; - uint8_t count = 1; //count = 1 (primary) - while (pgm_read_dword(((uint32_t*)table)) == LANG_MAGIC) //magic valid - { - table += pgm_read_word((uint16_t*)(table + 4)); - count++; - } + uint16_t table = _SEC_LANG_TABLE; + uint8_t count = 1; //count = 1 (primary) + while (pgm_read_dword(((uint32_t*)table)) == LANG_MAGIC) //magic valid + { + table += pgm_read_word((uint16_t*)(table + 4)); + count++; + } #endif //W25X20CL - return count; + return count; } uint8_t lang_get_header(uint8_t lang, lang_table_header_t* header, uint32_t* offset) { - if (lang == LANG_ID_PRI) return 0; //primary lang not supported for this function + if (lang == LANG_ID_PRI) return 0; //primary lang not supported for this function #ifdef W25X20CL - if (lang == LANG_ID_SEC) - { - uint16_t ui = _SEC_LANG_TABLE; //table pointer - memcpy_P(header, (lang_table_t*)(_SEC_LANG_TABLE), sizeof(lang_table_header_t)); //read table header from progmem - if (offset) *offset = ui; - return (header->magic == LANG_MAGIC)?1:0; //return 1 if magic valid - } - W25X20CL_SPI_ENTER(); - uint32_t addr = 0x00000; //start of xflash - lang--; - while (1) - { - w25x20cl_rd_data(addr, (uint8_t*)(header), sizeof(lang_table_header_t)); //read table header from xflash - if (header->magic != LANG_MAGIC) break; //break if not valid - if (offset) *offset = addr; - if (--lang == 0) return 1; - addr += header->size; //calc address of next table - } + if (lang == LANG_ID_SEC) + { + uint16_t ui = _SEC_LANG_TABLE; //table pointer + memcpy_P(header, (lang_table_t*)(_SEC_LANG_TABLE), sizeof(lang_table_header_t)); //read table header from progmem + if (offset) *offset = ui; + return (header->magic == LANG_MAGIC)?1:0; //return 1 if magic valid + } + W25X20CL_SPI_ENTER(); + uint32_t addr = 0x00000; //start of xflash + lang--; + while (1) + { + w25x20cl_rd_data(addr, (uint8_t*)(header), sizeof(lang_table_header_t)); //read table header from xflash + if (header->magic != LANG_MAGIC) break; //break if not valid + if (offset) *offset = addr; + if (--lang == 0) return 1; + addr += header->size; //calc address of next table + } #else //W25X20CL - if (lang == LANG_ID_SEC) - { - uint16_t ui = _SEC_LANG_TABLE; //table pointer - memcpy_P(header, ui, sizeof(lang_table_header_t)); //read table header from progmem - if (offset) *offset = ui; - return (header->magic == LANG_MAGIC)?1:0; //return 1 if magic valid - } + if (lang == LANG_ID_SEC) + { + uint16_t ui = _SEC_LANG_TABLE; //table pointer + memcpy_P(header, ui, sizeof(lang_table_header_t)); //read table header from progmem + if (offset) *offset = ui; + return (header->magic == LANG_MAGIC)?1:0; //return 1 if magic valid + } #endif //W25X20CL - return 0; + return 0; } uint16_t lang_get_code(uint8_t lang) { - if (lang == LANG_ID_PRI) return LANG_CODE_EN; //primary lang = EN + if (lang == LANG_ID_PRI) return LANG_CODE_EN; //primary lang = EN #ifdef W25X20CL - if (lang == LANG_ID_SEC) - { - uint16_t ui = _SEC_LANG_TABLE; //table pointer - if (pgm_read_dword(((uint32_t*)(ui + 0))) != LANG_MAGIC) return LANG_CODE_XX; //magic not valid - return pgm_read_word(((uint32_t*)(ui + 10))); //return lang code from progmem - } - W25X20CL_SPI_ENTER(); - uint32_t addr = 0x00000; //start of xflash - lang_table_header_t header; //table header structure - lang--; - while (1) - { - w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); //read table header from xflash - if (header.magic != LANG_MAGIC) break; //break if not valid - if (--lang == 0) return header.code; - addr += header.size; //calc address of next table - } + if (lang == LANG_ID_SEC) + { + uint16_t ui = _SEC_LANG_TABLE; //table pointer + if (pgm_read_dword(((uint32_t*)(ui + 0))) != LANG_MAGIC) return LANG_CODE_XX; //magic not valid + return pgm_read_word(((uint32_t*)(ui + 10))); //return lang code from progmem + } + W25X20CL_SPI_ENTER(); + uint32_t addr = 0x00000; //start of xflash + lang_table_header_t header; //table header structure + lang--; + while (1) + { + w25x20cl_rd_data(addr, (uint8_t*)&header, sizeof(lang_table_header_t)); //read table header from xflash + if (header.magic != LANG_MAGIC) break; //break if not valid + if (--lang == 0) return header.code; + addr += header.size; //calc address of next table + } #else //W25X20CL - uint16_t table = _SEC_LANG_TABLE; - uint8_t count = 1; //count = 1 (primary) - while (pgm_read_dword((uint32_t*)table) == LANG_MAGIC) //magic valid - { - if (count == lang) return pgm_read_word(((uint16_t*)(table + 10))); //read language code - table += pgm_read_word((uint16_t*)(table + 4)); - count++; - } + uint16_t table = _SEC_LANG_TABLE; + uint8_t count = 1; //count = 1 (primary) + while (pgm_read_dword((uint32_t*)table) == LANG_MAGIC) //magic valid + { + if (count == lang) return pgm_read_word(((uint16_t*)(table + 10))); //read language code + table += pgm_read_word((uint16_t*)(table + 4)); + count++; + } #endif //W25X20CL - return LANG_CODE_XX; + return LANG_CODE_XX; } const char* lang_get_name_by_code(uint16_t code) { - switch (code) - { - case LANG_CODE_EN: return _n("English"); - case LANG_CODE_CZ: return _n("Cestina"); - case LANG_CODE_DE: return _n("Deutsch"); - case LANG_CODE_ES: return _n("Espanol"); - case LANG_CODE_FR: return _n("Francais"); - case LANG_CODE_IT: return _n("Italiano"); - case LANG_CODE_PL: return _n("Polski"); - } - return _n("??"); + switch (code) + { + case LANG_CODE_EN: + return _n("English"); + case LANG_CODE_CZ: + return _n("Cestina"); + case LANG_CODE_DE: + return _n("Deutsch"); + case LANG_CODE_ES: + return _n("Espanol"); + case LANG_CODE_FR: + return _n("Francais"); + case LANG_CODE_IT: + return _n("Italiano"); + case LANG_CODE_PL: + return _n("Polski"); + } + return _n("??"); } void lang_reset(void) { - lang_selected = 0; - eeprom_update_byte((unsigned char*)EEPROM_LANG, LANG_ID_FORCE_SELECTION); + lang_selected = 0; + eeprom_update_byte((unsigned char*)EEPROM_LANG, LANG_ID_FORCE_SELECTION); } uint8_t lang_is_selected(void) { - uint8_t lang_eeprom = eeprom_read_byte((unsigned char*)EEPROM_LANG); - return (lang_eeprom != LANG_ID_FORCE_SELECTION) && (lang_eeprom == lang_selected); + uint8_t lang_eeprom = eeprom_read_byte((unsigned char*)EEPROM_LANG); + return (lang_eeprom != LANG_ID_FORCE_SELECTION) && (lang_eeprom == lang_selected); } #ifdef DEBUG_SEC_LANG #include const char* lang_get_sec_lang_str_by_id(uint16_t id) { - uint16_t ui = _SEC_LANG_TABLE; //table pointer - return ui + pgm_read_word(((uint16_t*)(ui + 16 + id * 2))); //read relative offset and return calculated pointer + uint16_t ui = _SEC_LANG_TABLE; //table pointer + return ui + pgm_read_word(((uint16_t*)(ui + 16 + id * 2))); //read relative offset and return calculated pointer } uint16_t lang_print_sec_lang(FILE* out) { - printf_P(_n("&_SEC_LANG = 0x%04x\n"), &_SEC_LANG); - printf_P(_n("sizeof(_SEC_LANG) = 0x%04x\n"), sizeof(_SEC_LANG)); - uint16_t ptr_lang_table0 = ((uint16_t)(&_SEC_LANG) + 0xff) & 0xff00; - printf_P(_n("&_lang_table0 = 0x%04x\n"), ptr_lang_table0); - uint32_t _lt_magic = pgm_read_dword(((uint32_t*)(ptr_lang_table0 + 0))); - uint16_t _lt_size = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 4))); - uint16_t _lt_count = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 6))); - uint16_t _lt_chsum = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 8))); - uint16_t _lt_resv0 = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 10))); - uint32_t _lt_resv1 = pgm_read_dword(((uint32_t*)(ptr_lang_table0 + 12))); - printf_P(_n(" _lt_magic = 0x%08lx %S\n"), _lt_magic, (_lt_magic==LANG_MAGIC)?_n("OK"):_n("NA")); - printf_P(_n(" _lt_size = 0x%04x (%d)\n"), _lt_size, _lt_size); - printf_P(_n(" _lt_count = 0x%04x (%d)\n"), _lt_count, _lt_count); - printf_P(_n(" _lt_chsum = 0x%04x\n"), _lt_chsum); - printf_P(_n(" _lt_resv0 = 0x%04x\n"), _lt_resv0); - printf_P(_n(" _lt_resv1 = 0x%08lx\n"), _lt_resv1); - if (_lt_magic != LANG_MAGIC) return 0; - puts_P(_n(" strings:\n")); - uint16_t ui = _SEC_LANG_TABLE; //table pointer - for (ui = 0; ui < _lt_count; ui++) - fprintf_P(out, _n(" %3d %S\n"), ui, lang_get_sec_lang_str_by_id(ui)); - return _lt_count; + printf_P(_n("&_SEC_LANG = 0x%04x\n"), &_SEC_LANG); + printf_P(_n("sizeof(_SEC_LANG) = 0x%04x\n"), sizeof(_SEC_LANG)); + uint16_t ptr_lang_table0 = ((uint16_t)(&_SEC_LANG) + 0xff) & 0xff00; + printf_P(_n("&_lang_table0 = 0x%04x\n"), ptr_lang_table0); + uint32_t _lt_magic = pgm_read_dword(((uint32_t*)(ptr_lang_table0 + 0))); + uint16_t _lt_size = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 4))); + uint16_t _lt_count = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 6))); + uint16_t _lt_chsum = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 8))); + uint16_t _lt_resv0 = pgm_read_word(((uint16_t*)(ptr_lang_table0 + 10))); + uint32_t _lt_resv1 = pgm_read_dword(((uint32_t*)(ptr_lang_table0 + 12))); + printf_P(_n(" _lt_magic = 0x%08lx %S\n"), _lt_magic, (_lt_magic==LANG_MAGIC)?_n("OK"):_n("NA")); + printf_P(_n(" _lt_size = 0x%04x (%d)\n"), _lt_size, _lt_size); + printf_P(_n(" _lt_count = 0x%04x (%d)\n"), _lt_count, _lt_count); + printf_P(_n(" _lt_chsum = 0x%04x\n"), _lt_chsum); + printf_P(_n(" _lt_resv0 = 0x%04x\n"), _lt_resv0); + printf_P(_n(" _lt_resv1 = 0x%08lx\n"), _lt_resv1); + if (_lt_magic != LANG_MAGIC) return 0; + puts_P(_n(" strings:\n")); + uint16_t ui = _SEC_LANG_TABLE; //table pointer + for (ui = 0; ui < _lt_count; ui++) + fprintf_P(out, _n(" %3d %S\n"), ui, lang_get_sec_lang_str_by_id(ui)); + return _lt_count; } #endif //DEBUG_SEC_LANG @@ -266,7 +284,7 @@ uint16_t lang_print_sec_lang(FILE* out) void lang_boot_update_start(uint8_t lang) { - uint8_t cnt = lang_get_count(); - if ((lang < 2) || (lang > cnt)) return; //only languages from xflash can be selected - bootapp_reboot_user0(lang << 4); + uint8_t cnt = lang_get_count(); + if ((lang < 2) || (lang > cnt)) return; //only languages from xflash can be selected + bootapp_reboot_user0(lang << 4); } diff --git a/Firmware/language.h b/Firmware/language.h index 36c18dba94..1c741eb382 100755 --- a/Firmware/language.h +++ b/Firmware/language.h @@ -11,11 +11,11 @@ #define PROTOCOL_VERSION "1.0" #ifndef CUSTOM_MENDEL_NAME - #define MACHINE_NAME "Mendel" +#define MACHINE_NAME "Mendel" #endif #ifndef MACHINE_UUID - #define MACHINE_UUID "00000000-0000-0000-0000-000000000000" +#define MACHINE_UUID "00000000-0000-0000-0000-000000000000" #endif #define MSG_FW_VERSION "Firmware" @@ -49,19 +49,19 @@ /** @brief lang_table_header_t structure - (size= 16byte) */ typedef struct { - uint32_t magic; //+0 - uint16_t size; //+4 - uint16_t count; //+6 - uint16_t checksum; //+8 - uint16_t code; //+10 - uint32_t signature; //+12 + uint32_t magic; //+0 + uint16_t size; //+4 + uint16_t count; //+6 + uint16_t checksum; //+8 + uint16_t code; //+10 + uint32_t signature; //+12 } lang_table_header_t; /** @brief lang_table_t structure - (size= 16byte + 2*count) */ typedef struct { - lang_table_header_t header; - uint16_t table[]; + lang_table_header_t header; + uint16_t table[]; } lang_table_t; /** @name Language indices into their particular symbol tables.*/ diff --git a/Firmware/lcd.cpp b/Firmware/lcd.cpp index 4ec40c5f1a..b6ff7d4fbb 100755 --- a/Firmware/lcd.cpp +++ b/Firmware/lcd.cpp @@ -76,52 +76,52 @@ uint8_t lcd_escape[8]; void lcd_pulseEnable(void) { - digitalWrite(lcd_enable_pin, LOW); - delayMicroseconds(1); - digitalWrite(lcd_enable_pin, HIGH); - delayMicroseconds(1); // enable pulse must be >450ns - digitalWrite(lcd_enable_pin, LOW); - delayMicroseconds(100); // commands need > 37us to settle + digitalWrite(lcd_enable_pin, LOW); + delayMicroseconds(1); + digitalWrite(lcd_enable_pin, HIGH); + delayMicroseconds(1); // enable pulse must be >450ns + digitalWrite(lcd_enable_pin, LOW); + delayMicroseconds(100); // commands need > 37us to settle } void lcd_write4bits(uint8_t value) { - for (int i = 0; i < 4; i++) - { - pinMode(lcd_data_pins[i], OUTPUT); - digitalWrite(lcd_data_pins[i], (value >> i) & 0x01); - } - lcd_pulseEnable(); + for (int i = 0; i < 4; i++) + { + pinMode(lcd_data_pins[i], OUTPUT); + digitalWrite(lcd_data_pins[i], (value >> i) & 0x01); + } + lcd_pulseEnable(); } void lcd_write8bits(uint8_t value) { - for (int i = 0; i < 8; i++) - { - pinMode(lcd_data_pins[i], OUTPUT); - digitalWrite(lcd_data_pins[i], (value >> i) & 0x01); - } - lcd_pulseEnable(); + for (int i = 0; i < 8; i++) + { + pinMode(lcd_data_pins[i], OUTPUT); + digitalWrite(lcd_data_pins[i], (value >> i) & 0x01); + } + lcd_pulseEnable(); } // write either command or data, with automatic 4/8-bit selection void lcd_send(uint8_t value, uint8_t mode) { - digitalWrite(lcd_rs_pin, mode); - // if there is a RW pin indicated, set it low to Write - if (lcd_rw_pin != 255) digitalWrite(lcd_rw_pin, LOW); - if (lcd_displayfunction & LCD_8BITMODE) - lcd_write8bits(value); - else - { - lcd_write4bits(value>>4); - lcd_write4bits(value); - } + digitalWrite(lcd_rs_pin, mode); + // if there is a RW pin indicated, set it low to Write + if (lcd_rw_pin != 255) digitalWrite(lcd_rw_pin, LOW); + if (lcd_displayfunction & LCD_8BITMODE) + lcd_write8bits(value); + else + { + lcd_write4bits(value>>4); + lcd_write4bits(value); + } } void lcd_command(uint8_t value) { - lcd_send(value, LOW); + lcd_send(value, LOW); } void lcd_clear(void); @@ -145,111 +145,111 @@ uint8_t lcd_escape_write(uint8_t chr); uint8_t lcd_write(uint8_t value) { - if (value == '\n') - { - if (lcd_currline > 3) lcd_currline = -1; - lcd_set_cursor(0, lcd_currline + 1); // LF - return 1; - } - if (lcd_escape[0] || (value == 0x1b)) - return lcd_escape_write(value); - lcd_send(value, HIGH); - return 1; // assume sucess + if (value == '\n') + { + if (lcd_currline > 3) lcd_currline = -1; + lcd_set_cursor(0, lcd_currline + 1); // LF + return 1; + } + if (lcd_escape[0] || (value == 0x1b)) + return lcd_escape_write(value); + lcd_send(value, HIGH); + return 1; // assume sucess } static void lcd_begin(uint8_t lines, uint8_t dotsize, uint8_t clear) { - if (lines > 1) lcd_displayfunction |= LCD_2LINE; - lcd_numlines = lines; - lcd_currline = 0; - // for some 1 line displays you can select a 10 pixel high font - if ((dotsize != 0) && (lines == 1)) lcd_displayfunction |= LCD_5x10DOTS; - // 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 - _delay_us(50000); - // Now we pull both RS and R/W low to begin commands - digitalWrite(lcd_rs_pin, LOW); - digitalWrite(lcd_enable_pin, LOW); - if (lcd_rw_pin != 255) - digitalWrite(lcd_rw_pin, LOW); - //put the LCD into 4 bit or 8 bit mode - if (!(lcd_displayfunction & LCD_8BITMODE)) - { - // this is according to the hitachi HD44780 datasheet - // figure 24, pg 46 - // we start in 8bit mode, try to set 4 bit mode - lcd_write4bits(0x03); - _delay_us(4500); // wait min 4.1ms - // second try - lcd_write4bits(0x03); - _delay_us(4500); // wait min 4.1ms - // third go! - lcd_write4bits(0x03); - _delay_us(150); - // finally, set to 4-bit interface - lcd_write4bits(0x02); - } - else - { - // this is according to the hitachi HD44780 datasheet - // page 45 figure 23 - // Send function set command sequence - lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); - _delay_us(4500); // wait more than 4.1ms - // second try - lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); - _delay_us(150); - // third go - lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); - } - // finally, set # lines, font size, etc. - lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); - _delay_us(60); - // turn the display on with no cursor or blinking default - lcd_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; - lcd_display(); - _delay_us(60); - // clear it off - if (clear) lcd_clear(); - _delay_us(3000); - // Initialize to default text direction (for romance languages) - lcd_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; - // set the entry mode - lcd_command(LCD_ENTRYMODESET | lcd_displaymode); - _delay_us(60); - lcd_escape[0] = 0; + if (lines > 1) lcd_displayfunction |= LCD_2LINE; + lcd_numlines = lines; + lcd_currline = 0; + // for some 1 line displays you can select a 10 pixel high font + if ((dotsize != 0) && (lines == 1)) lcd_displayfunction |= LCD_5x10DOTS; + // 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 + _delay_us(50000); + // Now we pull both RS and R/W low to begin commands + digitalWrite(lcd_rs_pin, LOW); + digitalWrite(lcd_enable_pin, LOW); + if (lcd_rw_pin != 255) + digitalWrite(lcd_rw_pin, LOW); + //put the LCD into 4 bit or 8 bit mode + if (!(lcd_displayfunction & LCD_8BITMODE)) + { + // this is according to the hitachi HD44780 datasheet + // figure 24, pg 46 + // we start in 8bit mode, try to set 4 bit mode + lcd_write4bits(0x03); + _delay_us(4500); // wait min 4.1ms + // second try + lcd_write4bits(0x03); + _delay_us(4500); // wait min 4.1ms + // third go! + lcd_write4bits(0x03); + _delay_us(150); + // finally, set to 4-bit interface + lcd_write4bits(0x02); + } + else + { + // this is according to the hitachi HD44780 datasheet + // page 45 figure 23 + // Send function set command sequence + lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); + _delay_us(4500); // wait more than 4.1ms + // second try + lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); + _delay_us(150); + // third go + lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); + } + // finally, set # lines, font size, etc. + lcd_command(LCD_FUNCTIONSET | lcd_displayfunction); + _delay_us(60); + // turn the display on with no cursor or blinking default + lcd_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; + lcd_display(); + _delay_us(60); + // clear it off + if (clear) lcd_clear(); + _delay_us(3000); + // Initialize to default text direction (for romance languages) + lcd_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; + // set the entry mode + lcd_command(LCD_ENTRYMODESET | lcd_displaymode); + _delay_us(60); + lcd_escape[0] = 0; } int lcd_putchar(char c, FILE *) { - lcd_write(c); - return 0; + lcd_write(c); + return 0; } void lcd_init(void) { - uint8_t fourbitmode = 1; - lcd_rs_pin = LCD_PINS_RS; - lcd_rw_pin = 255; - lcd_enable_pin = LCD_PINS_ENABLE; - lcd_data_pins[0] = LCD_PINS_D4; - lcd_data_pins[1] = LCD_PINS_D5; - lcd_data_pins[2] = LCD_PINS_D6; - lcd_data_pins[3] = LCD_PINS_D7; - lcd_data_pins[4] = 0; - lcd_data_pins[5] = 0; - lcd_data_pins[6] = 0; - lcd_data_pins[7] = 0; - pinMode(lcd_rs_pin, OUTPUT); - // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin# - if (lcd_rw_pin != 255) pinMode(lcd_rw_pin, OUTPUT); - pinMode(lcd_enable_pin, OUTPUT); - if (fourbitmode) lcd_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; - else lcd_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS; - lcd_begin(LCD_HEIGHT, LCD_5x8DOTS, 1); - //lcd_clear(); - fdev_setup_stream(lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE); //setup lcdout stream + uint8_t fourbitmode = 1; + lcd_rs_pin = LCD_PINS_RS; + lcd_rw_pin = 255; + lcd_enable_pin = LCD_PINS_ENABLE; + lcd_data_pins[0] = LCD_PINS_D4; + lcd_data_pins[1] = LCD_PINS_D5; + lcd_data_pins[2] = LCD_PINS_D6; + lcd_data_pins[3] = LCD_PINS_D7; + lcd_data_pins[4] = 0; + lcd_data_pins[5] = 0; + lcd_data_pins[6] = 0; + lcd_data_pins[7] = 0; + pinMode(lcd_rs_pin, OUTPUT); + // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin# + if (lcd_rw_pin != 255) pinMode(lcd_rw_pin, OUTPUT); + pinMode(lcd_enable_pin, OUTPUT); + if (fourbitmode) lcd_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + else lcd_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS; + lcd_begin(LCD_HEIGHT, LCD_5x8DOTS, 1); + //lcd_clear(); + fdev_setup_stream(lcdout, lcd_putchar, NULL, _FDEV_SETUP_WRITE); //setup lcdout stream } void lcd_refresh(void) @@ -268,111 +268,111 @@ void lcd_refresh_noclear(void) void lcd_clear(void) { - lcd_command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero - _delay_us(1600); // this command takes a long time + lcd_command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero + _delay_us(1600); // this command takes a long time } void lcd_home(void) { - lcd_command(LCD_RETURNHOME); // set cursor position to zero - _delay_us(1600); // this command takes a long time! + lcd_command(LCD_RETURNHOME); // set cursor position to zero + _delay_us(1600); // this command takes a long time! } // Turn the display on/off (quickly) void lcd_no_display(void) { - lcd_displaycontrol &= ~LCD_DISPLAYON; - lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); + lcd_displaycontrol &= ~LCD_DISPLAYON; + lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); } void lcd_display(void) { - lcd_displaycontrol |= LCD_DISPLAYON; - lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); + lcd_displaycontrol |= LCD_DISPLAYON; + lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); } // Turns the underline cursor on/off void lcd_no_cursor(void) { - lcd_displaycontrol &= ~LCD_CURSORON; - lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); + lcd_displaycontrol &= ~LCD_CURSORON; + lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); } void lcd_cursor(void) { - lcd_displaycontrol |= LCD_CURSORON; - lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); + lcd_displaycontrol |= LCD_CURSORON; + lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); } // Turn on and off the blinking cursor void lcd_no_blink(void) { - lcd_displaycontrol &= ~LCD_BLINKON; - lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); + lcd_displaycontrol &= ~LCD_BLINKON; + lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); } void lcd_blink(void) { - lcd_displaycontrol |= LCD_BLINKON; - lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); + lcd_displaycontrol |= LCD_BLINKON; + lcd_command(LCD_DISPLAYCONTROL | lcd_displaycontrol); } // These commands scroll the display without changing the RAM void lcd_scrollDisplayLeft(void) { - lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); + lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); } void lcd_scrollDisplayRight(void) { - lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); + lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); } // This is for text that flows Left to Right void lcd_leftToRight(void) { - lcd_displaymode |= LCD_ENTRYLEFT; - lcd_command(LCD_ENTRYMODESET | lcd_displaymode); + lcd_displaymode |= LCD_ENTRYLEFT; + lcd_command(LCD_ENTRYMODESET | lcd_displaymode); } // This is for text that flows Right to Left void lcd_rightToLeft(void) { - lcd_displaymode &= ~LCD_ENTRYLEFT; - lcd_command(LCD_ENTRYMODESET | lcd_displaymode); + lcd_displaymode &= ~LCD_ENTRYLEFT; + lcd_command(LCD_ENTRYMODESET | lcd_displaymode); } // This will 'right justify' text from the cursor void lcd_autoscroll(void) { - lcd_displaymode |= LCD_ENTRYSHIFTINCREMENT; - lcd_command(LCD_ENTRYMODESET | lcd_displaymode); + lcd_displaymode |= LCD_ENTRYSHIFTINCREMENT; + lcd_command(LCD_ENTRYMODESET | lcd_displaymode); } // This will 'left justify' text from the cursor void lcd_no_autoscroll(void) { - lcd_displaymode &= ~LCD_ENTRYSHIFTINCREMENT; - lcd_command(LCD_ENTRYMODESET | lcd_displaymode); + lcd_displaymode &= ~LCD_ENTRYSHIFTINCREMENT; + lcd_command(LCD_ENTRYMODESET | lcd_displaymode); } void lcd_set_cursor(uint8_t col, uint8_t row) { - int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; - if ( row >= lcd_numlines ) - row = lcd_numlines-1; // we count rows starting w/0 - lcd_currline = row; - lcd_command(LCD_SETDDRAMADDR | (col + row_offsets[row])); + int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; + if ( row >= lcd_numlines ) + row = lcd_numlines-1; // we count rows starting w/0 + lcd_currline = row; + lcd_command(LCD_SETDDRAMADDR | (col + row_offsets[row])); } // Allows us to fill the first 8 CGRAM locations // with custom characters void lcd_createChar_P(uint8_t location, const uint8_t* charmap) { - location &= 0x7; // we only have 8 locations 0-7 - lcd_command(LCD_SETCGRAMADDR | (location << 3)); - for (int i=0; i<8; i++) - lcd_send(pgm_read_byte(&charmap[i]), HIGH); + location &= 0x7; // we only have 8 locations 0-7 + lcd_command(LCD_SETCGRAMADDR | (location << 3)); + for (int i=0; i<8; i++) + lcd_send(pgm_read_byte(&charmap[i]), HIGH); } //Supported VT100 escape codes: @@ -399,114 +399,120 @@ uint8_t lcd_escape_write(uint8_t chr) #define e45_num (10*e4_num+e5_num) //number from characters 4 and 5 #define e6_num (lcd_escape[6] - '0') //number from character 6 #define e56_num (10*e5_num+e6_num) //number from characters 5 and 6 - if (escape_cnt > 1) // escape length > 1 = "\x1b[" - { - lcd_escape[escape_cnt] = chr; // store current char - if ((chr >= '0') && (chr <= '9')) // char is numeric - is_num_msk |= (1 | (1 << escape_cnt)); //set mask - else - is_num_msk &= ~1; //clear mask - } - switch (escape_cnt++) - { - case 0: - if (chr == 0x1b) return 1; // escape = "\x1b" - break; - case 1: - is_num_msk = 0x00; // reset 'is number' bit mask - if (chr == '[') return 1; // escape = "\x1b[" - break; - case 2: - switch (chr) - { - case '2': return 1; // escape = "\x1b[2" - case '?': return 1; // escape = "\x1b[?" - default: - if (chr_is_num) return 1; // escape = "\x1b[%1d" - } - break; - case 3: - switch (lcd_escape[2]) - { - case '?': // escape = "\x1b[?" - if (chr == '2') return 1; // escape = "\x1b[?2" - break; - case '2': - if (chr == 'J') // escape = "\x1b[2J" - { lcd_clear(); lcd_currline = 0; break; } // EraseScreen - default: - if (e_2_is_num && // escape = "\x1b[%1d" - ((chr == ';') || // escape = "\x1b[%1d;" - chr_is_num)) // escape = "\x1b[%2d" - return 1; - } - break; - case 4: - switch (lcd_escape[2]) - { - case '?': // "\x1b[?" - if ((lcd_escape[3] == '2') && (chr == '5')) return 1; // escape = "\x1b[?25" - break; - default: - if (e_2_is_num) // escape = "\x1b[%1d" - { - if ((lcd_escape[3] == ';') && chr_is_num) return 1; // escape = "\x1b[%1d;%1d" - else if (e_3_is_num && (chr == ';')) return 1; // escape = "\x1b[%2d;" - } - } - break; - case 5: - switch (lcd_escape[2]) - { - case '?': - if ((lcd_escape[3] == '2') && (lcd_escape[4] == '5')) // escape = "\x1b[?25" - switch (chr) - { - case 'h': // escape = "\x1b[?25h" - lcd_cursor(); // CursorShow - break; - case 'l': // escape = "\x1b[?25l" - lcd_no_cursor(); // CursorHide - break; - } - break; - default: - if (e_2_is_num) // escape = "\x1b[%1d" - { - if ((lcd_escape[3] == ';') && e_4_is_num) // escape = "\x1b%1d;%1dH" - { - if (chr == 'H') // escape = "\x1b%1d;%1dH" - lcd_set_cursor(e4_num, e2_num); // CursorHome - else if (chr_is_num) - return 1; // escape = "\x1b%1d;%2d" - } - else if (e_3_is_num && (lcd_escape[4] == ';') && chr_is_num) - return 1; // escape = "\x1b%2d;%1d" - } - } - break; - case 6: - if (e_2_is_num) // escape = "\x1b[%1d" - { - if ((lcd_escape[3] == ';') && e_4_is_num && e_5_is_num && (chr == 'H')) // escape = "\x1b%1d;%2dH" - lcd_set_cursor(e45_num, e2_num); // CursorHome - else if (e_3_is_num && (lcd_escape[4] == ';') && e_5_is_num) // escape = "\x1b%2d;%1d" - { - if (chr == 'H') // escape = "\x1b%2d;%1dH" - lcd_set_cursor(e5_num, e23_num); // CursorHome - else if (chr_is_num) // "\x1b%2d;%2d" - return 1; - } - } - break; - case 7: - if (e_2_is_num && e_3_is_num && (lcd_escape[4] == ';')) // "\x1b[%2d;" - if (e_5_is_num && e_6_is_num && (chr == 'H')) // "\x1b[%2d;%2dH" - lcd_set_cursor(e56_num, e23_num); // CursorHome - break; - } - escape_cnt = 0; // reset escape - return 1; // assume sucess + if (escape_cnt > 1) // escape length > 1 = "\x1b[" + { + lcd_escape[escape_cnt] = chr; // store current char + if ((chr >= '0') && (chr <= '9')) // char is numeric + is_num_msk |= (1 | (1 << escape_cnt)); //set mask + else + is_num_msk &= ~1; //clear mask + } + switch (escape_cnt++) + { + case 0: + if (chr == 0x1b) return 1; // escape = "\x1b" + break; + case 1: + is_num_msk = 0x00; // reset 'is number' bit mask + if (chr == '[') return 1; // escape = "\x1b[" + break; + case 2: + switch (chr) + { + case '2': + return 1; // escape = "\x1b[2" + case '?': + return 1; // escape = "\x1b[?" + default: + if (chr_is_num) return 1; // escape = "\x1b[%1d" + } + break; + case 3: + switch (lcd_escape[2]) + { + case '?': // escape = "\x1b[?" + if (chr == '2') return 1; // escape = "\x1b[?2" + break; + case '2': + if (chr == 'J') // escape = "\x1b[2J" + { + lcd_clear(); // EraseScreen + lcd_currline = 0; + break; + } + default: + if (e_2_is_num && // escape = "\x1b[%1d" + ((chr == ';') || // escape = "\x1b[%1d;" + chr_is_num)) // escape = "\x1b[%2d" + return 1; + } + break; + case 4: + switch (lcd_escape[2]) + { + case '?': // "\x1b[?" + if ((lcd_escape[3] == '2') && (chr == '5')) return 1; // escape = "\x1b[?25" + break; + default: + if (e_2_is_num) // escape = "\x1b[%1d" + { + if ((lcd_escape[3] == ';') && chr_is_num) return 1; // escape = "\x1b[%1d;%1d" + else if (e_3_is_num && (chr == ';')) return 1; // escape = "\x1b[%2d;" + } + } + break; + case 5: + switch (lcd_escape[2]) + { + case '?': + if ((lcd_escape[3] == '2') && (lcd_escape[4] == '5')) // escape = "\x1b[?25" + switch (chr) + { + case 'h': // escape = "\x1b[?25h" + lcd_cursor(); // CursorShow + break; + case 'l': // escape = "\x1b[?25l" + lcd_no_cursor(); // CursorHide + break; + } + break; + default: + if (e_2_is_num) // escape = "\x1b[%1d" + { + if ((lcd_escape[3] == ';') && e_4_is_num) // escape = "\x1b%1d;%1dH" + { + if (chr == 'H') // escape = "\x1b%1d;%1dH" + lcd_set_cursor(e4_num, e2_num); // CursorHome + else if (chr_is_num) + return 1; // escape = "\x1b%1d;%2d" + } + else if (e_3_is_num && (lcd_escape[4] == ';') && chr_is_num) + return 1; // escape = "\x1b%2d;%1d" + } + } + break; + case 6: + if (e_2_is_num) // escape = "\x1b[%1d" + { + if ((lcd_escape[3] == ';') && e_4_is_num && e_5_is_num && (chr == 'H')) // escape = "\x1b%1d;%2dH" + lcd_set_cursor(e45_num, e2_num); // CursorHome + else if (e_3_is_num && (lcd_escape[4] == ';') && e_5_is_num) // escape = "\x1b%2d;%1d" + { + if (chr == 'H') // escape = "\x1b%2d;%1dH" + lcd_set_cursor(e5_num, e23_num); // CursorHome + else if (chr_is_num) // "\x1b%2d;%2d" + return 1; + } + } + break; + case 7: + if (e_2_is_num && e_3_is_num && (lcd_escape[4] == ';')) // "\x1b[%2d;" + if (e_5_is_num && e_6_is_num && (chr == 'H')) // "\x1b[%2d;%2dH" + lcd_set_cursor(e56_num, e23_num); // CursorHome + break; + } + escape_cnt = 0; // reset escape + return 1; // assume sucess } @@ -514,137 +520,137 @@ uint8_t lcd_escape_write(uint8_t chr) int lcd_putc(int c) { - return fputc(c, lcdout); + return fputc(c, lcdout); } int lcd_puts_P(const char* str) { - return fputs_P(str, lcdout); + return fputs_P(str, lcdout); } int lcd_puts_at_P(uint8_t c, uint8_t r, const char* str) { - lcd_set_cursor(c, r); - return fputs_P(str, lcdout); + lcd_set_cursor(c, r); + return fputs_P(str, lcdout); } int lcd_printf_P(const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vfprintf_P(lcdout, format, args); - va_end(args); - return ret; + va_list args; + va_start(args, format); + int ret = vfprintf_P(lcdout, format, args); + va_end(args); + return ret; } void lcd_space(uint8_t n) { - while (n--) lcd_putc(' '); + while (n--) lcd_putc(' '); } void lcd_print(const char* s) { - while (*s) lcd_write(*(s++)); + while (*s) lcd_write(*(s++)); } void lcd_print(char c, int base) { - lcd_print((long) c, base); + lcd_print((long) c, base); } void lcd_print(unsigned char b, int base) { - lcd_print((unsigned long) b, base); + lcd_print((unsigned long) b, base); } void lcd_print(int n, int base) { - lcd_print((long) n, base); + lcd_print((long) n, base); } void lcd_print(unsigned int n, int base) { - lcd_print((unsigned long) n, base); + lcd_print((unsigned long) n, base); } void lcd_print(long n, int base) { - if (base == 0) - lcd_write(n); - else if (base == 10) - { - if (n < 0) - { - lcd_print('-'); - n = -n; - } - lcd_printNumber(n, 10); - } - else - lcd_printNumber(n, base); + if (base == 0) + lcd_write(n); + else if (base == 10) + { + if (n < 0) + { + lcd_print('-'); + n = -n; + } + lcd_printNumber(n, 10); + } + else + lcd_printNumber(n, base); } void lcd_print(unsigned long n, int base) { - if (base == 0) - lcd_write(n); - else - lcd_printNumber(n, base); + if (base == 0) + lcd_write(n); + else + lcd_printNumber(n, base); } void lcd_print(double n, int digits) { - lcd_printFloat(n, digits); + lcd_printFloat(n, digits); } void lcd_printNumber(unsigned long n, uint8_t base) { - unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. - unsigned long i = 0; - if (n == 0) - { - lcd_print('0'); - return; - } - while (n > 0) - { - buf[i++] = n % base; - n /= base; - } - for (; i > 0; i--) - lcd_print((char) (buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10)); + unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. + unsigned long i = 0; + if (n == 0) + { + lcd_print('0'); + return; + } + while (n > 0) + { + buf[i++] = n % base; + n /= base; + } + for (; i > 0; i--) + lcd_print((char) (buf[i - 1] < 10 ? '0' + buf[i - 1] : 'A' + buf[i - 1] - 10)); } -void lcd_printFloat(double number, uint8_t digits) -{ - // Handle negative numbers - if (number < 0.0) - { - lcd_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) - lcd_print('.'); - // Extract digits from the remainder one at a time - while (digits-- > 0) - { - remainder *= 10.0; - int toPrint = int(remainder); - lcd_print(toPrint); - remainder -= toPrint; - } +void lcd_printFloat(double number, uint8_t digits) +{ + // Handle negative numbers + if (number < 0.0) + { + lcd_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) + lcd_print('.'); + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + int toPrint = int(remainder); + lcd_print(toPrint); + remainder -= toPrint; + } } @@ -694,35 +700,35 @@ LongTimer lcd_timeoutToStatus; //! @retval nonzero clicked uint8_t lcd_clicked(void) { - bool clicked = LCD_CLICKED; - if(clicked) - { - lcd_consume_click(); - } + bool clicked = LCD_CLICKED; + if(clicked) + { + lcd_consume_click(); + } return clicked; } void lcd_beeper_quick_feedback(void) { - SET_OUTPUT(BEEPER); + SET_OUTPUT(BEEPER); //-// -Sound_MakeSound(e_SOUND_TYPE_ButtonEcho); -/* - for(int8_t i = 0; i < 10; i++) - { - WRITE(BEEPER,HIGH); - delayMicroseconds(100); - WRITE(BEEPER,LOW); - delayMicroseconds(100); - } -*/ + Sound_MakeSound(e_SOUND_TYPE_ButtonEcho); + /* + for(int8_t i = 0; i < 10; i++) + { + WRITE(BEEPER,HIGH); + delayMicroseconds(100); + WRITE(BEEPER,LOW); + delayMicroseconds(100); + } + */ } void lcd_quick_feedback(void) { - lcd_draw_update = 2; - lcd_button_pressed = false; - lcd_beeper_quick_feedback(); + lcd_draw_update = 2; + lcd_button_pressed = false; + lcd_beeper_quick_feedback(); } @@ -734,49 +740,49 @@ void lcd_quick_feedback(void) void lcd_update(uint8_t lcdDrawUpdateOverride) { - if (lcd_draw_update < lcdDrawUpdateOverride) - lcd_draw_update = lcdDrawUpdateOverride; - if (!lcd_update_enabled) - return; - if (lcd_lcdupdate_func) - lcd_lcdupdate_func(); + if (lcd_draw_update < lcdDrawUpdateOverride) + lcd_draw_update = lcdDrawUpdateOverride; + if (!lcd_update_enabled) + return; + if (lcd_lcdupdate_func) + lcd_lcdupdate_func(); } void lcd_update_enable(uint8_t enabled) { - if (lcd_update_enabled != enabled) - { - lcd_update_enabled = enabled; - if (enabled) - { // Reset encoder position. This is equivalent to re-entering a menu. - lcd_encoder = 0; - lcd_encoder_diff = 0; - // Enabling the normal LCD update procedure. - // Reset the timeout interval. - lcd_timeoutToStatus.start(); - // Force the keypad update now. - lcd_next_update_millis = millis() - 1; - // Full update. - lcd_clear(); - if (lcd_charsetup_func) - lcd_charsetup_func(); - lcd_update(2); - } else - { - // Clear the LCD always, or let it to the caller? - } - } + if (lcd_update_enabled != enabled) + { + lcd_update_enabled = enabled; + if (enabled) + { // Reset encoder position. This is equivalent to re-entering a menu. + lcd_encoder = 0; + lcd_encoder_diff = 0; + // Enabling the normal LCD update procedure. + // Reset the timeout interval. + lcd_timeoutToStatus.start(); + // Force the keypad update now. + lcd_next_update_millis = millis() - 1; + // Full update. + lcd_clear(); + if (lcd_charsetup_func) + lcd_charsetup_func(); + lcd_update(2); + } else + { + // Clear the LCD always, or let it to the caller? + } + } } void lcd_buttons_update(void) { static uint8_t lcd_long_press_active = 0; - uint8_t newbutton = 0; - if (READ(BTN_EN1) == 0) newbutton |= EN_A; - if (READ(BTN_EN2) == 0) newbutton |= EN_B; + uint8_t newbutton = 0; + if (READ(BTN_EN1) == 0) newbutton |= EN_A; + if (READ(BTN_EN2) == 0) newbutton |= EN_B; if (READ(BTN_ENC) == 0) - { //button is pressed + { //button is pressed lcd_timeoutToStatus.start(); if (!buttonBlanking.running() || buttonBlanking.expired(BUTTON_BLANKING_TIME)) { buttonBlanking.start(); @@ -796,12 +802,12 @@ void lcd_buttons_update(void) } } else - { //button not pressed + { //button not pressed if (lcd_button_pressed) - { //button was released + { //button was released buttonBlanking.start(); if (lcd_long_press_active == 0) - { //button released before long press gets activated + { //button released before long press gets activated newbutton |= EN_C; } //else if (menu_menu == lcd_move_z) lcd_quick_feedback(); @@ -811,42 +817,42 @@ void lcd_buttons_update(void) lcd_long_press_active = 0; } - lcd_buttons = newbutton; - //manage encoder rotation - uint8_t enc = 0; - if (lcd_buttons & EN_A) enc |= B01; - if (lcd_buttons & EN_B) enc |= B10; - if (enc != lcd_encoder_bits) - { - switch (enc) - { - case encrot0: - if (lcd_encoder_bits == encrot3) - lcd_encoder_diff++; - else if (lcd_encoder_bits == encrot1) - lcd_encoder_diff--; - break; - case encrot1: - if (lcd_encoder_bits == encrot0) - lcd_encoder_diff++; - else if (lcd_encoder_bits == encrot2) - lcd_encoder_diff--; - break; - case encrot2: - if (lcd_encoder_bits == encrot1) - lcd_encoder_diff++; - else if (lcd_encoder_bits == encrot3) - lcd_encoder_diff--; - break; - case encrot3: - if (lcd_encoder_bits == encrot2) - lcd_encoder_diff++; - else if (lcd_encoder_bits == encrot0) - lcd_encoder_diff--; - break; - } - } - lcd_encoder_bits = enc; + lcd_buttons = newbutton; + //manage encoder rotation + uint8_t enc = 0; + if (lcd_buttons & EN_A) enc |= B01; + if (lcd_buttons & EN_B) enc |= B10; + if (enc != lcd_encoder_bits) + { + switch (enc) + { + case encrot0: + if (lcd_encoder_bits == encrot3) + lcd_encoder_diff++; + else if (lcd_encoder_bits == encrot1) + lcd_encoder_diff--; + break; + case encrot1: + if (lcd_encoder_bits == encrot0) + lcd_encoder_diff++; + else if (lcd_encoder_bits == encrot2) + lcd_encoder_diff--; + break; + case encrot2: + if (lcd_encoder_bits == encrot1) + lcd_encoder_diff++; + else if (lcd_encoder_bits == encrot3) + lcd_encoder_diff--; + break; + case encrot3: + if (lcd_encoder_bits == encrot2) + lcd_encoder_diff++; + else if (lcd_encoder_bits == encrot0) + lcd_encoder_diff--; + break; + } + } + lcd_encoder_bits = enc; } @@ -854,64 +860,70 @@ void lcd_buttons_update(void) // Custom character data const uint8_t lcd_chardata_bedTemp[8] PROGMEM = { - B00000, - B11111, - B10101, - B10001, - B10101, - B11111, - B00000, - B00000}; //thanks Sonny Mounicou + B00000, + B11111, + B10101, + B10001, + B10101, + B11111, + B00000, + B00000 +}; //thanks Sonny Mounicou const uint8_t lcd_chardata_degree[8] PROGMEM = { - B01100, - B10010, - B10010, - B01100, - B00000, - B00000, - B00000, - B00000}; + B01100, + B10010, + B10010, + B01100, + B00000, + B00000, + B00000, + B00000 +}; const uint8_t lcd_chardata_thermometer[8] PROGMEM = { - B00100, - B01010, - B01010, - B01010, - B01010, - B10001, - B10001, - B01110}; + B00100, + B01010, + B01010, + B01010, + B01010, + B10001, + B10001, + B01110 +}; const uint8_t lcd_chardata_uplevel[8] PROGMEM = { - B00100, - B01110, - B11111, - B00100, - B11100, - B00000, - B00000, - B00000}; //thanks joris + B00100, + B01110, + B11111, + B00100, + B11100, + B00000, + B00000, + B00000 +}; //thanks joris const uint8_t lcd_chardata_refresh[8] PROGMEM = { - B00000, - B00110, - B11001, - B11000, - B00011, - B10011, - B01100, - B00000}; //thanks joris + B00000, + B00110, + B11001, + B11000, + B00011, + B10011, + B01100, + B00000 +}; //thanks joris const uint8_t lcd_chardata_folder[8] PROGMEM = { - B00000, - B11100, - B11111, - B10001, - B10001, - B11111, - B00000, - B00000}; //thanks joris + B00000, + B11100, + B11111, + B10001, + B10001, + B11111, + B00000, + B00000 +}; //thanks joris /*const uint8_t lcd_chardata_feedrate[8] PROGMEM = { B11100, @@ -944,108 +956,115 @@ const uint8_t lcd_chardata_folder[8] PROGMEM = { B10011};*/ const uint8_t lcd_chardata_feedrate[8] PROGMEM = { - B00000, - B00100, - B10010, - B01001, - B10010, - B00100, - B00000, - B00000}; + B00000, + B00100, + B10010, + B01001, + B10010, + B00100, + B00000, + B00000 +}; const uint8_t lcd_chardata_clock[8] PROGMEM = { - B00000, - B01110, - B10011, - B10101, - B10001, - B01110, - B00000, - B00000}; //thanks Sonny Mounicou + B00000, + B01110, + B10011, + B10101, + B10001, + B01110, + B00000, + B00000 +}; //thanks Sonny Mounicou const uint8_t lcd_chardata_arrup[8] PROGMEM = { - B00100, - B01110, - B11111, - B00000, - B00000, - B00000, - B00000, - B00000}; + B00100, + B01110, + B11111, + B00000, + B00000, + B00000, + B00000, + B00000 +}; const uint8_t lcd_chardata_arrdown[8] PROGMEM = { - B00000, - B00000, - B00000, - B00000, - B00000, - B10001, - B01010, - B00100}; + B00000, + B00000, + B00000, + B00000, + B00000, + B10001, + B01010, + B00100 +}; void lcd_set_custom_characters(void) { - lcd_createChar_P(LCD_STR_BEDTEMP[0], lcd_chardata_bedTemp); - lcd_createChar_P(LCD_STR_DEGREE[0], lcd_chardata_degree); - lcd_createChar_P(LCD_STR_THERMOMETER[0], lcd_chardata_thermometer); - lcd_createChar_P(LCD_STR_UPLEVEL[0], lcd_chardata_uplevel); - lcd_createChar_P(LCD_STR_REFRESH[0], lcd_chardata_refresh); - lcd_createChar_P(LCD_STR_FOLDER[0], lcd_chardata_folder); - lcd_createChar_P(LCD_STR_FEEDRATE[0], lcd_chardata_feedrate); - lcd_createChar_P(LCD_STR_CLOCK[0], lcd_chardata_clock); - //lcd_createChar_P(LCD_STR_ARROW_UP[0], lcd_chardata_arrup); - //lcd_createChar_P(LCD_STR_ARROW_DOWN[0], lcd_chardata_arrdown); + lcd_createChar_P(LCD_STR_BEDTEMP[0], lcd_chardata_bedTemp); + lcd_createChar_P(LCD_STR_DEGREE[0], lcd_chardata_degree); + lcd_createChar_P(LCD_STR_THERMOMETER[0], lcd_chardata_thermometer); + lcd_createChar_P(LCD_STR_UPLEVEL[0], lcd_chardata_uplevel); + lcd_createChar_P(LCD_STR_REFRESH[0], lcd_chardata_refresh); + lcd_createChar_P(LCD_STR_FOLDER[0], lcd_chardata_folder); + lcd_createChar_P(LCD_STR_FEEDRATE[0], lcd_chardata_feedrate); + lcd_createChar_P(LCD_STR_CLOCK[0], lcd_chardata_clock); + //lcd_createChar_P(LCD_STR_ARROW_UP[0], lcd_chardata_arrup); + //lcd_createChar_P(LCD_STR_ARROW_DOWN[0], lcd_chardata_arrdown); } void lcd_set_custom_characters_arrows(void) { - lcd_createChar_P(1, lcd_chardata_arrdown); + lcd_createChar_P(1, lcd_chardata_arrdown); } const uint8_t lcd_chardata_progress[8] PROGMEM = { - B11111, - B11111, - B11111, - B11111, - B11111, - B11111, - B11111, - B11111}; + B11111, + B11111, + B11111, + B11111, + B11111, + B11111, + B11111, + B11111 +}; void lcd_set_custom_characters_progress(void) { - lcd_createChar_P(1, lcd_chardata_progress); + lcd_createChar_P(1, lcd_chardata_progress); } const uint8_t lcd_chardata_arr2down[8] PROGMEM = { - B00000, - B00000, - B10001, - B01010, - B00100, - B10001, - B01010, - B00100}; + B00000, + B00000, + B10001, + B01010, + B00100, + B10001, + B01010, + B00100 +}; const uint8_t lcd_chardata_confirm[8] PROGMEM = { - B00000, - B00001, - B00011, - B10110, - B11100, - B01000, - B00000}; + B00000, + B00001, + B00011, + B10110, + B11100, + B01000, + B00000 +}; void lcd_set_custom_characters_nextpage(void) { - lcd_createChar_P(1, lcd_chardata_arr2down); - lcd_createChar_P(2, lcd_chardata_confirm); + lcd_createChar_P(1, lcd_chardata_arr2down); + lcd_createChar_P(2, lcd_chardata_confirm); } void lcd_set_custom_characters_degree(void) { - lcd_createChar_P(1, lcd_chardata_degree); + lcd_createChar_P(1, lcd_chardata_degree); } diff --git a/Firmware/lcd.h b/Firmware/lcd.h index 12935188ae..8b3585e9c7 100755 --- a/Firmware/lcd.h +++ b/Firmware/lcd.h @@ -197,16 +197,16 @@ class LcdUpdateDisabler //////////////////////////////////// // Setup button and encode mappings for each panel (into 'lcd_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 +// 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. #define BLEN_B 1 #define BLEN_A 0 #define EN_B (1<= sizeof(menu_data_edit_t),"menu_data_edit_t doe void menu_goto(menu_func_t menu, const uint32_t encoder, const bool feedback, bool reset_menu_state) { - asm("cli"); - if (menu_menu != menu) - { - menu_menu = menu; - lcd_encoder = encoder; - asm("sei"); - if (reset_menu_state) - { - // Resets the global shared C union. - // This ensures, that the menu entered will find out, that it shall initialize itself. - memset(&menu_data, 0, sizeof(menu_data)); - } - if (feedback) lcd_quick_feedback(); - } - else - asm("sei"); + asm("cli"); + if (menu_menu != menu) + { + menu_menu = menu; + lcd_encoder = encoder; + asm("sei"); + if (reset_menu_state) + { + // Resets the global shared C union. + // This ensures, that the menu entered will find out, that it shall initialize itself. + memset(&menu_data, 0, sizeof(menu_data)); + } + if (feedback) lcd_quick_feedback(); + } + else + asm("sei"); } void menu_start(void) @@ -67,83 +67,83 @@ void menu_start(void) if (lcd_encoder > 0x8000) lcd_encoder = 0; if (lcd_encoder < 0) lcd_encoder = 0; if (lcd_encoder < menu_top) - menu_top = lcd_encoder; + menu_top = lcd_encoder; menu_line = menu_top; menu_clicked = LCD_CLICKED; } void menu_end(void) { - if (lcd_encoder >= menu_item) - lcd_encoder = menu_item - 1; - if (((uint8_t)lcd_encoder) >= menu_top + LCD_HEIGHT) - { - menu_top = lcd_encoder - LCD_HEIGHT + 1; - lcd_draw_update = 1; - menu_line = menu_top - 1; - menu_row = -1; - } + if (lcd_encoder >= menu_item) + lcd_encoder = menu_item - 1; + if (((uint8_t)lcd_encoder) >= menu_top + LCD_HEIGHT) + { + menu_top = lcd_encoder - LCD_HEIGHT + 1; + lcd_draw_update = 1; + menu_line = menu_top - 1; + menu_row = -1; + } } void menu_back(void) { - if (menu_depth > 0) - { - menu_depth--; - menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, true, true); - } + if (menu_depth > 0) + { + menu_depth--; + menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, true, true); + } } static void menu_back_no_reset(void) { - if (menu_depth > 0) - { - menu_depth--; - menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, true, false); - } + if (menu_depth > 0) + { + menu_depth--; + menu_goto(menu_stack[menu_depth].menu, menu_stack[menu_depth].position, true, false); + } } void menu_back_if_clicked(void) { - if (lcd_clicked()) - menu_back(); + if (lcd_clicked()) + menu_back(); } void menu_back_if_clicked_fb(void) { - if (lcd_clicked()) - { + if (lcd_clicked()) + { lcd_quick_feedback(); - menu_back(); - } + menu_back(); + } } void menu_submenu(menu_func_t submenu) { - if (menu_depth <= MENU_DEPTH_MAX) - { - menu_stack[menu_depth].menu = menu_menu; - menu_stack[menu_depth++].position = lcd_encoder; - menu_goto(submenu, 0, true, true); - } + if (menu_depth <= MENU_DEPTH_MAX) + { + menu_stack[menu_depth].menu = menu_menu; + menu_stack[menu_depth++].position = lcd_encoder; + menu_goto(submenu, 0, true, true); + } } static void menu_submenu_no_reset(menu_func_t submenu) { - if (menu_depth <= MENU_DEPTH_MAX) - { - menu_stack[menu_depth].menu = menu_menu; - menu_stack[menu_depth++].position = lcd_encoder; - menu_goto(submenu, 0, true, false); - } + if (menu_depth <= MENU_DEPTH_MAX) + { + menu_stack[menu_depth].menu = menu_menu; + menu_stack[menu_depth++].position = lcd_encoder; + menu_goto(submenu, 0, true, false); + } } uint8_t menu_item_ret(void) { - lcd_beeper_quick_feedback(); - lcd_draw_update = 2; - lcd_button_pressed = false; - return 1; + lcd_beeper_quick_feedback(); + lcd_draw_update = 2; + lcd_button_pressed = false; + return 1; } /* @@ -169,8 +169,8 @@ int menu_draw_item_printf_P(char type_char, const char* format, ...) static int menu_draw_item_puts_P(char type_char, const char* str) { lcd_set_cursor(0, menu_row); - int cnt = lcd_printf_P(PSTR("%c%-18S%c"), (lcd_encoder == menu_item)?'>':' ', str, type_char); - return cnt; + int cnt = lcd_printf_P(PSTR("%c%-18S%c"), (lcd_encoder == menu_item)?'>':' ', str, type_char); + return cnt; } /* @@ -184,83 +184,83 @@ int menu_draw_item_puts_P_int16(char type_char, const char* str, int16_t val, ) void menu_item_dummy(void) { - menu_item++; + menu_item++; } uint8_t menu_item_text_P(const char* str) { - if (menu_item == menu_line) - { - if (lcd_draw_update) menu_draw_item_puts_P(' ', str); - if (menu_clicked && (lcd_encoder == menu_item)) - return menu_item_ret(); - } - menu_item++; - return 0; + if (menu_item == menu_line) + { + if (lcd_draw_update) menu_draw_item_puts_P(' ', str); + if (menu_clicked && (lcd_encoder == menu_item)) + return menu_item_ret(); + } + menu_item++; + return 0; } uint8_t menu_item_submenu_P(const char* str, menu_func_t submenu) { - if (menu_item == menu_line) - { - if (lcd_draw_update) menu_draw_item_puts_P(LCD_STR_ARROW_RIGHT[0], str); - if (menu_clicked && (lcd_encoder == menu_item)) - { - menu_submenu(submenu); - return menu_item_ret(); - } - } - menu_item++; - return 0; + if (menu_item == menu_line) + { + if (lcd_draw_update) menu_draw_item_puts_P(LCD_STR_ARROW_RIGHT[0], str); + if (menu_clicked && (lcd_encoder == menu_item)) + { + menu_submenu(submenu); + return menu_item_ret(); + } + } + menu_item++; + return 0; } uint8_t menu_item_back_P(const char* str) { - if (menu_item == menu_line) - { - if (lcd_draw_update) menu_draw_item_puts_P(LCD_STR_UPLEVEL[0], str); - if (menu_clicked && (lcd_encoder == menu_item)) - { - menu_back(); - return menu_item_ret(); - } - } - menu_item++; - return 0; + if (menu_item == menu_line) + { + if (lcd_draw_update) menu_draw_item_puts_P(LCD_STR_UPLEVEL[0], str); + if (menu_clicked && (lcd_encoder == menu_item)) + { + menu_back(); + return menu_item_ret(); + } + } + menu_item++; + return 0; } uint8_t menu_item_function_P(const char* str, menu_func_t func) { - if (menu_item == menu_line) - { - if (lcd_draw_update) menu_draw_item_puts_P(' ', str); - if (menu_clicked && (lcd_encoder == menu_item)) - { - menu_clicked = false; - lcd_consume_click(); - lcd_update_enabled = 0; - if (func) func(); - lcd_update_enabled = 1; - return menu_item_ret(); - } - } - menu_item++; - return 0; + if (menu_item == menu_line) + { + if (lcd_draw_update) menu_draw_item_puts_P(' ', str); + if (menu_clicked && (lcd_encoder == menu_item)) + { + menu_clicked = false; + lcd_consume_click(); + lcd_update_enabled = 0; + if (func) func(); + lcd_update_enabled = 1; + return menu_item_ret(); + } + } + menu_item++; + return 0; } uint8_t menu_item_gcode_P(const char* str, const char* str_gcode) { - if (menu_item == menu_line) - { - if (lcd_draw_update) menu_draw_item_puts_P(' ', str); - if (menu_clicked && (lcd_encoder == menu_item)) - { - if (str_gcode) enquecommand_P(str_gcode); - return menu_item_ret(); - } - } - menu_item++; - return 0; + if (menu_item == menu_line) + { + if (lcd_draw_update) menu_draw_item_puts_P(' ', str); + if (menu_clicked && (lcd_encoder == menu_item)) + { + if (str_gcode) enquecommand_P(str_gcode); + return menu_item_ret(); + } + } + menu_item++; + return 0; } @@ -280,12 +280,12 @@ static void menu_draw_P(char chr, const char* str, int16_t val); template<> void menu_draw_P(char chr, const char* str, int16_t val) { - int text_len = strlen_P(str); - if (text_len > 15) text_len = 15; - char spaces[21]; - strcpy_P(spaces, menu_20x_space); - spaces[15 - text_len] = 0; - lcd_printf_P(menu_fmt_int3, chr, str, spaces, val); + int text_len = strlen_P(str); + if (text_len > 15) text_len = 15; + char spaces[21]; + strcpy_P(spaces, menu_20x_space); + spaces[15 - text_len] = 0; + lcd_printf_P(menu_fmt_int3, chr, str, spaces, val); } template<> @@ -312,67 +312,67 @@ void menu_draw_P(char chr, const char* str, int16_t val) //draw up to 12 chars of text, ':' and float number in format +123.0 void menu_draw_float31(char chr, const char* str, float val) { - int text_len = strlen_P(str); - if (text_len > 12) text_len = 12; - char spaces[21]; - strcpy_P(spaces, menu_20x_space); - spaces[12 - text_len] = 0; - lcd_printf_P(menu_fmt_float31, chr, str, spaces, val); + int text_len = strlen_P(str); + if (text_len > 12) text_len = 12; + char spaces[21]; + strcpy_P(spaces, menu_20x_space); + spaces[12 - text_len] = 0; + lcd_printf_P(menu_fmt_float31, chr, str, spaces, val); } //draw up to 12 chars of text, ':' and float number in format +1.234 void menu_draw_float13(char chr, const char* str, float val) { - int text_len = strlen_P(str); - if (text_len > 12) text_len = 12; - char spaces[21]; - strcpy_P(spaces, menu_20x_space); - spaces[12 - text_len] = 0; - lcd_printf_P(menu_fmt_float13, chr, str, spaces, val); + int text_len = strlen_P(str); + if (text_len > 12) text_len = 12; + char spaces[21]; + strcpy_P(spaces, menu_20x_space); + spaces[12 - text_len] = 0; + lcd_printf_P(menu_fmt_float13, chr, str, spaces, val); } template static void _menu_edit_P(void) { - menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]); - if (lcd_draw_update) - { - if (lcd_encoder < _md->minEditValue) lcd_encoder = _md->minEditValue; - if (lcd_encoder > _md->maxEditValue) lcd_encoder = _md->maxEditValue; - lcd_set_cursor(0, 1); - menu_draw_P(' ', _md->editLabel, (int)lcd_encoder); - } - if (LCD_CLICKED) - { - *((T)(_md->editValue)) = lcd_encoder; - menu_back_no_reset(); - } + menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]); + if (lcd_draw_update) + { + if (lcd_encoder < _md->minEditValue) lcd_encoder = _md->minEditValue; + if (lcd_encoder > _md->maxEditValue) lcd_encoder = _md->maxEditValue; + lcd_set_cursor(0, 1); + menu_draw_P(' ', _md->editLabel, (int)lcd_encoder); + } + if (LCD_CLICKED) + { + *((T)(_md->editValue)) = lcd_encoder; + menu_back_no_reset(); + } } template uint8_t menu_item_edit_P(const char* str, T pval, int16_t min_val, int16_t max_val) { - menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]); - if (menu_item == menu_line) - { - if (lcd_draw_update) - { - lcd_set_cursor(0, menu_row); - menu_draw_P((lcd_encoder == menu_item)?'>':' ', str, *pval); - } - if (menu_clicked && (lcd_encoder == menu_item)) - { - menu_submenu_no_reset(_menu_edit_P); - _md->editLabel = str; - _md->editValue = pval; - _md->minEditValue = min_val; - _md->maxEditValue = max_val; - lcd_encoder = *pval; - return menu_item_ret(); - } - } - menu_item++; - return 0; + menu_data_edit_t* _md = (menu_data_edit_t*)&(menu_data[0]); + if (menu_item == menu_line) + { + if (lcd_draw_update) + { + lcd_set_cursor(0, menu_row); + menu_draw_P((lcd_encoder == menu_item)?'>':' ', str, *pval); + } + if (menu_clicked && (lcd_encoder == menu_item)) + { + menu_submenu_no_reset(_menu_edit_P); + _md->editLabel = str; + _md->editValue = pval; + _md->minEditValue = min_val; + _md->maxEditValue = max_val; + lcd_encoder = *pval; + return menu_item_ret(); + } + } + menu_item++; + return 0; } template uint8_t menu_item_edit_P(const char* str, int16_t *pval, int16_t min_val, int16_t max_val); diff --git a/Firmware/menu.h b/Firmware/menu.h index 73e4925a61..b96622e58f 100755 --- a/Firmware/menu.h +++ b/Firmware/menu.h @@ -9,7 +9,7 @@ //Function pointer to menu functions. typedef void (*menu_func_t)(void); -typedef struct +typedef struct { menu_func_t menu; int8_t position; diff --git a/Firmware/mesh_bed_calibration.cpp b/Firmware/mesh_bed_calibration.cpp index 35798c2e52..c70d3cbb54 100755 --- a/Firmware/mesh_bed_calibration.cpp +++ b/Firmware/mesh_bed_calibration.cpp @@ -76,48 +76,48 @@ const float bed_skew_angle_extreme = (0.25f * M_PI / 180.f); * MK25 and MK3: front left, front right, rear right, rear left */ const float bed_ref_points_4[] PROGMEM = { - 37.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, - 18.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y, + 37.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, + 18.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y, - 245.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, - 18.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y, + 245.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, + 18.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y, - 245.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, - 210.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y, + 245.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, + 210.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y, - 37.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, - 210.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y + 37.f - BED_PRINT_ZERO_REF_X - X_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_X, + 210.4f - BED_PRINT_ZERO_REF_Y - Y_PROBE_OFFSET_FROM_EXTRUDER - SHEET_PRINT_ZERO_REF_Y }; const float bed_ref_points[] PROGMEM = { - 13.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, - 216.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, + 13.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, + 216.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, - 216.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y, - 13.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y, + 216.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y, + 13.f - BED_ZERO_REF_X, 106.4f - BED_ZERO_REF_Y, - 13.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, - 216.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y + 13.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, + 216.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y }; #else // Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor. // The points are the following: center front, center right, center rear, center left. const float bed_ref_points_4[] PROGMEM = { - 115.f - BED_ZERO_REF_X, 8.4f - BED_ZERO_REF_Y, - 216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, - 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, - 13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y + 115.f - BED_ZERO_REF_X, 8.4f - BED_ZERO_REF_Y, + 216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, + 115.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, + 13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y }; const float bed_ref_points[] PROGMEM = { 13.f - BED_ZERO_REF_X, 8.4f - BED_ZERO_REF_Y, 115.f - BED_ZERO_REF_X, 8.4f - BED_ZERO_REF_Y, 216.f - BED_ZERO_REF_X, 8.4f - BED_ZERO_REF_Y, - + 216.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, 115.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, 13.f - BED_ZERO_REF_X, 104.4f - BED_ZERO_REF_Y, @@ -129,17 +129,19 @@ const float bed_ref_points[] PROGMEM = { #endif //not HEATBED_V2 -static inline float sqr(float x) { return x * x; } +static inline float sqr(float x) { + return x * x; +} #ifdef HEATBED_V2 static inline bool point_on_1st_row(const uint8_t /*i*/) { - return false; + return false; } #else //HEATBED_V2 static inline bool point_on_1st_row(const uint8_t i) { - return (i < 3); + return (i < 3); } #endif //HEATBED_V2 @@ -151,7 +153,7 @@ static inline float point_weight_x(const uint8_t i, const float &y) { float w = 1.f; if (point_on_1st_row(i)) { - if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) { + if (y >= Y_MIN_POS_CALIBRATION_POINT_ACCURATE) { w = WEIGHT_FIRST_ROW_X_HIGH; } else if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { // If the point is fully outside, give it some weight. @@ -213,12 +215,12 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( #ifdef SUPPORT_VERBOSITY verbosity_level #endif //SUPPORT_VERBOSITY - ) +) { - float angleDiff; - #ifdef SUPPORT_VERBOSITY + float angleDiff; +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 10) { - SERIAL_ECHOLNPGM("calculate machine skew and offset LS"); + SERIAL_ECHOLNPGM("calculate machine skew and offset LS"); // Show the initial state, before the fitting. SERIAL_ECHOPGM("X vector, initial: "); @@ -252,13 +254,13 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); SERIAL_ECHOPGM("), error: "); MYSERIAL.print(sqrt( - sqr(pgm_read_float(true_pts + i * 2) - measured_pts[i * 2]) + - sqr(pgm_read_float(true_pts + i * 2 + 1) - measured_pts[i * 2 + 1])), 5); + sqr(pgm_read_float(true_pts + i * 2) - measured_pts[i * 2]) + + sqr(pgm_read_float(true_pts + i * 2 + 1) - measured_pts[i * 2 + 1])), 5); SERIAL_ECHOLNPGM(""); } delay_keep_alive(100); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Run some iterations of the Gauss-Newton method of non-linear least squares. // Initial set of parameters: @@ -278,7 +280,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( float A[4][4] = { 0.f }; float b[4] = { 0.f }; float acc; - delay_keep_alive(0); //manage heater, reset watchdog, manage inactivity + delay_keep_alive(0); //manage heater, reset watchdog, manage inactivity for (uint8_t r = 0; r < 4; ++r) { for (uint8_t c = 0; c < 4; ++c) { acc = 0; @@ -286,29 +288,29 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( for (uint8_t i = 0; i < npts; ++i) { // First for the residuum in the x axis: if (r != 1 && c != 1) { - float a = - (r == 0) ? 1.f : + float a = + (r == 0) ? 1.f : ((r == 2) ? (-s1 * measured_pts[2 * i]) : - (-c2 * measured_pts[2 * i + 1])); - float b = - (c == 0) ? 1.f : + (-c2 * measured_pts[2 * i + 1])); + float b = + (c == 0) ? 1.f : ((c == 2) ? (-s1 * measured_pts[2 * i]) : - (-c2 * measured_pts[2 * i + 1])); + (-c2 * measured_pts[2 * i + 1])); float w = point_weight_x(i, measured_pts[2 * i + 1]); acc += a * b * w; } - // Second for the residuum in the y axis. + // Second for the residuum in the y axis. // The first row of the points have a low weight, because their position may not be known // with a sufficient accuracy. if (r != 0 && c != 0) { - float a = - (r == 1) ? 1.f : + float a = + (r == 1) ? 1.f : ((r == 2) ? ( c1 * measured_pts[2 * i]) : - (-s2 * measured_pts[2 * i + 1])); - float b = - (c == 1) ? 1.f : + (-s2 * measured_pts[2 * i + 1])); + float b = + (c == 1) ? 1.f : ((c == 2) ? ( c1 * measured_pts[2 * i]) : - (-s2 * measured_pts[2 * i + 1])); + (-s2 * measured_pts[2 * i + 1])); float w = point_weight_y(i, measured_pts[2 * i + 1]); acc += a * b * w; } @@ -319,21 +321,21 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( acc = 0.f; for (uint8_t i = 0; i < npts; ++i) { { - float j = - (r == 0) ? 1.f : + float j = + (r == 0) ? 1.f : ((r == 1) ? 0.f : - ((r == 2) ? (-s1 * measured_pts[2 * i]) : - (-c2 * measured_pts[2 * i + 1]))); + ((r == 2) ? (-s1 * measured_pts[2 * i]) : + (-c2 * measured_pts[2 * i + 1]))); float fx = c1 * measured_pts[2 * i] - s2 * measured_pts[2 * i + 1] + cntr[0] - pgm_read_float(true_pts + i * 2); float w = point_weight_x(i, measured_pts[2 * i + 1]); acc += j * fx * w; } { - float j = - (r == 0) ? 0.f : + float j = + (r == 0) ? 0.f : ((r == 1) ? 1.f : - ((r == 2) ? ( c1 * measured_pts[2 * i]) : - (-s2 * measured_pts[2 * i + 1]))); + ((r == 2) ? ( c1 * measured_pts[2 * i]) : + (-s2 * measured_pts[2 * i + 1]))); float fy = s1 * measured_pts[2 * i] + c2 * measured_pts[2 * i + 1] + cntr[1] - pgm_read_float(true_pts + i * 2 + 1); float w = point_weight_y(i, measured_pts[2 * i + 1]); acc += j * fy * w; @@ -360,11 +362,11 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( a1 += h[2]; a2 += h[3]; - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 20) { SERIAL_ECHOPGM("iteration: "); MYSERIAL.print(int(iter)); - SERIAL_ECHOPGM("; correction vector: "); + SERIAL_ECHOPGM("; correction vector: "); MYSERIAL.print(h[0], 5); SERIAL_ECHOPGM(", "); MYSERIAL.print(h[1], 5); @@ -384,7 +386,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( MYSERIAL.print(180.f * a2 / M_PI, 5); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY } vec_x[0] = cos(a1) * MACHINE_AXIS_SCALE_X; @@ -395,16 +397,16 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( BedSkewOffsetDetectionResultType result = BED_SKEW_OFFSET_DETECTION_PERFECT; { angleDiff = fabs(a2 - a1); - eeprom_update_float((float*)(EEPROM_XYZ_CAL_SKEW), angleDiff); //storing xyz cal. skew to be able to show in support menu later + eeprom_update_float((float*)(EEPROM_XYZ_CAL_SKEW), angleDiff); //storing xyz cal. skew to be able to show in support menu later if (angleDiff > bed_skew_angle_mild) result = (angleDiff > bed_skew_angle_extreme) ? - BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME : - BED_SKEW_OFFSET_DETECTION_SKEW_MILD; + BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME : + BED_SKEW_OFFSET_DETECTION_SKEW_MILD; if (fabs(a1) > bed_skew_angle_extreme || - fabs(a2) > bed_skew_angle_extreme) + fabs(a2) > bed_skew_angle_extreme) result = BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME; } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 1) { SERIAL_ECHOPGM("correction angles: "); MYSERIAL.print(180.f * a1 / M_PI, 5); @@ -436,7 +438,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( SERIAL_ECHOLNPGM("Error after correction: "); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Measure the error after correction. for (uint8_t i = 0; i < npts; ++i) { float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1] + cntr[0]; @@ -444,46 +446,46 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( float errX = sqr(pgm_read_float(true_pts + i * 2) - x); float errY = sqr(pgm_read_float(true_pts + i * 2 + 1) - y); float err = sqrt(errX + errY); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) { - SERIAL_ECHOPGM("point #"); - MYSERIAL.print(int(i)); - SERIAL_ECHOLNPGM(":"); - } - #endif // SUPPORT_VERBOSITY - - if (point_on_1st_row(i)) { - #ifdef SUPPORT_VERBOSITY - if(verbosity_level >= 20) SERIAL_ECHOPGM("Point on first row"); - #endif // SUPPORT_VERBOSITY - float w = point_weight_y(i, measured_pts[2 * i + 1]); - if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X || - (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) { - result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOPGM(", weigth Y: "); - MYSERIAL.print(w); - if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X) SERIAL_ECHOPGM(", error X > max. error X"); - if (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y) SERIAL_ECHOPGM(", error Y > max. error Y"); - } - #endif // SUPPORT_VERBOSITY - } - } - else { - #ifdef SUPPORT_VERBOSITY - if(verbosity_level >=20 ) SERIAL_ECHOPGM("Point not on first row"); - #endif // SUPPORT_VERBOSITY - if (err > BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN) { - result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; - #ifdef SUPPORT_VERBOSITY - if(verbosity_level >= 20) SERIAL_ECHOPGM(", error > max. error euclidian"); - #endif // SUPPORT_VERBOSITY - } - } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 10) { - SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("point #"); + MYSERIAL.print(int(i)); + SERIAL_ECHOLNPGM(":"); + } +#endif // SUPPORT_VERBOSITY + + if (point_on_1st_row(i)) { +#ifdef SUPPORT_VERBOSITY + if(verbosity_level >= 20) SERIAL_ECHOPGM("Point on first row"); +#endif // SUPPORT_VERBOSITY + float w = point_weight_y(i, measured_pts[2 * i + 1]); + if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X || + (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y)) { + result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOPGM(", weigth Y: "); + MYSERIAL.print(w); + if (sqrt(errX) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X) SERIAL_ECHOPGM(", error X > max. error X"); + if (w != 0.f && sqrt(errY) > BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y) SERIAL_ECHOPGM(", error Y > max. error Y"); + } +#endif // SUPPORT_VERBOSITY + } + } + else { +#ifdef SUPPORT_VERBOSITY + if(verbosity_level >=20 ) SERIAL_ECHOPGM("Point not on first row"); +#endif // SUPPORT_VERBOSITY + if (err > BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN) { + result = BED_SKEW_OFFSET_DETECTION_FITTING_FAILED; +#ifdef SUPPORT_VERBOSITY + if(verbosity_level >= 20) SERIAL_ECHOPGM(", error > max. error euclidian"); +#endif // SUPPORT_VERBOSITY + } + } +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) { + SERIAL_ECHOLNPGM(""); SERIAL_ECHOPGM("measured: ("); MYSERIAL.print(measured_pts[i * 2], 5); SERIAL_ECHOPGM(", "); @@ -496,50 +498,50 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( MYSERIAL.print(pgm_read_float(true_pts + i * 2), 5); SERIAL_ECHOPGM(", "); MYSERIAL.print(pgm_read_float(true_pts + i * 2 + 1), 5); - SERIAL_ECHOLNPGM(")"); - SERIAL_ECHOPGM("error: "); + SERIAL_ECHOLNPGM(")"); + SERIAL_ECHOPGM("error: "); MYSERIAL.print(err); - SERIAL_ECHOPGM(", error X: "); - MYSERIAL.print(sqrt(errX)); - SERIAL_ECHOPGM(", error Y: "); - MYSERIAL.print(sqrt(errY)); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY + SERIAL_ECHOPGM(", error X: "); + MYSERIAL.print(sqrt(errX)); + SERIAL_ECHOPGM(", error Y: "); + MYSERIAL.print(sqrt(errY)); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY + } +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("Max. errors:"); + SERIAL_ECHOPGM("Max. error X:"); + MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X); + SERIAL_ECHOPGM("Max. error Y:"); + MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y); + SERIAL_ECHOPGM("Max. error euclidian:"); + MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN); + SERIAL_ECHOLNPGM(""); } - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM("Max. errors:"); - SERIAL_ECHOPGM("Max. error X:"); - MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_X); - SERIAL_ECHOPGM("Max. error Y:"); - MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_1ST_ROW_Y); - SERIAL_ECHOPGM("Max. error euclidian:"); - MYSERIAL.println(BED_CALIBRATION_POINT_OFFSET_MAX_EUCLIDIAN); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY - - #if 0 +#endif // SUPPORT_VERBOSITY + +#if 0 if (result == BED_SKEW_OFFSET_DETECTION_PERFECT && fabs(a1) < bed_skew_angle_mild && fabs(a2) < bed_skew_angle_mild) { - #ifdef SUPPORT_VERBOSITY - if (verbosity_level > 0) +#ifdef SUPPORT_VERBOSITY + if (verbosity_level > 0) SERIAL_ECHOLNPGM("Very little skew detected. Disabling skew correction."); - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Just disable the skew correction. vec_x[0] = MACHINE_AXIS_SCALE_X; vec_x[1] = 0.f; vec_y[0] = 0.f; vec_y[1] = MACHINE_AXIS_SCALE_Y; } - #else +#else if (result == BED_SKEW_OFFSET_DETECTION_PERFECT) { - #ifdef SUPPORT_VERBOSITY - if (verbosity_level > 0) +#ifdef SUPPORT_VERBOSITY + if (verbosity_level > 0) SERIAL_ECHOLNPGM("Very little skew detected. Orthogonalizing the axes."); - #endif // SUPPORT_VERBOSITY - // Orthogonalize the axes. +#endif // SUPPORT_VERBOSITY + // Orthogonalize the axes. a1 = 0.5f * (a1 + a2); vec_x[0] = cos(a1) * MACHINE_AXIS_SCALE_X; vec_x[1] = sin(a1) * MACHINE_AXIS_SCALE_X; @@ -554,58 +556,58 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( float x = vec_x[0] * measured_pts[i * 2] + vec_y[0] * measured_pts[i * 2 + 1]; float y = vec_x[1] * measured_pts[i * 2] + vec_y[1] * measured_pts[i * 2 + 1]; float w = point_weight_x(i, y); - cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x); - wx += w; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - MYSERIAL.print(i); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("Weight_x:"); - MYSERIAL.print(w); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("cntr[0]:"); - MYSERIAL.print(cntr[0]); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("wx:"); - MYSERIAL.print(wx); - } - #endif // SUPPORT_VERBOSITY + cntr[0] += w * (pgm_read_float(true_pts + i * 2) - x); + wx += w; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + MYSERIAL.print(i); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Weight_x:"); + MYSERIAL.print(w); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("cntr[0]:"); + MYSERIAL.print(cntr[0]); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("wx:"); + MYSERIAL.print(wx); + } +#endif // SUPPORT_VERBOSITY w = point_weight_y(i, y); - cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y); - wy += w; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("Weight_y:"); - MYSERIAL.print(w); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("cntr[1]:"); - MYSERIAL.print(cntr[1]); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("wy:"); - MYSERIAL.print(wy); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY - - } + cntr[1] += w * (pgm_read_float(true_pts + i * 2 + 1) - y); + wy += w; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Weight_y:"); + MYSERIAL.print(w); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("cntr[1]:"); + MYSERIAL.print(cntr[1]); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("wy:"); + MYSERIAL.print(wy); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY + + } cntr[0] /= wx; cntr[1] /= wy; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("Final cntr values:"); - SERIAL_ECHOLNPGM("cntr[0]:"); - MYSERIAL.print(cntr[0]); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("cntr[1]:"); - MYSERIAL.print(cntr[1]); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Final cntr values:"); + SERIAL_ECHOLNPGM("cntr[0]:"); + MYSERIAL.print(cntr[0]); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("cntr[1]:"); + MYSERIAL.print(cntr[1]); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY } - #endif +#endif // Invert the transformation matrix made of vec_x, vec_y and cntr. { @@ -616,8 +618,8 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( }; float cntrInv[2] = { -Ainv[0][0] * cntr[0] - Ainv[0][1] * cntr[1], - -Ainv[1][0] * cntr[0] - Ainv[1][1] * cntr[1] - }; + -Ainv[1][0] * cntr[0] - Ainv[1][1] * cntr[1] + }; vec_x[0] = Ainv[0][0]; vec_x[1] = Ainv[1][0]; vec_y[0] = Ainv[0][1]; @@ -625,7 +627,7 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( cntr[0] = cntrInv[0]; cntr[1] = cntrInv[1]; } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 1) { // Show the adjusted state, before the fitting. SERIAL_ECHOPGM("X vector, adjusted: "); @@ -671,16 +673,16 @@ BedSkewOffsetDetectionResultType calculate_machine_skew_and_offset_LS( MYSERIAL.print(sqrt(sqr(measured_pts[i * 2] - x) + sqr(measured_pts[i * 2 + 1] - y))); SERIAL_ECHOLNPGM(""); } - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM("Calculate offset and skew returning result:"); - MYSERIAL.print(int(result)); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOLNPGM(""); - } + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM("Calculate offset and skew returning result:"); + MYSERIAL.print(int(result)); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOLNPGM(""); + } delay_keep_alive(100); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY return result; @@ -726,7 +728,7 @@ static void world2machine_update(const float vec_x[2], const float vec_y[2], con // Shift correction. world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SHIFT; if (world2machine_rotation_and_skew[0][0] != 1.f || world2machine_rotation_and_skew[0][1] != 0.f || - world2machine_rotation_and_skew[1][0] != 0.f || world2machine_rotation_and_skew[1][1] != 1.f) { + world2machine_rotation_and_skew[1][0] != 0.f || world2machine_rotation_and_skew[1][1] != 1.f) { // Rotation & skew correction. world2machine_correction_mode |= WORLD2MACHINE_CORRECTION_SKEW; // Invert the world2machine matrix. @@ -950,33 +952,33 @@ static inline void go_to_current(float fr) static inline void update_current_position_xyz() { - current_position[X_AXIS] = st_get_position_mm(X_AXIS); - current_position[Y_AXIS] = st_get_position_mm(Y_AXIS); - current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + current_position[X_AXIS] = st_get_position_mm(X_AXIS); + current_position[Y_AXIS] = st_get_position_mm(Y_AXIS); + current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); } static inline void update_current_position_z() { - current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); - plan_set_z_position(current_position[Z_AXIS]); + current_position[Z_AXIS] = st_get_position_mm(Z_AXIS); + plan_set_z_position(current_position[Z_AXIS]); } // At the current position, find the Z stop. inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, int #ifdef SUPPORT_VERBOSITY - verbosity_level + verbosity_level #endif //SUPPORT_VERBOSITY - ) + ) { #ifdef TMC2130 - FORCE_HIGH_POWER_START; + FORCE_HIGH_POWER_START; #endif - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if(verbosity_level >= 10) SERIAL_ECHOLNPGM("find bed induction sensor point z"); - #endif // SUPPORT_VERBOSITY - bool endstops_enabled = enable_endstops(true); +#endif // SUPPORT_VERBOSITY + bool endstops_enabled = enable_endstops(true); bool endstop_z_enabled = enable_z_endstop(false); float z = 0.f; endstop_z_hit_on_purpose(); @@ -989,10 +991,10 @@ inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, i if (! endstop_z_hit_on_purpose()) goto error; #ifdef TMC2130 - if (READ(Z_TMC2130_DIAG) != 0) goto error; //crash Z detected + if (READ(Z_TMC2130_DIAG) != 0) goto error; //crash Z detected #endif //TMC2130 for (uint8_t i = 0; i < n_iter; ++ i) - { + { // Move up the retract distance. current_position[Z_AXIS] += .5f; go_to_current(homing_feedrate[Z_AXIS]/60); @@ -1004,15 +1006,15 @@ inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, i if (! endstop_z_hit_on_purpose()) goto error; #ifdef TMC2130 - if (READ(Z_TMC2130_DIAG) != 0) goto error; //crash Z detected + if (READ(Z_TMC2130_DIAG) != 0) goto error; //crash Z detected #endif //TMC2130 // SERIAL_ECHOPGM("Bed find_bed_induction_sensor_point_z low, height: "); // MYSERIAL.print(current_position[Z_AXIS], 5); // SERIAL_ECHOLNPGM(""); - float dz = i?abs(current_position[Z_AXIS] - (z / i)):0; + float dz = i?abs(current_position[Z_AXIS] - (z / i)):0; z += current_position[Z_AXIS]; // printf_P(PSTR(" Z[%d] = %d, dz=%d\n"), i, (int)(current_position[Z_AXIS] * 1000), (int)(dz * 1000)); - if (dz > 0.05) goto error;//deviation > 50um + if (dz > 0.05) goto error;//deviation > 50um } current_position[Z_AXIS] = z; if (n_iter > 1) @@ -1023,18 +1025,18 @@ inline bool find_bed_induction_sensor_point_z(float minimum_z, uint8_t n_iter, i enable_z_endstop(endstop_z_enabled); // SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 3"); #ifdef TMC2130 - FORCE_HIGH_POWER_END; + FORCE_HIGH_POWER_END; #endif - return true; + return true; error: // SERIAL_ECHOLNPGM("find_bed_induction_sensor_point_z 4"); enable_endstops(endstops_enabled); enable_z_endstop(endstop_z_enabled); #ifdef TMC2130 - FORCE_HIGH_POWER_END; + FORCE_HIGH_POWER_END; #endif - return false; + return false; } #ifdef NEW_XYZCAL @@ -1058,453 +1060,454 @@ inline bool find_bed_induction_sensor_point_xy(int #if !defined (NEW_XYZCAL) && defined (SUPPORT_VERBOSITY) verbosity_level #endif - ) + ) { #ifdef NEW_XYZCAL - return xyzcal_find_bed_induction_sensor_point_xy(); + return xyzcal_find_bed_induction_sensor_point_xy(); #else //NEW_XYZCAL - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) MYSERIAL.println("find bed induction sensor point xy"); - #endif // SUPPORT_VERBOSITY - float feedrate = homing_feedrate[X_AXIS] / 60.f; - bool found = false; - - { - float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; - float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; - float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; - float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; - uint8_t nsteps_y; - uint8_t i; - if (x0 < X_MIN_POS) { - x0 = X_MIN_POS; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius lower than X_MIN. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - if (x1 > X_MAX_POS) { - x1 = X_MAX_POS; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius higher than X_MAX. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) { - y0 = Y_MIN_POS_FOR_BED_CALIBRATION; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius lower than Y_MIN. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - if (y1 > Y_MAX_POS) { - y1 = Y_MAX_POS; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius higher than X_MAX. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP)); - - enable_endstops(false); - bool dir_positive = true; - float z_error = 2 * FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP; - float find_bed_induction_sensor_point_z_step = FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP; - float initial_z_position = current_position[Z_AXIS]; - - // go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); - go_xyz(x0, y0, current_position[Z_AXIS], feedrate); - // Continously lower the Z axis. - endstops_hit_on_purpose(); - enable_z_endstop(true); - bool direction = false; - while (current_position[Z_AXIS] > -10.f && z_error > FIND_BED_INDUCTION_SENSOR_POINT_MAX_Z_ERROR) { - // Do nsteps_y zig-zag movements. - - SERIAL_ECHOPGM("z_error: "); - MYSERIAL.println(z_error); - current_position[Y_AXIS] = direction ? y1 : y0; - initial_z_position = current_position[Z_AXIS]; - for (i = 0; i < (nsteps_y - 1); (direction == false) ? (current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1)) : (current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1)), ++i) { - // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. - current_position[Z_AXIS] -= find_bed_induction_sensor_point_z_step / float(nsteps_y - 1); - go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); - dir_positive = !dir_positive; - if (endstop_z_hit_on_purpose()) { - update_current_position_xyz(); - z_error = initial_z_position - current_position[Z_AXIS] + find_bed_induction_sensor_point_z_step; - if (z_error > FIND_BED_INDUCTION_SENSOR_POINT_MAX_Z_ERROR) { - find_bed_induction_sensor_point_z_step = z_error / 2; - current_position[Z_AXIS] += z_error; - enable_z_endstop(false); - (direction == false) ? go_xyz(x0, y0, current_position[Z_AXIS], feedrate) : go_xyz(x0, y1, current_position[Z_AXIS], feedrate); - enable_z_endstop(true); - } - goto endloop; - } - } - for (i = 0; i < (nsteps_y - 1); (direction == false) ? (current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1)) : (current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1)), ++i) { - // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. - current_position[Z_AXIS] -= find_bed_induction_sensor_point_z_step / float(nsteps_y - 1); - go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); - dir_positive = !dir_positive; - if (endstop_z_hit_on_purpose()) { - update_current_position_xyz(); - z_error = initial_z_position - current_position[Z_AXIS]; - if (z_error > FIND_BED_INDUCTION_SENSOR_POINT_MAX_Z_ERROR) { - find_bed_induction_sensor_point_z_step = z_error / 2; - current_position[Z_AXIS] += z_error; - enable_z_endstop(false); - direction = !direction; - (direction == false) ? go_xyz(x0, y0, current_position[Z_AXIS], feedrate) : go_xyz(x0, y1, current_position[Z_AXIS], feedrate); - enable_z_endstop(true); - } - goto endloop; - } - } - endloop:; - } - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHO("First hit"); - SERIAL_ECHO("- X: "); - MYSERIAL.print(current_position[X_AXIS]); - SERIAL_ECHO("; Y: "); - MYSERIAL.print(current_position[Y_AXIS]); - SERIAL_ECHO("; Z: "); - MYSERIAL.println(current_position[Z_AXIS]); - } - #endif //SUPPORT_VERBOSITY - //lcd_show_fullscreen_message_and_wait_P(PSTR("First hit")); - //lcd_update_enable(true); - - float init_x_position = current_position[X_AXIS]; - float init_y_position = current_position[Y_AXIS]; - - // we have to let the planner know where we are right now as it is not where we said to go. - update_current_position_xyz(); - enable_z_endstop(false); - - for (int8_t iter = 0; iter < 2; ++iter) { - /*SERIAL_ECHOPGM("iter: "); - MYSERIAL.println(iter); - SERIAL_ECHOPGM("1 - current_position[Z_AXIS]: "); - MYSERIAL.println(current_position[Z_AXIS]);*/ - - // Slightly lower the Z axis to get a reliable trigger. - current_position[Z_AXIS] -= 0.1f; - go_xyz(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], homing_feedrate[Z_AXIS] / (60 * 10)); - - SERIAL_ECHOPGM("2 - current_position[Z_AXIS]: "); - MYSERIAL.println(current_position[Z_AXIS]); - // Do nsteps_y zig-zag movements. - float a, b; - float avg[2] = { 0,0 }; - invert_z_endstop(true); - for (int iteration = 0; iteration < 8; iteration++) { - - found = false; - enable_z_endstop(true); - go_xy(init_x_position + 16.0f, current_position[Y_AXIS], feedrate / 5); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search X span 0 - not found"); - continue; - } - // SERIAL_ECHOLN("Search X span 0 - found"); - a = current_position[X_AXIS]; - enable_z_endstop(false); - go_xy(init_x_position, current_position[Y_AXIS], feedrate / 5); - enable_z_endstop(true); - go_xy(init_x_position - 16.0f, current_position[Y_AXIS], feedrate / 5); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search X span 1 - not found"); - continue; - } - // SERIAL_ECHOLN("Search X span 1 - found"); - b = current_position[X_AXIS]; - // Go to the center. - enable_z_endstop(false); - current_position[X_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], init_y_position, feedrate / 5); - found = true; - - // Search in the Y direction along a cross. - found = false; - enable_z_endstop(true); - go_xy(current_position[X_AXIS], init_y_position + 16.0f, feedrate / 5); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search Y2 span 0 - not found"); - continue; - } - // SERIAL_ECHOLN("Search Y2 span 0 - found"); - a = current_position[Y_AXIS]; - enable_z_endstop(false); - go_xy(current_position[X_AXIS], init_y_position, feedrate / 5); - enable_z_endstop(true); - go_xy(current_position[X_AXIS], init_y_position - 16.0f, feedrate / 5); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search Y2 span 1 - not found"); - continue; - } - // SERIAL_ECHOLN("Search Y2 span 1 - found"); - b = current_position[Y_AXIS]; - // Go to the center. - enable_z_endstop(false); - current_position[Y_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate / 5); - - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOPGM("ITERATION: "); - MYSERIAL.println(iteration); - SERIAL_ECHOPGM("CURRENT POSITION X: "); - MYSERIAL.println(current_position[X_AXIS]); - SERIAL_ECHOPGM("CURRENT POSITION Y: "); - MYSERIAL.println(current_position[Y_AXIS]); - } - #endif //SUPPORT_VERBOSITY - - if (iteration > 0) { - // Average the last 7 measurements. - avg[X_AXIS] += current_position[X_AXIS]; - avg[Y_AXIS] += current_position[Y_AXIS]; - } - - init_x_position = current_position[X_AXIS]; - init_y_position = current_position[Y_AXIS]; - - found = true; - - } - invert_z_endstop(false); - avg[X_AXIS] *= (1.f / 7.f); - avg[Y_AXIS] *= (1.f / 7.f); - - current_position[X_AXIS] = avg[X_AXIS]; - current_position[Y_AXIS] = avg[Y_AXIS]; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOPGM("AVG CURRENT POSITION X: "); - MYSERIAL.println(current_position[X_AXIS]); - SERIAL_ECHOPGM("AVG CURRENT POSITION Y: "); - MYSERIAL.println(current_position[Y_AXIS]); - } - #endif // SUPPORT_VERBOSITY - go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - lcd_show_fullscreen_message_and_wait_P(PSTR("Final position")); - lcd_update_enable(true); - } - #endif //SUPPORT_VERBOSITY - - break; - } - } - - enable_z_endstop(false); - invert_z_endstop(false); - return found; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) MYSERIAL.println("find bed induction sensor point xy"); +#endif // SUPPORT_VERBOSITY + float feedrate = homing_feedrate[X_AXIS] / 60.f; + bool found = false; + + { + float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; + float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; + float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; + float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; + uint8_t nsteps_y; + uint8_t i; + if (x0 < X_MIN_POS) { + x0 = X_MIN_POS; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius lower than X_MIN. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + if (x1 > X_MAX_POS) { + x1 = X_MAX_POS; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius higher than X_MAX. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) { + y0 = Y_MIN_POS_FOR_BED_CALIBRATION; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius lower than Y_MIN. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + if (y1 > Y_MAX_POS) { + y1 = Y_MAX_POS; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius higher than X_MAX. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP)); + + enable_endstops(false); + bool dir_positive = true; + float z_error = 2 * FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP; + float find_bed_induction_sensor_point_z_step = FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP; + float initial_z_position = current_position[Z_AXIS]; + + // go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); + go_xyz(x0, y0, current_position[Z_AXIS], feedrate); + // Continously lower the Z axis. + endstops_hit_on_purpose(); + enable_z_endstop(true); + bool direction = false; + while (current_position[Z_AXIS] > -10.f && z_error > FIND_BED_INDUCTION_SENSOR_POINT_MAX_Z_ERROR) { + // Do nsteps_y zig-zag movements. + + SERIAL_ECHOPGM("z_error: "); + MYSERIAL.println(z_error); + current_position[Y_AXIS] = direction ? y1 : y0; + initial_z_position = current_position[Z_AXIS]; + for (i = 0; i < (nsteps_y - 1); (direction == false) ? (current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1)) : (current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1)), ++i) { + // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. + current_position[Z_AXIS] -= find_bed_induction_sensor_point_z_step / float(nsteps_y - 1); + go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); + dir_positive = !dir_positive; + if (endstop_z_hit_on_purpose()) { + update_current_position_xyz(); + z_error = initial_z_position - current_position[Z_AXIS] + find_bed_induction_sensor_point_z_step; + if (z_error > FIND_BED_INDUCTION_SENSOR_POINT_MAX_Z_ERROR) { + find_bed_induction_sensor_point_z_step = z_error / 2; + current_position[Z_AXIS] += z_error; + enable_z_endstop(false); + (direction == false) ? go_xyz(x0, y0, current_position[Z_AXIS], feedrate) : go_xyz(x0, y1, current_position[Z_AXIS], feedrate); + enable_z_endstop(true); + } + goto endloop; + } + } + for (i = 0; i < (nsteps_y - 1); (direction == false) ? (current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1)) : (current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1)), ++i) { + // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. + current_position[Z_AXIS] -= find_bed_induction_sensor_point_z_step / float(nsteps_y - 1); + go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); + dir_positive = !dir_positive; + if (endstop_z_hit_on_purpose()) { + update_current_position_xyz(); + z_error = initial_z_position - current_position[Z_AXIS]; + if (z_error > FIND_BED_INDUCTION_SENSOR_POINT_MAX_Z_ERROR) { + find_bed_induction_sensor_point_z_step = z_error / 2; + current_position[Z_AXIS] += z_error; + enable_z_endstop(false); + direction = !direction; + (direction == false) ? go_xyz(x0, y0, current_position[Z_AXIS], feedrate) : go_xyz(x0, y1, current_position[Z_AXIS], feedrate); + enable_z_endstop(true); + } + goto endloop; + } + } +endloop: + ; + } +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHO("First hit"); + SERIAL_ECHO("- X: "); + MYSERIAL.print(current_position[X_AXIS]); + SERIAL_ECHO("; Y: "); + MYSERIAL.print(current_position[Y_AXIS]); + SERIAL_ECHO("; Z: "); + MYSERIAL.println(current_position[Z_AXIS]); + } +#endif //SUPPORT_VERBOSITY + //lcd_show_fullscreen_message_and_wait_P(PSTR("First hit")); + //lcd_update_enable(true); + + float init_x_position = current_position[X_AXIS]; + float init_y_position = current_position[Y_AXIS]; + + // we have to let the planner know where we are right now as it is not where we said to go. + update_current_position_xyz(); + enable_z_endstop(false); + + for (int8_t iter = 0; iter < 2; ++iter) { + /*SERIAL_ECHOPGM("iter: "); + MYSERIAL.println(iter); + SERIAL_ECHOPGM("1 - current_position[Z_AXIS]: "); + MYSERIAL.println(current_position[Z_AXIS]);*/ + + // Slightly lower the Z axis to get a reliable trigger. + current_position[Z_AXIS] -= 0.1f; + go_xyz(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], homing_feedrate[Z_AXIS] / (60 * 10)); + + SERIAL_ECHOPGM("2 - current_position[Z_AXIS]: "); + MYSERIAL.println(current_position[Z_AXIS]); + // Do nsteps_y zig-zag movements. + float a, b; + float avg[2] = { 0,0 }; + invert_z_endstop(true); + for (int iteration = 0; iteration < 8; iteration++) { + + found = false; + enable_z_endstop(true); + go_xy(init_x_position + 16.0f, current_position[Y_AXIS], feedrate / 5); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search X span 0 - not found"); + continue; + } + // SERIAL_ECHOLN("Search X span 0 - found"); + a = current_position[X_AXIS]; + enable_z_endstop(false); + go_xy(init_x_position, current_position[Y_AXIS], feedrate / 5); + enable_z_endstop(true); + go_xy(init_x_position - 16.0f, current_position[Y_AXIS], feedrate / 5); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search X span 1 - not found"); + continue; + } + // SERIAL_ECHOLN("Search X span 1 - found"); + b = current_position[X_AXIS]; + // Go to the center. + enable_z_endstop(false); + current_position[X_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], init_y_position, feedrate / 5); + found = true; + + // Search in the Y direction along a cross. + found = false; + enable_z_endstop(true); + go_xy(current_position[X_AXIS], init_y_position + 16.0f, feedrate / 5); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search Y2 span 0 - not found"); + continue; + } + // SERIAL_ECHOLN("Search Y2 span 0 - found"); + a = current_position[Y_AXIS]; + enable_z_endstop(false); + go_xy(current_position[X_AXIS], init_y_position, feedrate / 5); + enable_z_endstop(true); + go_xy(current_position[X_AXIS], init_y_position - 16.0f, feedrate / 5); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search Y2 span 1 - not found"); + continue; + } + // SERIAL_ECHOLN("Search Y2 span 1 - found"); + b = current_position[Y_AXIS]; + // Go to the center. + enable_z_endstop(false); + current_position[Y_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate / 5); + +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("ITERATION: "); + MYSERIAL.println(iteration); + SERIAL_ECHOPGM("CURRENT POSITION X: "); + MYSERIAL.println(current_position[X_AXIS]); + SERIAL_ECHOPGM("CURRENT POSITION Y: "); + MYSERIAL.println(current_position[Y_AXIS]); + } +#endif //SUPPORT_VERBOSITY + + if (iteration > 0) { + // Average the last 7 measurements. + avg[X_AXIS] += current_position[X_AXIS]; + avg[Y_AXIS] += current_position[Y_AXIS]; + } + + init_x_position = current_position[X_AXIS]; + init_y_position = current_position[Y_AXIS]; + + found = true; + + } + invert_z_endstop(false); + avg[X_AXIS] *= (1.f / 7.f); + avg[Y_AXIS] *= (1.f / 7.f); + + current_position[X_AXIS] = avg[X_AXIS]; + current_position[Y_AXIS] = avg[Y_AXIS]; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("AVG CURRENT POSITION X: "); + MYSERIAL.println(current_position[X_AXIS]); + SERIAL_ECHOPGM("AVG CURRENT POSITION Y: "); + MYSERIAL.println(current_position[Y_AXIS]); + } +#endif // SUPPORT_VERBOSITY + go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + lcd_show_fullscreen_message_and_wait_P(PSTR("Final position")); + lcd_update_enable(true); + } +#endif //SUPPORT_VERBOSITY + + break; + } + } + + enable_z_endstop(false); + invert_z_endstop(false); + return found; #endif //NEW_XYZCAL } #else //HEATBED_V2 inline bool find_bed_induction_sensor_point_xy(int verbosity_level) { #ifdef NEW_XYZCAL - return xyzcal_find_bed_induction_sensor_point_xy(); + return xyzcal_find_bed_induction_sensor_point_xy(); #else //NEW_XYZCAL - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) MYSERIAL.println("find bed induction sensor point xy"); - #endif // SUPPORT_VERBOSITY - float feedrate = homing_feedrate[X_AXIS] / 60.f; - bool found = false; - - { - float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; - float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; - float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; - float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; - uint8_t nsteps_y; - uint8_t i; - if (x0 < X_MIN_POS) { - x0 = X_MIN_POS; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius lower than X_MIN. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - if (x1 > X_MAX_POS) { - x1 = X_MAX_POS; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius higher than X_MAX. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) { - y0 = Y_MIN_POS_FOR_BED_CALIBRATION; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius lower than Y_MIN. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - if (y1 > Y_MAX_POS) { - y1 = Y_MAX_POS; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius higher than X_MAX. Clamping was done."); - #endif // SUPPORT_VERBOSITY - } - nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP)); - - enable_endstops(false); - bool dir_positive = true; - - // go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); - go_xyz(x0, y0, current_position[Z_AXIS], feedrate); - // Continously lower the Z axis. - endstops_hit_on_purpose(); - enable_z_endstop(true); - while (current_position[Z_AXIS] > -10.f) { - // Do nsteps_y zig-zag movements. - current_position[Y_AXIS] = y0; - for (i = 0; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++i) { - // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. - current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); - go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); - dir_positive = !dir_positive; - if (endstop_z_hit_on_purpose()) - goto endloop; - } - for (i = 0; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++i) { - // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. - current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); - go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); - dir_positive = !dir_positive; - if (endstop_z_hit_on_purpose()) - goto endloop; - } - } - endloop: - // SERIAL_ECHOLN("First hit"); - - // we have to let the planner know where we are right now as it is not where we said to go. - update_current_position_xyz(); - - // Search in this plane for the first hit. Zig-zag first in X, then in Y axis. - for (int8_t iter = 0; iter < 3; ++iter) { - if (iter > 0) { - // Slightly lower the Z axis to get a reliable trigger. - current_position[Z_AXIS] -= 0.02f; - go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS] / 60); - } - - // Do nsteps_y zig-zag movements. - float a, b; - enable_endstops(false); - enable_z_endstop(false); - current_position[Y_AXIS] = y0; - go_xy(x0, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - found = false; - for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++i, dir_positive = !dir_positive) { - go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); - if (endstop_z_hit_on_purpose()) { - found = true; - break; - } - } - update_current_position_xyz(); - if (!found) { - // SERIAL_ECHOLN("Search in Y - not found"); - continue; - } - // SERIAL_ECHOLN("Search in Y - found"); - a = current_position[Y_AXIS]; - - enable_z_endstop(false); - current_position[Y_AXIS] = y1; - go_xy(x0, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - found = false; - for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++i, dir_positive = !dir_positive) { - go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); - if (endstop_z_hit_on_purpose()) { - found = true; - break; - } - } - update_current_position_xyz(); - if (!found) { - // SERIAL_ECHOLN("Search in Y2 - not found"); - continue; - } - // SERIAL_ECHOLN("Search in Y2 - found"); - b = current_position[Y_AXIS]; - current_position[Y_AXIS] = 0.5f * (a + b); - - // Search in the X direction along a cross. - found = false; - enable_z_endstop(false); - go_xy(x0, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - go_xy(x1, current_position[Y_AXIS], feedrate); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search X span 0 - not found"); - continue; - } - // SERIAL_ECHOLN("Search X span 0 - found"); - a = current_position[X_AXIS]; - enable_z_endstop(false); - go_xy(x1, current_position[Y_AXIS], feedrate); - enable_z_endstop(true); - go_xy(x0, current_position[Y_AXIS], feedrate); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search X span 1 - not found"); - continue; - } - // SERIAL_ECHOLN("Search X span 1 - found"); - b = current_position[X_AXIS]; - // Go to the center. - enable_z_endstop(false); - current_position[X_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); - found = true; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) MYSERIAL.println("find bed induction sensor point xy"); +#endif // SUPPORT_VERBOSITY + float feedrate = homing_feedrate[X_AXIS] / 60.f; + bool found = false; + + { + float x0 = current_position[X_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; + float x1 = current_position[X_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_X_RADIUS; + float y0 = current_position[Y_AXIS] - FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; + float y1 = current_position[Y_AXIS] + FIND_BED_INDUCTION_SENSOR_POINT_Y_RADIUS; + uint8_t nsteps_y; + uint8_t i; + if (x0 < X_MIN_POS) { + x0 = X_MIN_POS; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius lower than X_MIN. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + if (x1 > X_MAX_POS) { + x1 = X_MAX_POS; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("X searching radius higher than X_MAX. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + if (y0 < Y_MIN_POS_FOR_BED_CALIBRATION) { + y0 = Y_MIN_POS_FOR_BED_CALIBRATION; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius lower than Y_MIN. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + if (y1 > Y_MAX_POS) { + y1 = Y_MAX_POS; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) SERIAL_ECHOLNPGM("Y searching radius higher than X_MAX. Clamping was done."); +#endif // SUPPORT_VERBOSITY + } + nsteps_y = int(ceil((y1 - y0) / FIND_BED_INDUCTION_SENSOR_POINT_XY_STEP)); + + enable_endstops(false); + bool dir_positive = true; + + // go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS]/60); + go_xyz(x0, y0, current_position[Z_AXIS], feedrate); + // Continously lower the Z axis. + endstops_hit_on_purpose(); + enable_z_endstop(true); + while (current_position[Z_AXIS] > -10.f) { + // Do nsteps_y zig-zag movements. + current_position[Y_AXIS] = y0; + for (i = 0; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++i) { + // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. + current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); + go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); + dir_positive = !dir_positive; + if (endstop_z_hit_on_purpose()) + goto endloop; + } + for (i = 0; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++i) { + // Run with a slightly decreasing Z axis, zig-zag movement. Stop at the Z end-stop. + current_position[Z_AXIS] -= FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP / float(nsteps_y); + go_xyz(dir_positive ? x1 : x0, current_position[Y_AXIS], current_position[Z_AXIS], feedrate); + dir_positive = !dir_positive; + if (endstop_z_hit_on_purpose()) + goto endloop; + } + } +endloop: + // SERIAL_ECHOLN("First hit"); + + // we have to let the planner know where we are right now as it is not where we said to go. + update_current_position_xyz(); + + // Search in this plane for the first hit. Zig-zag first in X, then in Y axis. + for (int8_t iter = 0; iter < 3; ++iter) { + if (iter > 0) { + // Slightly lower the Z axis to get a reliable trigger. + current_position[Z_AXIS] -= 0.02f; + go_xyz(current_position[X_AXIS], current_position[Y_AXIS], MESH_HOME_Z_SEARCH, homing_feedrate[Z_AXIS] / 60); + } + + // Do nsteps_y zig-zag movements. + float a, b; + enable_endstops(false); + enable_z_endstop(false); + current_position[Y_AXIS] = y0; + go_xy(x0, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + found = false; + for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] += (y1 - y0) / float(nsteps_y - 1), ++i, dir_positive = !dir_positive) { + go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); + if (endstop_z_hit_on_purpose()) { + found = true; + break; + } + } + update_current_position_xyz(); + if (!found) { + // SERIAL_ECHOLN("Search in Y - not found"); + continue; + } + // SERIAL_ECHOLN("Search in Y - found"); + a = current_position[Y_AXIS]; + + enable_z_endstop(false); + current_position[Y_AXIS] = y1; + go_xy(x0, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + found = false; + for (i = 0, dir_positive = true; i < nsteps_y; current_position[Y_AXIS] -= (y1 - y0) / float(nsteps_y - 1), ++i, dir_positive = !dir_positive) { + go_xy(dir_positive ? x1 : x0, current_position[Y_AXIS], feedrate); + if (endstop_z_hit_on_purpose()) { + found = true; + break; + } + } + update_current_position_xyz(); + if (!found) { + // SERIAL_ECHOLN("Search in Y2 - not found"); + continue; + } + // SERIAL_ECHOLN("Search in Y2 - found"); + b = current_position[Y_AXIS]; + current_position[Y_AXIS] = 0.5f * (a + b); + + // Search in the X direction along a cross. + found = false; + enable_z_endstop(false); + go_xy(x0, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + go_xy(x1, current_position[Y_AXIS], feedrate); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search X span 0 - not found"); + continue; + } + // SERIAL_ECHOLN("Search X span 0 - found"); + a = current_position[X_AXIS]; + enable_z_endstop(false); + go_xy(x1, current_position[Y_AXIS], feedrate); + enable_z_endstop(true); + go_xy(x0, current_position[Y_AXIS], feedrate); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search X span 1 - not found"); + continue; + } + // SERIAL_ECHOLN("Search X span 1 - found"); + b = current_position[X_AXIS]; + // Go to the center. + enable_z_endstop(false); + current_position[X_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); + found = true; #if 1 - // Search in the Y direction along a cross. - found = false; - enable_z_endstop(false); - go_xy(current_position[X_AXIS], y0, feedrate); - enable_z_endstop(true); - go_xy(current_position[X_AXIS], y1, feedrate); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search Y2 span 0 - not found"); - continue; - } - // SERIAL_ECHOLN("Search Y2 span 0 - found"); - a = current_position[Y_AXIS]; - enable_z_endstop(false); - go_xy(current_position[X_AXIS], y1, feedrate); - enable_z_endstop(true); - go_xy(current_position[X_AXIS], y0, feedrate); - update_current_position_xyz(); - if (!endstop_z_hit_on_purpose()) { - // SERIAL_ECHOLN("Search Y2 span 1 - not found"); - continue; - } - // SERIAL_ECHOLN("Search Y2 span 1 - found"); - b = current_position[Y_AXIS]; - // Go to the center. - enable_z_endstop(false); - current_position[Y_AXIS] = 0.5f * (a + b); - go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); - found = true; + // Search in the Y direction along a cross. + found = false; + enable_z_endstop(false); + go_xy(current_position[X_AXIS], y0, feedrate); + enable_z_endstop(true); + go_xy(current_position[X_AXIS], y1, feedrate); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search Y2 span 0 - not found"); + continue; + } + // SERIAL_ECHOLN("Search Y2 span 0 - found"); + a = current_position[Y_AXIS]; + enable_z_endstop(false); + go_xy(current_position[X_AXIS], y1, feedrate); + enable_z_endstop(true); + go_xy(current_position[X_AXIS], y0, feedrate); + update_current_position_xyz(); + if (!endstop_z_hit_on_purpose()) { + // SERIAL_ECHOLN("Search Y2 span 1 - not found"); + continue; + } + // SERIAL_ECHOLN("Search Y2 span 1 - found"); + b = current_position[Y_AXIS]; + // Go to the center. + enable_z_endstop(false); + current_position[Y_AXIS] = 0.5f * (a + b); + go_xy(current_position[X_AXIS], current_position[Y_AXIS], feedrate); + found = true; #endif - break; - } - } + break; + } + } - enable_z_endstop(false); - return found; + enable_z_endstop(false); + return found; #endif //NEW_XYZCAL } @@ -1661,13 +1664,13 @@ inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t ver } b = current_position[X_AXIS]; if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { SERIAL_ECHOPGM("Point width too small: "); SERIAL_ECHO(b - a); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // We force the calibration routine to move the Z axis slightly down to make the response more pronounced. if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { // Don't use the new X value. @@ -1678,12 +1681,12 @@ inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t ver point_small = true; } } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Go to the center. enable_z_endstop(false); @@ -1736,13 +1739,13 @@ inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t ver b = current_position[Y_AXIS]; if (b - a < MIN_BED_SENSOR_POINT_RESPONSE_DMR) { // We force the calibration routine to move the Z axis slightly down to make the response more pronounced. - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 5) { +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 5) { SERIAL_ECHOPGM("Point height too small: "); SERIAL_ECHO(b - a); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY if (b - a < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { // Don't use the new Y value. current_position[Y_AXIS] = center_old_y; @@ -1752,12 +1755,12 @@ inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t ver point_small = true; } } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { debug_output_point(PSTR("top" ), current_position[X_AXIS], a, current_position[Z_AXIS]); debug_output_point(PSTR("bottom"), current_position[X_AXIS], b, current_position[Z_AXIS]); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Go to the center. enable_z_endstop(false); @@ -1787,14 +1790,14 @@ inline bool improve_bed_induction_sensor_point2(bool lift_z_on_min_y, int8_t ver #define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_RADIUS (8.f) #define IMPROVE_BED_INDUCTION_SENSOR_POINT3_SEARCH_STEP_FINE_Y (0.1f) inline bool improve_bed_induction_sensor_point3(int verbosity_level) -{ +{ float center_old_x = current_position[X_AXIS]; float center_old_y = current_position[Y_AXIS]; float a, b; bool result = true; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) MYSERIAL.println("Improve bed induction sensor point3"); - #endif // SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) MYSERIAL.println("Improve bed induction sensor point3"); +#endif // SUPPORT_VERBOSITY // Was the sensor point detected too far in the minus Y axis? // If yes, the center of the induction point cannot be reached by the machine. { @@ -1812,7 +1815,7 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) y0 = Y_MIN_POS_FOR_BED_CALIBRATION; if (y1 > Y_MAX_POS) y1 = Y_MAX_POS; - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 20) { SERIAL_ECHOPGM("Initial position: "); SERIAL_ECHO(center_old_x); @@ -1820,7 +1823,7 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) SERIAL_ECHO(center_old_y); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Search in the positive Y direction, until a maximum diameter is found. // (the next diameter is smaller than the current one.) @@ -1852,12 +1855,12 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) // goto canceled; } b = current_position[X_AXIS]; - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY float d = b - a; if (d > dmax) { xmax1 = 0.5f * (a + b); @@ -1868,11 +1871,11 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) } } if (dmax == 0.) { - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level > 0) SERIAL_PROTOCOLPGM("failed - not found\n"); - #endif // SUPPORT_VERBOSITY - current_position[X_AXIS] = center_old_x; +#endif // SUPPORT_VERBOSITY + current_position[X_AXIS] = center_old_x; current_position[Y_AXIS] = center_old_y; goto canceled; } @@ -1888,11 +1891,11 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) current_position[Y_AXIS] = center_old_y; goto canceled; } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); - #endif // SUPPORT_VERBOSITY - y1 = current_position[Y_AXIS]; +#endif // SUPPORT_VERBOSITY + y1 = current_position[Y_AXIS]; } if (y1 <= y0) { @@ -1934,12 +1937,12 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) */ } b = current_position[X_AXIS]; - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY float d = b - a; if (d > dmax) { xmax2 = 0.5f * (a + b); @@ -1987,12 +1990,12 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) */ } b = current_position[X_AXIS]; - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { debug_output_point(PSTR("left" ), a, current_position[Y_AXIS], current_position[Z_AXIS]); debug_output_point(PSTR("right"), b, current_position[Y_AXIS], current_position[Z_AXIS]); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY float d = b - a; if (d > dmax) { xmax = 0.5f * (a + b); @@ -2014,29 +2017,29 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) current_position[Y_AXIS] = center_old_y; goto canceled; } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) debug_output_point(PSTR("top" ), current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]); - #endif // SUPPORT_VERBOSITY - if (current_position[Y_AXIS] - Y_MIN_POS_FOR_BED_CALIBRATION < 0.5f * dmax) { +#endif // SUPPORT_VERBOSITY + if (current_position[Y_AXIS] - Y_MIN_POS_FOR_BED_CALIBRATION < 0.5f * dmax) { // Probably not even a half circle was detected. The induction point is likely too far in the minus Y direction. // First verify, if the measurement has been done at a sufficient height. If no, lower the Z axis a bit. if (current_position[Y_AXIS] < ymax || dmax < 0.5f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 5) { +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 5) { SERIAL_ECHOPGM("Partial point diameter too small: "); SERIAL_ECHO(dmax); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY result = false; } else { // Estimate the circle radius from the maximum diameter and height: float h = current_position[Y_AXIS] - ymax; float r = dmax * dmax / (8.f * h) + 0.5f * h; if (r < 0.8f * MIN_BED_SENSOR_POINT_RESPONSE_DMR) { - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 5) { +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 5) { SERIAL_ECHOPGM("Partial point estimated radius too small: "); SERIAL_ECHO(r); SERIAL_ECHOPGM(", dmax:"); @@ -2045,7 +2048,7 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) SERIAL_ECHO(h); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY result = false; } else { // The point may end up outside of the machine working space. @@ -2072,7 +2075,7 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) enable_z_endstop(false); current_position[X_AXIS] = xmax; current_position[Y_AXIS] = ymax; - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 20) { SERIAL_ECHOPGM("Adjusted position: "); SERIAL_ECHO(current_position[X_AXIS]); @@ -2080,7 +2083,7 @@ inline bool improve_bed_induction_sensor_point3(int verbosity_level) SERIAL_ECHO(current_position[Y_AXIS]); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Don't clamp current_position[Y_AXIS], because the out-of-reach Y coordinate may actually be true. // Only clamp the coordinate to go. @@ -2152,7 +2155,7 @@ inline void scan_bed_induction_sensor_point() #define MESH_BED_CALIBRATION_SHOW_LCD BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level, uint8_t &too_far_mask) -{ +{ // Don't let the manage_inactivity() function remove power from the motors. refresh_cmd_timeout(); @@ -2163,284 +2166,284 @@ BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level float *vec_y = vec_x + 2; float *cntr = vec_y + 2; memset(pts, 0, sizeof(float) * 7 * 7); - uint8_t iteration = 0; - BedSkewOffsetDetectionResultType result; + uint8_t iteration = 0; + BedSkewOffsetDetectionResultType result; // SERIAL_ECHOLNPGM("find_bed_offset_and_skew verbosity level: "); // SERIAL_ECHO(int(verbosity_level)); // SERIAL_ECHOPGM(""); - + #ifdef NEW_XYZCAL - { + { #else //NEW_XYZCAL - while (iteration < 3) { + while (iteration < 3) { #endif //NEW_XYZCAL - SERIAL_ECHOPGM("Iteration: "); - MYSERIAL.println(int(iteration + 1)); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM("Vectors: "); - - SERIAL_ECHOPGM("vec_x[0]:"); - MYSERIAL.print(vec_x[0], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("vec_x[1]:"); - MYSERIAL.print(vec_x[1], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("vec_y[0]:"); - MYSERIAL.print(vec_y[0], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("vec_y[1]:"); - MYSERIAL.print(vec_y[1], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("cntr[0]:"); - MYSERIAL.print(cntr[0], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("cntr[1]:"); - MYSERIAL.print(cntr[1], 5); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY + SERIAL_ECHOPGM("Iteration: "); + MYSERIAL.println(int(iteration + 1)); +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("Vectors: "); + + SERIAL_ECHOPGM("vec_x[0]:"); + MYSERIAL.print(vec_x[0], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("vec_x[1]:"); + MYSERIAL.print(vec_x[1], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("vec_y[0]:"); + MYSERIAL.print(vec_y[0], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("vec_y[1]:"); + MYSERIAL.print(vec_y[1], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("cntr[0]:"); + MYSERIAL.print(cntr[0], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("cntr[1]:"); + MYSERIAL.print(cntr[1], 5); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY #ifdef MESH_BED_CALIBRATION_SHOW_LCD - uint8_t next_line; - lcd_display_message_fullscreen_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1), next_line); - if (next_line > 3) - next_line = 3; + uint8_t next_line; + lcd_display_message_fullscreen_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE1), next_line); + if (next_line > 3) + next_line = 3; #endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - // Collect the rear 2x3 points. - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3; - for (int k = 0; k < 4; ++k) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); + // Collect the rear 2x3 points. + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3; + for (int k = 0; k < 4; ++k) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); #ifdef MESH_BED_CALIBRATION_SHOW_LCD - lcd_set_cursor(0, next_line); - lcd_print(k + 1); - lcd_puts_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2)); - - if (iteration > 0) { - lcd_puts_at_P(0, next_line + 1, _i("Iteration "));////MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION c=20 r=0 - lcd_print(int(iteration + 1)); - } + lcd_set_cursor(0, next_line); + lcd_print(k + 1); + lcd_puts_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2)); + + if (iteration > 0) { + lcd_puts_at_P(0, next_line + 1, _i("Iteration "));////MSG_FIND_BED_OFFSET_AND_SKEW_ITERATION c=20 r=0 + lcd_print(int(iteration + 1)); + } #endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - float *pt = pts + k * 2; - // Go up to z_initial. - - go_to_current(homing_feedrate[Z_AXIS] / 60.f); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - // Go to Y0, wait, then go to Y-4. - current_position[Y_AXIS] = 0.f; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - SERIAL_ECHOLNPGM("At Y0"); - delay_keep_alive(5000); - current_position[Y_AXIS] = Y_MIN_POS; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - SERIAL_ECHOLNPGM("At Y-4"); - delay_keep_alive(5000); - } - #endif // SUPPORT_VERBOSITY - // Go to the measurement point position. - //if (iteration == 0) { - current_position[X_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2 + 1); - /*} - else { - // if first iteration failed, count corrected point coordinates as initial - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - - current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[0] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[0]; - current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[1]; - - // The calibration points are very close to the min Y. - if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) - current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; - - }*/ - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOPGM("current_position[X_AXIS]:"); - MYSERIAL.print(current_position[X_AXIS], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("current_position[Y_AXIS]:"); - MYSERIAL.print(current_position[Y_AXIS], 5); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("current_position[Z_AXIS]:"); - MYSERIAL.print(current_position[Z_AXIS], 5); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY - - go_to_current(homing_feedrate[X_AXIS] / 60.f); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) - delay_keep_alive(3000); - #endif // SUPPORT_VERBOSITY - if (!find_bed_induction_sensor_point_xy(verbosity_level)) - return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; + float *pt = pts + k * 2; + // Go up to z_initial. + + go_to_current(homing_feedrate[Z_AXIS] / 60.f); +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + // Go to Y0, wait, then go to Y-4. + current_position[Y_AXIS] = 0.f; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + SERIAL_ECHOLNPGM("At Y0"); + delay_keep_alive(5000); + current_position[Y_AXIS] = Y_MIN_POS; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + SERIAL_ECHOLNPGM("At Y-4"); + delay_keep_alive(5000); + } +#endif // SUPPORT_VERBOSITY + // Go to the measurement point position. + //if (iteration == 0) { + current_position[X_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points_4 + k * 2 + 1); + /*} + else { + // if first iteration failed, count corrected point coordinates as initial + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + + current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[0] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[0]; + current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points_4 + k * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + k * 2 + 1) + cntr[1]; + + // The calibration points are very close to the min Y. + if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) + current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; + + }*/ +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("current_position[X_AXIS]:"); + MYSERIAL.print(current_position[X_AXIS], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("current_position[Y_AXIS]:"); + MYSERIAL.print(current_position[Y_AXIS], 5); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("current_position[Z_AXIS]:"); + MYSERIAL.print(current_position[Z_AXIS], 5); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY + + go_to_current(homing_feedrate[X_AXIS] / 60.f); +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) + delay_keep_alive(3000); +#endif // SUPPORT_VERBOSITY + if (!find_bed_induction_sensor_point_xy(verbosity_level)) + return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; #ifndef NEW_XYZCAL #ifndef HEATBED_V2 - - if (k == 0 || k == 1) { - // Improve the position of the 1st row sensor points by a zig-zag movement. - find_bed_induction_sensor_point_z(); - int8_t i = 4; - for (;;) { - if (improve_bed_induction_sensor_point3(verbosity_level)) - break; - if (--i == 0) - return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; - // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. - current_position[Z_AXIS] -= 0.025f; - enable_endstops(false); - enable_z_endstop(false); - go_to_current(homing_feedrate[Z_AXIS]); - } - if (i == 0) - // not found - return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; - } + + if (k == 0 || k == 1) { + // Improve the position of the 1st row sensor points by a zig-zag movement. + find_bed_induction_sensor_point_z(); + int8_t i = 4; + for (;;) { + if (improve_bed_induction_sensor_point3(verbosity_level)) + break; + if (--i == 0) + return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; + // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. + current_position[Z_AXIS] -= 0.025f; + enable_endstops(false); + enable_z_endstop(false); + go_to_current(homing_feedrate[Z_AXIS]); + } + if (i == 0) + // not found + return BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND; + } #endif //HEATBED_V2 #endif - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) - delay_keep_alive(3000); - #endif // SUPPORT_VERBOSITY - // Save the detected point position and then clamp the Y coordinate, which may have been estimated - // to lie outside the machine working space. - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM("Measured:"); - MYSERIAL.println(current_position[X_AXIS]); - MYSERIAL.println(current_position[Y_AXIS]); - } - #endif // SUPPORT_VERBOSITY - pt[0] = (pt[0] * iteration) / (iteration + 1); - pt[0] += (current_position[X_AXIS]/(iteration + 1)); //count average - pt[1] = (pt[1] * iteration) / (iteration + 1); - pt[1] += (current_position[Y_AXIS] / (iteration + 1)); - - - //pt[0] += current_position[X_AXIS]; - //if(iteration > 0) pt[0] = pt[0] / 2; - - //pt[1] += current_position[Y_AXIS]; - //if (iteration > 0) pt[1] = pt[1] / 2; - - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("pt[0]:"); - MYSERIAL.println(pt[0]); - SERIAL_ECHOPGM("pt[1]:"); - MYSERIAL.println(pt[1]); - } - #endif // SUPPORT_VERBOSITY - - if (current_position[Y_AXIS] < Y_MIN_POS) - current_position[Y_AXIS] = Y_MIN_POS; - // Start searching for the other points at 3mm above the last point. - current_position[Z_AXIS] += 3.f + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3; - //cntr[0] += pt[0]; - //cntr[1] += pt[1]; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10 && k == 0) { - // Show the zero. Test, whether the Y motor skipped steps. - current_position[Y_AXIS] = MANUAL_Y_HOME_POS; - go_to_current(homing_feedrate[X_AXIS] / 60.f); - delay_keep_alive(3000); - } - #endif // SUPPORT_VERBOSITY - } - delay_keep_alive(0); //manage_heater, reset watchdog, manage inactivity - - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. - delay_keep_alive(3000); - for (int8_t mesh_point = 0; mesh_point < 4; ++mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = pts[mesh_point * 2]; - current_position[Y_AXIS] = pts[mesh_point * 2 + 1]; - go_to_current(homing_feedrate[X_AXIS] / 60); - delay_keep_alive(3000); - } - } - #endif // SUPPORT_VERBOSITY - if (pts[1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { - too_far_mask |= 1 << 1; //front center point is out of reach - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("WARNING: Front point not reachable. Y coordinate:"); - MYSERIAL.print(pts[1]); - SERIAL_ECHOPGM(" < "); - MYSERIAL.println(Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); - } - result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level); - delay_keep_alive(0); //manage_heater, reset watchdog, manage inactivity - - if (result >= 0) { - world2machine_update(vec_x, vec_y, cntr); +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) + delay_keep_alive(3000); +#endif // SUPPORT_VERBOSITY + // Save the detected point position and then clamp the Y coordinate, which may have been estimated + // to lie outside the machine working space. +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM("Measured:"); + MYSERIAL.println(current_position[X_AXIS]); + MYSERIAL.println(current_position[Y_AXIS]); + } +#endif // SUPPORT_VERBOSITY + pt[0] = (pt[0] * iteration) / (iteration + 1); + pt[0] += (current_position[X_AXIS]/(iteration + 1)); //count average + pt[1] = (pt[1] * iteration) / (iteration + 1); + pt[1] += (current_position[Y_AXIS] / (iteration + 1)); + + + //pt[0] += current_position[X_AXIS]; + //if(iteration > 0) pt[0] = pt[0] / 2; + + //pt[1] += current_position[Y_AXIS]; + //if (iteration > 0) pt[1] = pt[1] / 2; + +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("pt[0]:"); + MYSERIAL.println(pt[0]); + SERIAL_ECHOPGM("pt[1]:"); + MYSERIAL.println(pt[1]); + } +#endif // SUPPORT_VERBOSITY + + if (current_position[Y_AXIS] < Y_MIN_POS) + current_position[Y_AXIS] = Y_MIN_POS; + // Start searching for the other points at 3mm above the last point. + current_position[Z_AXIS] += 3.f + FIND_BED_INDUCTION_SENSOR_POINT_Z_STEP * iteration * 0.3; + //cntr[0] += pt[0]; + //cntr[1] += pt[1]; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10 && k == 0) { + // Show the zero. Test, whether the Y motor skipped steps. + current_position[Y_AXIS] = MANUAL_Y_HOME_POS; + go_to_current(homing_feedrate[X_AXIS] / 60.f); + delay_keep_alive(3000); + } +#endif // SUPPORT_VERBOSITY + } + delay_keep_alive(0); //manage_heater, reset watchdog, manage inactivity + +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. + delay_keep_alive(3000); + for (int8_t mesh_point = 0; mesh_point < 4; ++mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = pts[mesh_point * 2]; + current_position[Y_AXIS] = pts[mesh_point * 2 + 1]; + go_to_current(homing_feedrate[X_AXIS] / 60); + delay_keep_alive(3000); + } + } +#endif // SUPPORT_VERBOSITY + if (pts[1] < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) { + too_far_mask |= 1 << 1; //front center point is out of reach + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("WARNING: Front point not reachable. Y coordinate:"); + MYSERIAL.print(pts[1]); + SERIAL_ECHOPGM(" < "); + MYSERIAL.println(Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + } + result = calculate_machine_skew_and_offset_LS(pts, 4, bed_ref_points_4, vec_x, vec_y, cntr, verbosity_level); + delay_keep_alive(0); //manage_heater, reset watchdog, manage inactivity + + if (result >= 0) { + world2machine_update(vec_x, vec_y, cntr); #if 1 - // Fearlessly store the calibration values into the eeprom. - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0), cntr[0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4), cntr[1]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0), vec_x[0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4), vec_x[1]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0), vec_y[0]); - eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4), vec_y[1]); + // Fearlessly store the calibration values into the eeprom. + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0), cntr[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4), cntr[1]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0), vec_x[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4), vec_x[1]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0), vec_y[0]); + eeprom_update_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4), vec_y[1]); #endif - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) { - // Length of the vec_x - float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]); - SERIAL_ECHOLNPGM("X vector length:"); - MYSERIAL.println(l); - - // Length of the vec_y - l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]); - SERIAL_ECHOLNPGM("Y vector length:"); - MYSERIAL.println(l); - // Zero point correction - l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]); - SERIAL_ECHOLNPGM("Zero point correction:"); - MYSERIAL.println(l); - - // vec_x and vec_y shall be nearly perpendicular. - l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1]; - SERIAL_ECHOLNPGM("Perpendicularity"); - MYSERIAL.println(fabs(l)); - SERIAL_ECHOLNPGM("Saving bed calibration vectors to EEPROM"); - } - #endif // SUPPORT_VERBOSITY - // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set. - world2machine_update_current(); - - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. - delay_keep_alive(3000); - for (int8_t mesh_point = 0; mesh_point < 9; ++mesh_point) { - // Don't let the manage_inactivity() function remove power from the motors. - refresh_cmd_timeout(); - // Go to the measurement point. - // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). - current_position[X_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2); - current_position[Y_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2 + 1); - go_to_current(homing_feedrate[X_AXIS] / 60); - delay_keep_alive(3000); - } - } - #endif // SUPPORT_VERBOSITY - return result; - } - if (result == BED_SKEW_OFFSET_DETECTION_FITTING_FAILED && too_far_mask == 2) return result; //if fitting failed and front center point is out of reach, terminate calibration and inform user - iteration++; - } - return result; +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) { + // Length of the vec_x + float l = sqrt(vec_x[0] * vec_x[0] + vec_x[1] * vec_x[1]); + SERIAL_ECHOLNPGM("X vector length:"); + MYSERIAL.println(l); + + // Length of the vec_y + l = sqrt(vec_y[0] * vec_y[0] + vec_y[1] * vec_y[1]); + SERIAL_ECHOLNPGM("Y vector length:"); + MYSERIAL.println(l); + // Zero point correction + l = sqrt(cntr[0] * cntr[0] + cntr[1] * cntr[1]); + SERIAL_ECHOLNPGM("Zero point correction:"); + MYSERIAL.println(l); + + // vec_x and vec_y shall be nearly perpendicular. + l = vec_x[0] * vec_y[0] + vec_x[1] * vec_y[1]; + SERIAL_ECHOLNPGM("Perpendicularity"); + MYSERIAL.println(fabs(l)); + SERIAL_ECHOLNPGM("Saving bed calibration vectors to EEPROM"); + } +#endif // SUPPORT_VERBOSITY + // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set. + world2machine_update_current(); + +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. + delay_keep_alive(3000); + for (int8_t mesh_point = 0; mesh_point < 9; ++mesh_point) { + // Don't let the manage_inactivity() function remove power from the motors. + refresh_cmd_timeout(); + // Go to the measurement point. + // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). + current_position[X_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2); + current_position[Y_AXIS] = pgm_read_float(bed_ref_points + mesh_point * 2 + 1); + go_to_current(homing_feedrate[X_AXIS] / 60); + delay_keep_alive(3000); + } + } +#endif // SUPPORT_VERBOSITY + return result; + } + if (result == BED_SKEW_OFFSET_DETECTION_FITTING_FAILED && too_far_mask == 2) return result; //if fitting failed and front center point is out of reach, terminate calibration and inform user + iteration++; + } + return result; } #ifndef NEW_XYZCAL @@ -2459,9 +2462,9 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 float *vec_y = vec_x + 2; float *cntr = vec_y + 2; memset(pts, 0, sizeof(float) * 7 * 7); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) SERIAL_ECHOLNPGM("Improving bed offset and skew"); - #endif // SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) SERIAL_ECHOLNPGM("Improving bed offset and skew"); +#endif // SUPPORT_VERBOSITY // Cache the current correction matrix. world2machine_initialize(); vec_x[0] = world2machine_rotation_and_skew[0][0]; @@ -2491,7 +2494,7 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 // Print the decrasing ID of the measurement point. #ifdef MESH_BED_CALIBRATION_SHOW_LCD lcd_set_cursor(0, next_line); - lcd_print(mesh_point+1); + lcd_print(mesh_point+1); lcd_puts_P(_T(MSG_FIND_BED_OFFSET_AND_SKEW_LINE2));////MSG_IMPROVE_BED_OFFSET_AND_SKEW_LINE2 c=14 r=0 #endif /* MESH_BED_CALIBRATION_SHOW_LCD */ @@ -2500,7 +2503,7 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 enable_endstops(false); enable_z_endstop(false); go_to_current(homing_feedrate[Z_AXIS]/60); - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 20) { // Go to Y0, wait, then go to Y-4. current_position[Y_AXIS] = 0.f; @@ -2509,43 +2512,43 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 delay_keep_alive(5000); current_position[Y_AXIS] = Y_MIN_POS; go_to_current(homing_feedrate[X_AXIS] / 60.f); - SERIAL_ECHOLNPGM("At Y_MIN_POS"); + SERIAL_ECHOLNPGM("At Y_MIN_POS"); delay_keep_alive(5000); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY // Go to the measurement point. // Use the coorrected coordinate, which is a result of find_bed_offset_and_skew(). current_position[X_AXIS] = vec_x[0] * pgm_read_float(bed_ref_points_4+mesh_point*2) + vec_y[0] * pgm_read_float(bed_ref_points_4+mesh_point*2+1) + cntr[0]; current_position[Y_AXIS] = vec_x[1] * pgm_read_float(bed_ref_points_4+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points_4+mesh_point*2+1) + cntr[1]; // The calibration points are very close to the min Y. - if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION){ + if (current_position[Y_AXIS] < Y_MIN_POS_FOR_BED_CALIBRATION) { current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOPGM("Calibration point "); - SERIAL_ECHO(mesh_point); - SERIAL_ECHOPGM("lower than Ymin. Y coordinate clamping was used."); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY - } +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOPGM("Calibration point "); + SERIAL_ECHO(mesh_point); + SERIAL_ECHOPGM("lower than Ymin. Y coordinate clamping was used."); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY + } go_to_current(homing_feedrate[X_AXIS]/60); // Find its Z position by running the normal vertical search. - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) delay_keep_alive(3000); - #endif // SUPPORT_VERBOSITY - find_bed_induction_sensor_point_z(); - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 10) +#endif // SUPPORT_VERBOSITY + find_bed_induction_sensor_point_z(); +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 10) delay_keep_alive(3000); - #endif // SUPPORT_VERBOSITY - // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. +#endif // SUPPORT_VERBOSITY + // Try to move the Z axis down a bit to increase a chance of the sensor to trigger. current_position[Z_AXIS] -= 0.025f; // Improve the point position by searching its center in a current plane. int8_t n_errors = 3; for (int8_t iter = 0; iter < 8; ) { - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level > 20) { SERIAL_ECHOPGM("Improving bed point "); SERIAL_ECHO(mesh_point); @@ -2555,7 +2558,7 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 MYSERIAL.print(current_position[Z_AXIS], 5); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY bool found = false; if (mesh_point < 2) { // Because the sensor cannot move in front of the first row @@ -2565,9 +2568,14 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 found = improve_bed_induction_sensor_point3(verbosity_level); } else { switch (method) { - case 0: found = improve_bed_induction_sensor_point(); break; - case 1: found = improve_bed_induction_sensor_point2(mesh_point < 2, verbosity_level); break; - default: break; + case 0: + found = improve_bed_induction_sensor_point(); + break; + case 1: + found = improve_bed_induction_sensor_point2(mesh_point < 2, verbosity_level); + break; + default: + break; } } if (found) { @@ -2589,7 +2597,7 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 enable_endstops(false); enable_z_endstop(false); go_to_current(homing_feedrate[Z_AXIS]); - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { SERIAL_ECHOPGM("Improving bed point "); SERIAL_ECHO(mesh_point); @@ -2599,13 +2607,13 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 MYSERIAL.print(current_position[Z_AXIS], 5); SERIAL_ECHOLNPGM(""); } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY } } - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 10) delay_keep_alive(3000); - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY } // Don't let the manage_inactivity() function remove power from the motors. refresh_cmd_timeout(); @@ -2617,10 +2625,10 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 enable_endstops(false); enable_z_endstop(false); - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { // Test the positions. Are the positions reproducible? - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; for (int8_t mesh_point = 0; mesh_point < 4; ++ mesh_point) { // Don't let the manage_inactivity() function remove power from the motors. refresh_cmd_timeout(); @@ -2641,7 +2649,7 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 SERIAL_ECHOLNPGM(""); } } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY { // First fill in the too_far_mask from the measured points. @@ -2656,18 +2664,18 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 // In case of success, update the too_far_mask from the calculated points. for (uint8_t mesh_point = 0; mesh_point < 2; ++ mesh_point) { float y = vec_x[1] * pgm_read_float(bed_ref_points_4+mesh_point*2) + vec_y[1] * pgm_read_float(bed_ref_points_4+mesh_point*2+1) + cntr[1]; - #ifdef SUPPORT_VERBOSITY - if (verbosity_level >= 20) { - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("Distance from min:"); - MYSERIAL.print(y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); - SERIAL_ECHOLNPGM(""); - SERIAL_ECHOPGM("y:"); - MYSERIAL.print(y); - SERIAL_ECHOLNPGM(""); - } - #endif // SUPPORT_VERBOSITY - if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) +#ifdef SUPPORT_VERBOSITY + if (verbosity_level >= 20) { + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("Distance from min:"); + MYSERIAL.print(y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + SERIAL_ECHOLNPGM(""); + SERIAL_ECHOPGM("y:"); + MYSERIAL.print(y); + SERIAL_ECHOLNPGM(""); + } +#endif // SUPPORT_VERBOSITY + if (y < Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH) too_far_mask |= 1 << mesh_point; } } @@ -2684,15 +2692,15 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 #endif // Correct the current_position to match the transformed coordinate system after world2machine_rotation_and_skew and world2machine_shift were set. - world2machine_update_current(); + world2machine_update_current(); enable_endstops(false); enable_z_endstop(false); - #ifdef SUPPORT_VERBOSITY +#ifdef SUPPORT_VERBOSITY if (verbosity_level >= 5) { // Test the positions. Are the positions reproducible? Now the calibration is active in the planner. delay_keep_alive(3000); - current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; + current_position[Z_AXIS] = MESH_HOME_Z_SEARCH; for (int8_t mesh_point = 0; mesh_point < 4; ++ mesh_point) { // Don't let the manage_inactivity() function remove power from the motors. refresh_cmd_timeout(); @@ -2717,9 +2725,9 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 } } } - #endif // SUPPORT_VERBOSITY +#endif // SUPPORT_VERBOSITY - if(!sample_z()) + if(!sample_z()) goto canceled; enable_endstops(endstops_enabled); @@ -2743,19 +2751,19 @@ BedSkewOffsetDetectionResultType improve_bed_offset_and_skew(int8_t method, int8 #endif //NEW_XYZCAL bool sample_z() { - bool sampled = true; - //make space - current_position[Z_AXIS] += 150; - go_to_current(homing_feedrate[Z_AXIS] / 60); - //plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder);); + bool sampled = true; + //make space + current_position[Z_AXIS] += 150; + go_to_current(homing_feedrate[Z_AXIS] / 60); + //plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder);); - lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET)); + lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET)); - // Sample Z heights for the mesh bed leveling. - // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process. - if (!sample_mesh_and_store_reference()) sampled = false; + // Sample Z heights for the mesh bed leveling. + // In addition, store the results into an eeprom, to be used later for verification of the bed leveling process. + if (!sample_mesh_and_store_reference()) sampled = false; - return sampled; + return sampled; } void go_home_with_z_lift() @@ -2774,7 +2782,7 @@ void go_home_with_z_lift() go_to_current(homing_feedrate[X_AXIS]/60); // Third move up to a safe height. current_position[Z_AXIS] = Z_MIN_POS; - go_to_current(homing_feedrate[Z_AXIS]/60); + go_to_current(homing_feedrate[Z_AXIS]/60); } // Sample the 9 points of the bed and store them into the EEPROM as a reference. @@ -2795,7 +2803,7 @@ bool sample_mesh_and_store_reference() if (next_line > 3) next_line = 3; // display "point xx of yy" - lcd_set_cursor(0, next_line); + lcd_set_cursor(0, next_line); lcd_print(1); lcd_puts_P(_T(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2)); #endif /* MESH_BED_CALIBRATION_SHOW_LCD */ @@ -2815,19 +2823,19 @@ bool sample_mesh_and_store_reference() homeaxis(Z_AXIS); #ifdef TMC2130 - if (!axis_known_position[Z_AXIS] && (READ(Z_TMC2130_DIAG) != 0)) //Z crash - { - kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); - return false; - } + if (!axis_known_position[Z_AXIS] && (READ(Z_TMC2130_DIAG) != 0)) //Z crash + { + kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); + return false; + } #endif //TMC2130 enable_endstops(false); - if (!find_bed_induction_sensor_point_z()) //Z crash or deviation > 50um - { - kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); - return false; - } + if (!find_bed_induction_sensor_point_z()) //Z crash or deviation > 50um + { + kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); + return false; + } mbl.set_z(0, 0, current_position[Z_AXIS]); } for (int8_t mesh_point = 1; mesh_point != MESH_MEAS_NUM_X_POINTS * MESH_MEAS_NUM_Y_POINTS; ++ mesh_point) { @@ -2842,15 +2850,15 @@ bool sample_mesh_and_store_reference() go_to_current(homing_feedrate[X_AXIS]/60); #ifdef MESH_BED_CALIBRATION_SHOW_LCD // display "point xx of yy" - lcd_set_cursor(0, next_line); + lcd_set_cursor(0, next_line); lcd_print(mesh_point+1); lcd_puts_P(_T(MSG_MEASURE_BED_REFERENCE_HEIGHT_LINE2)); #endif /* MESH_BED_CALIBRATION_SHOW_LCD */ - if (!find_bed_induction_sensor_point_z()) //Z crash or deviation > 50um - { - kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); - return false; - } + if (!find_bed_induction_sensor_point_z()) //Z crash or deviation > 50um + { + kill(_T(MSG_BED_LEVELING_FAILED_POINT_LOW)); + return false; + } // Get cords of measuring point int8_t ix = mesh_point % MESH_MEAS_NUM_X_POINTS; int8_t iy = mesh_point / MESH_MEAS_NUM_X_POINTS; @@ -2862,10 +2870,10 @@ bool sample_mesh_and_store_reference() float zmin = mbl.z_values[0][0]; float zmax = zmin; for (int8_t j = 0; j < 3; ++ j) - for (int8_t i = 0; i < 3; ++ i) { + for (int8_t i = 0; i < 3; ++ i) { zmin = min(zmin, mbl.z_values[j][i]); zmax = max(zmax, mbl.z_values[j][i]); - } + } if (zmax - zmin > 3.f) { // The span of the Z offsets is extreme. Give up. // Homing failed on some of the points. @@ -2886,7 +2894,7 @@ bool sample_mesh_and_store_reference() float dif = mbl.z_values[j][i] - mbl.z_values[0][0]; int16_t dif_quantized = int16_t(floor(dif * 100.f + 0.5f)); eeprom_update_word((uint16_t*)addr, *reinterpret_cast(&dif_quantized)); - #if 0 +#if 0 { uint16_t z_offset_u = eeprom_read_word((uint16_t*)addr); float dif2 = *reinterpret_cast(&z_offset_u) * 0.01; @@ -2901,7 +2909,7 @@ bool sample_mesh_and_store_reference() MYSERIAL.print(dif2, 5); SERIAL_ECHOLNPGM(""); } - #endif +#endif addr += 2; } } @@ -2963,7 +2971,7 @@ bool scan_bed_induction_points(int8_t verbosity_level) current_position[Y_AXIS] = Y_MIN_POS_FOR_BED_CALIBRATION; go_to_current(homing_feedrate[X_AXIS]/60); find_bed_induction_sensor_point_z(); - scan_bed_induction_sensor_point(); + scan_bed_induction_sensor_point(); } // Don't let the manage_inactivity() function remove power from the motors. refresh_cmd_timeout(); @@ -2996,16 +3004,16 @@ static int babystepLoadZ = 0; void babystep_load() { - babystepLoadZ = 0; + babystepLoadZ = 0; // Apply Z height correction aka baby stepping before mesh bed leveling gets activated. if (calibration_status() < CALIBRATION_STATUS_LIVE_ADJUST) { check_babystep(); //checking if babystep is in allowed range, otherwise setting babystep to 0 - + // End of G80: Apply the baby stepping value. EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystepLoadZ); - - #if 0 + +#if 0 SERIAL_ECHO("Z baby step: "); SERIAL_ECHO(babystepLoadZ); SERIAL_ECHO(", current Z: "); @@ -3013,7 +3021,7 @@ void babystep_load() SERIAL_ECHO("correction: "); SERIAL_ECHO(float(babystepLoadZ) / float(axis_steps_per_unit[Z_AXIS])); SERIAL_ECHOLN(""); - #endif +#endif } } @@ -3030,39 +3038,39 @@ void babystep_apply() void babystep_undo() { #ifdef BABYSTEP_LOADZ_BY_PLANNER - shift_z(float(babystepLoadZ) / float(cs.axis_steps_per_unit[Z_AXIS])); + shift_z(float(babystepLoadZ) / float(cs.axis_steps_per_unit[Z_AXIS])); #else - babystepsTodoZsubtract(babystepLoadZ); + babystepsTodoZsubtract(babystepLoadZ); #endif /* BABYSTEP_LOADZ_BY_PLANNER */ - babystepLoadZ = 0; + babystepLoadZ = 0; } void babystep_reset() { - babystepLoadZ = 0; + babystepLoadZ = 0; } void count_xyz_details(float (&distanceMin)[2]) { - float cntr[2] = { - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0)), - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4)) - }; - float vec_x[2] = { - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0)), - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4)) - }; - float vec_y[2] = { - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0)), - eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4)) - }; + float cntr[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_CENTER + 4)) + }; + float vec_x[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_X + 4)) + }; + float vec_y[2] = { + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 0)), + eeprom_read_float((float*)(EEPROM_BED_CALIBRATION_VEC_Y + 4)) + }; #if 0 - a2 = -1 * asin(vec_y[0] / MACHINE_AXIS_SCALE_Y); - a1 = asin(vec_x[1] / MACHINE_AXIS_SCALE_X); - angleDiff = fabs(a2 - a1); + a2 = -1 * asin(vec_y[0] / MACHINE_AXIS_SCALE_Y); + a1 = asin(vec_x[1] / MACHINE_AXIS_SCALE_X); + angleDiff = fabs(a2 - a1); #endif - for (uint8_t mesh_point = 0; mesh_point < 2; ++mesh_point) { - float y = vec_x[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2 + 1) + cntr[1]; - distanceMin[mesh_point] = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); - } + for (uint8_t mesh_point = 0; mesh_point < 2; ++mesh_point) { + float y = vec_x[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2) + vec_y[1] * pgm_read_float(bed_ref_points_4 + mesh_point * 2 + 1) + cntr[1]; + distanceMin[mesh_point] = (y - Y_MIN_POS_CALIBRATION_POINT_OUT_OF_REACH); + } } diff --git a/Firmware/mesh_bed_calibration.h b/Firmware/mesh_bed_calibration.h index d928f1d11c..60905bf9f0 100755 --- a/Firmware/mesh_bed_calibration.h +++ b/Firmware/mesh_bed_calibration.h @@ -13,9 +13,9 @@ extern const float bed_skew_angle_extreme; // Is the world2machine correction activated? enum World2MachineCorrectionMode { - WORLD2MACHINE_CORRECTION_NONE = 0, - WORLD2MACHINE_CORRECTION_SHIFT = 1, - WORLD2MACHINE_CORRECTION_SKEW = 2, + WORLD2MACHINE_CORRECTION_NONE = 0, + WORLD2MACHINE_CORRECTION_SHIFT = 1, + WORLD2MACHINE_CORRECTION_SKEW = 2, }; extern uint8_t world2machine_correction_mode; // 2x2 transformation matrix from the world coordinates to the machine coordinates. @@ -34,22 +34,22 @@ extern void world2machine_update_current(); inline void world2machine(float &x, float &y) { - if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { - // No correction. - } else { - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { - // Firs the skew & rotation correction. - float out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y; - float out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y; - x = out_x; - y = out_y; - } - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { - // Then add the offset. - x += world2machine_shift[0]; - y += world2machine_shift[1]; - } - } + if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { + // No correction. + } else { + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { + // Firs the skew & rotation correction. + float out_x = world2machine_rotation_and_skew[0][0] * x + world2machine_rotation_and_skew[0][1] * y; + float out_y = world2machine_rotation_and_skew[1][0] * x + world2machine_rotation_and_skew[1][1] * y; + x = out_x; + y = out_y; + } + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { + // Then add the offset. + x += world2machine_shift[0]; + y += world2machine_shift[1]; + } + } } inline void world2machine(const float &x, const float &y, float &out_x, float &out_y) @@ -61,48 +61,48 @@ inline void world2machine(const float &x, const float &y, float &out_x, float &o inline void machine2world(float x, float y, float &out_x, float &out_y) { - if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { - // No correction. - out_x = x; - out_y = y; - } else { - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { - // Then add the offset. - x -= world2machine_shift[0]; - y -= world2machine_shift[1]; - } - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { - // Firs the skew & rotation correction. - out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; - out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; - } - } + if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { + // No correction. + out_x = x; + out_y = y; + } else { + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { + // Then add the offset. + x -= world2machine_shift[0]; + y -= world2machine_shift[1]; + } + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { + // Firs the skew & rotation correction. + out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; + out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; + } + } } inline void machine2world(float &x, float &y) { - if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { - // No correction. - } else { - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { - // Then add the offset. - x -= world2machine_shift[0]; - y -= world2machine_shift[1]; - } - if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { - // Firs the skew & rotation correction. - float out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; - float out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; - x = out_x; - y = out_y; - } - } + if (world2machine_correction_mode == WORLD2MACHINE_CORRECTION_NONE) { + // No correction. + } else { + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SHIFT) { + // Then add the offset. + x -= world2machine_shift[0]; + y -= world2machine_shift[1]; + } + if (world2machine_correction_mode & WORLD2MACHINE_CORRECTION_SKEW) { + // Firs the skew & rotation correction. + float out_x = world2machine_rotation_and_skew_inv[0][0] * x + world2machine_rotation_and_skew_inv[0][1] * y; + float out_y = world2machine_rotation_and_skew_inv[1][0] * x + world2machine_rotation_and_skew_inv[1][1] * y; + x = out_x; + y = out_y; + } + } } inline bool world2machine_clamp(float &x, float &y) { - bool clamped = false; - float tmpx, tmpy; + bool clamped = false; + float tmpx, tmpy; world2machine(x, y, tmpx, tmpy); if (tmpx < X_MIN_POS) { tmpx = X_MIN_POS; @@ -137,14 +137,14 @@ extern void go_home_with_z_lift(); */ enum BedSkewOffsetDetectionResultType { - // Detection failed, some point was not found. - BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND = -1, //!< Point not found. - BED_SKEW_OFFSET_DETECTION_FITTING_FAILED = -2, //!< Fitting failed - - // Detection finished with success. - BED_SKEW_OFFSET_DETECTION_PERFECT = 0, //!< Perfect. - BED_SKEW_OFFSET_DETECTION_SKEW_MILD = 1, //!< Mildly skewed. - BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME = 2 //!< Extremely skewed. + // Detection failed, some point was not found. + BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND = -1, //!< Point not found. + BED_SKEW_OFFSET_DETECTION_FITTING_FAILED = -2, //!< Fitting failed + + // Detection finished with success. + BED_SKEW_OFFSET_DETECTION_PERFECT = 0, //!< Perfect. + BED_SKEW_OFFSET_DETECTION_SKEW_MILD = 1, //!< Mildly skewed. + BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME = 2 //!< Extremely skewed. }; extern BedSkewOffsetDetectionResultType find_bed_offset_and_skew(int8_t verbosity_level, uint8_t &too_far_mask); @@ -162,7 +162,7 @@ extern bool is_bed_z_jitter_data_valid(); // Useful for visualizing the behavior of the bed induction detector. extern bool scan_bed_induction_points(int8_t verbosity_level); -// Load Z babystep value from the EEPROM into babystepLoadZ, +// Load Z babystep value from the EEPROM into babystepLoadZ, // but don't apply it through the planner. This is useful on wake up // after power panic, when it is expected, that the baby step has been already applied. extern void babystep_load(); diff --git a/Firmware/mesh_bed_leveling.cpp b/Firmware/mesh_bed_leveling.cpp index 746458aeaa..6e1bc195cd 100755 --- a/Firmware/mesh_bed_leveling.cpp +++ b/Firmware/mesh_bed_leveling.cpp @@ -6,7 +6,9 @@ mesh_bed_leveling mbl; -mesh_bed_leveling::mesh_bed_leveling() { reset(); } +mesh_bed_leveling::mesh_bed_leveling() { + reset(); +} void mesh_bed_leveling::reset() { active = 0; @@ -116,16 +118,16 @@ void mesh_bed_leveling::upsample_3x3() if (i == idx1) continue; float x = get_x(i); - #ifdef MBL_BILINEAR +#ifdef MBL_BILINEAR z_values[j][i] = (x < x1) ? - ((z_values[j][idx0] * (x - x0) + z_values[j][idx1] * (x1 - x)) / (x1 - x0)) : - ((z_values[j][idx1] * (x - x1) + z_values[j][idx2] * (x2 - x)) / (x2 - x1)); - #else - z_values[j][i] = + ((z_values[j][idx0] * (x - x0) + z_values[j][idx1] * (x1 - x)) / (x1 - x0)) : + ((z_values[j][idx1] * (x - x1) + z_values[j][idx2] * (x2 - x)) / (x2 - x1)); +#else + z_values[j][i] = z_values[j][idx0] * (x - x1) * (x - x2) / ((x0 - x1) * (x0 - x2)) + z_values[j][idx1] * (x - x0) * (x - x2) / ((x1 - x0) * (x1 - x2)) + z_values[j][idx2] * (x - x0) * (x - x1) / ((x2 - x0) * (x2 - x1)); - #endif +#endif } } } @@ -143,36 +145,36 @@ void mesh_bed_leveling::upsample_3x3() if (j == idx1) continue; float y = get_y(j); - #ifdef MBL_BILINEAR - z_values[j][i] = (y < y1) ? - ((z_values[idx0][i] * (y - y0) + z_values[idx1][i] * (y1 - y)) / (y1 - y0)) : - ((z_values[idx1][i] * (y - y1) + z_values[idx2][i] * (y2 - y)) / (y2 - y1)); - #else - z_values[j][i] = +#ifdef MBL_BILINEAR + z_values[j][i] = (y < y1) ? + ((z_values[idx0][i] * (y - y0) + z_values[idx1][i] * (y1 - y)) / (y1 - y0)) : + ((z_values[idx1][i] * (y - y1) + z_values[idx2][i] * (y2 - y)) / (y2 - y1)); +#else + z_values[j][i] = z_values[idx0][i] * (y - y1) * (y - y2) / ((y0 - y1) * (y0 - y2)) + z_values[idx1][i] * (y - y0) * (y - y2) / ((y1 - y0) * (y1 - y2)) + z_values[idx2][i] * (y - y0) * (y - y1) / ((y2 - y0) * (y2 - y1)); - #endif +#endif } } } -/* - // Relax the non-measured points. - const float weight = 0.2f; - for (uint8_t iter = 0; iter < 20; ++ iter) { - for (int8_t j = 1; j < 6; ++ j) { - for (int8_t i = 1; i < 6; ++ i) { - if (i == 3 || j == 3) - continue; - if ((i % 3) == 0 && (j % 3) == 0) - continue; - float avg = 0.25f * (z_values[j][i-1]+z_values[j][i+1]+z_values[j-1][i]+z_values[j+1][i]); - z_values[j][i] = (1.f-weight)*z_values[j][i] + weight*avg; + /* + // Relax the non-measured points. + const float weight = 0.2f; + for (uint8_t iter = 0; iter < 20; ++ iter) { + for (int8_t j = 1; j < 6; ++ j) { + for (int8_t i = 1; i < 6; ++ i) { + if (i == 3 || j == 3) + continue; + if ((i % 3) == 0 && (j % 3) == 0) + continue; + float avg = 0.25f * (z_values[j][i-1]+z_values[j][i+1]+z_values[j-1][i]+z_values[j+1][i]); + z_values[j][i] = (1.f-weight)*z_values[j][i] + weight*avg; + } } } - } -*/ + */ } #endif diff --git a/Firmware/mesh_bed_leveling.h b/Firmware/mesh_bed_leveling.h index bf3729558b..eed88589b7 100755 --- a/Firmware/mesh_bed_leveling.h +++ b/Firmware/mesh_bed_leveling.h @@ -12,41 +12,47 @@ class mesh_bed_leveling { public: uint8_t active; float z_values[MESH_NUM_Y_POINTS][MESH_NUM_X_POINTS]; - + mesh_bed_leveling(); - + void reset(); - + #if MESH_NUM_X_POINTS>=5 && MESH_NUM_Y_POINTS>=5 && (MESH_NUM_X_POINTS&1)==1 && (MESH_NUM_Y_POINTS&1)==1 void upsample_3x3(); #endif - - static float get_x(int i) { return float(MESH_MIN_X) + float(MESH_X_DIST) * float(i); } - static float get_y(int i) { return float(MESH_MIN_Y) + float(MESH_Y_DIST) * float(i); } - + + static float get_x(int i) { + return float(MESH_MIN_X) + float(MESH_X_DIST) * float(i); + } + static float get_y(int i) { + return float(MESH_MIN_Y) + float(MESH_Y_DIST) * float(i); + } + // Measurement point for the Z probe. // If use_default=true, then the default positions for a correctly built printer are used. // Otherwise a correction matrix is pulled from the EEPROM if available. static void get_meas_xy(int ix, int iy, float &x, float &y, bool use_default); - - void set_z(int ix, int iy, float z) { z_values[iy][ix] = z; } - + + void set_z(int ix, int iy, float z) { + z_values[iy][ix] = z; + } + int select_x_index(float x) { int i = 1; while (x > get_x(i) && i < MESH_NUM_X_POINTS - 1) i++; return i - 1; } - + int select_y_index(float y) { int i = 1; while (y > get_y(i) && i < MESH_NUM_Y_POINTS - 1) i++; return i - 1; } - + float get_z(float x, float y) { int i, j; float s, t; - + #if MESH_NUM_X_POINTS==3 && MESH_NUM_Y_POINTS==3 #define MESH_MID_X (0.5f*(MESH_MIN_X+MESH_MAX_X)) #define MESH_MID_Y (0.5f*(MESH_MIN_Y+MESH_MAX_Y)) @@ -111,13 +117,13 @@ class mesh_bed_leveling { t = 1.f; } #endif /* MESH_NUM_X_POINTS==3 && MESH_NUM_Y_POINTS==3 */ - + float si = 1.f-s; float z0 = si * z_values[j ][i] + s * z_values[j ][i+1]; float z1 = si * z_values[j+1][i] + s * z_values[j+1][i+1]; return (1.f-t) * z0 + t * z1; } - + }; extern mesh_bed_leveling mbl; diff --git a/Firmware/mmu.cpp b/Firmware/mmu.cpp index a9986bccd0..43def55859 100644 --- a/Firmware/mmu.cpp +++ b/Firmware/mmu.cpp @@ -22,7 +22,7 @@ #define MMU_TODELAY 100 #define MMU_TIMEOUT 10 -#define MMU_CMD_TIMEOUT 300000ul //5min timeout for mmu commands (except P0) +#define MMU_CMD_TIMEOUT 60000ul //300000ul //1min timeout for mmu commands (except P0) #define MMU_P0_TIMEOUT 3000ul //timeout for P0 command: 3seconds #ifdef MMU_HWRESET @@ -32,6 +32,7 @@ bool mmu_enabled = false; bool mmu_ready = false; +bool isMMUPrintPaused = false; bool mmuFSensorLoading = false; int lastLoadedFilament = -10; @@ -160,14 +161,6 @@ int8_t mmu_rx_ok(void) return res; } -//check 'nk' response -int8_t mmu_rx_not_ok(void) -{ - int8_t res = uart2_rx_str_P(PSTR("nk\n")); - if (res == 1) mmu_last_response = millis(); - return res; -} - //check 'MK3 FSensor requested to look for load' response int8_t mmu_rx_fsensorLook(void) { @@ -210,7 +203,6 @@ void mmu_init(void) * 2 >> 1 MMURX ok, Finda State * 3 >> 1 MMURX ok, mmu commands response * 10 >> 3 MMUECHO, confirm receipt of cmd (timeout 500ms to resend) - * 20 >> 1 not_ok */ void mmu_loop(void) @@ -219,6 +211,8 @@ void mmu_loop(void) #ifdef MMU_DEBUG if (last_state != mmu_state) printf_P(PSTR("MMU loop, state=%d\n"), mmu_state); #endif //MMU_DEBUG + //if (mmu_print_saved && !isMMUPrintPaused) { printf_P(PSTR("// action:pause\n")); isMMUPrintPaused = true; } + //if (!mmu_print_saved && isMMUPrintPaused) { printf_P(PSTR("// action:resume\n")); isMMUPrintPaused = false; } last_state = mmu_state; switch (mmu_state) { @@ -421,7 +415,6 @@ void mmu_loop(void) { printf_P(PSTR("MMU <= 'Filament seen at extruder'\n")); mmu_puts_P(PSTR("EE\n")); - //mmuFSensorLoading = false; mmu_state = 3; // wait for response } mmu_cmd = 0; @@ -430,22 +423,21 @@ void mmu_loop(void) { mmu_puts_P(PSTR("P0\n")); //send 'read finda' request mmu_state = 2; + } else if (((mmu_last_response + 500) < millis()) && mmuFSensorLoading) { + if (!fsensor_enabled) fsensor_enable(); } return; case 2: //response to command P0 if (mmu_rx_ok() > 0) { fscanf_P(uart2io, PSTR("%hhu"), &mmu_finda); //scan finda from buffer - //printf_P(PSTR("MMU => '%dok'\n"), mmu_finda); if (!mmu_finda && CHECK_FINDA && fsensor_enabled) { - fsensor_stop_and_save_print(); - enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover - if (lcd_autoDepleteEnabled()) enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command - else enquecommand_front_P(PSTR("M600")); //save print and run M600 command + fsensor_stop_and_save_print(); + enquecommand_front_P(PSTR("FSENSOR_RECOVER")); //then recover + if (lcd_autoDepleteEnabled()) enquecommand_front_P(PSTR("M600 AUTO")); //save print and run M600 command + else enquecommand_front_P(PSTR("M600")); //save print and run M600 command } mmu_state = 1; - //if (mmu_cmd == 0) - //mmu_ready = true; } else if ((mmu_last_request + MMU_P0_TIMEOUT) < millis()) { //resend request after timeout (30s) @@ -470,39 +462,19 @@ void mmu_loop(void) printf_P(PSTR("MMU => 'ok'\n")); mmu_ready = true; mmu_state = 1; - } else if(mmu_rx_not_ok() > 0) - { - printf_P(PSTR("MMU => 'fixTheProblem!!'\n")); - mmu_ready = false; - mmu_state = 20; - } - else if ((mmu_last_request + MMU_CMD_TIMEOUT) < millis()) - { //resend request after timeout (5 min) - printf_P(PSTR("MMU => 'Erro 5m Timeout'\n")); - mmu_ready = false; - mmu_state = 20; } return; case 10: //echo response, comms confirmation if (mmu_rx_echo() > 0) { printf_P(PSTR("MMU => 'CMD ACK 0x%2X'\n"), mmu_cmd); - //mmu_puts_P(PSTR("EE\n")); // Advise MMU CMD is correct, execute ack_received = true; mmu_state = 1; // Do normal Await command completion confirmation } else if ((mmu_last_request + 1000) < millis()) { // Timeout if echo doesn't match request, resend cmd - //printf_P(PSTR("MMU => 'CMD RETRY'\n")); printf_P(PSTR("MMU => 'CMD RETRY 0x%2X'\n"), mmu_cmd); mmu_state = 1; } return; - case 20: // MMU in fixTheProblem mode, we're waiting for an all good from it to continue. - if (mmu_rx_ok() > 0) - { - //if ok received then go back to ready - mmu_state = 1; - mmu_ready = true; - } } } @@ -531,21 +503,20 @@ int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament) void mmu_command(uint8_t cmd) { #ifdef TMC2130 - if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4)) - { - //disable extruder motor - tmc2130_set_pwr(E_AXIS, 0); - //printf_P(PSTR("E-axis disabled\n")); - } + if ((cmd >= MMU_CMD_T0) && (cmd <= MMU_CMD_T4)) + { + //disable extruder motor + tmc2130_set_pwr(E_AXIS, 0); + //printf_P(PSTR("E-axis disabled\n")); + } #endif //TMC2130 - mmu_cmd = cmd; - mmu_ready = false; + mmu_cmd = cmd; + mmu_ready = false; } bool mmu_get_response(void) { -// printf_P(PSTR("mmu_get_response - begin\n")); KEEPALIVE_STATE(IN_PROCESS); while (mmu_cmd != 0) { @@ -553,7 +524,7 @@ bool mmu_get_response(void) } while (!mmu_ready) { - if ((mmu_state == 3) || (mmu_state == 10) || ((mmuFSensorLoading) && ((mmu_last_request + MMU_CMD_TIMEOUT) > millis()))) { + if (((mmu_state == 3) || (mmu_state == 10) || (mmuFSensorLoading)) && ((mmu_last_request + MMU_CMD_TIMEOUT) > millis())) { delay_keep_alive(100); } else { break; @@ -561,122 +532,125 @@ bool mmu_get_response(void) } bool ret = mmu_ready; mmu_ready = false; -// printf_P(PSTR("mmu_get_response - end %d\n"), ret?1:0); return ret; } void manage_response(bool move_axes, bool turn_off_nozzle) { - bool response = false; - mmu_print_saved = false; - bool lcd_update_was_enabled = false; - float hotend_temp_bckp = degTargetHotend(active_extruder); - float z_position_bckp = current_position[Z_AXIS]; - float x_position_bckp = current_position[X_AXIS]; - float y_position_bckp = current_position[Y_AXIS]; - uint8_t screen = 0; //used for showing multiscreen messages - while(!response) - { - response = mmu_get_response(); //wait for "ok" from mmu - if (!response) { //no "ok" was received in reserved time frame, user will fix the issue on mmu unit - if (!mmu_print_saved) { //first occurence, we are saving current position, park print head in certain position and disable nozzle heater - if (lcd_update_enabled) { - lcd_update_was_enabled = true; - lcd_update_enable(false); - } - st_synchronize(); - mmu_print_saved = true; - printf_P(PSTR("MMU not responding\n")); - hotend_temp_bckp = degTargetHotend(active_extruder); - if (move_axes) { - z_position_bckp = current_position[Z_AXIS]; - x_position_bckp = current_position[X_AXIS]; - y_position_bckp = current_position[Y_AXIS]; - - //lift z - current_position[Z_AXIS] += Z_PAUSE_LIFT; - if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder); - st_synchronize(); - - //Move XY to side - current_position[X_AXIS] = X_PAUSE_POS; - current_position[Y_AXIS] = Y_PAUSE_POS; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); - st_synchronize(); - } - if (turn_off_nozzle) { - //set nozzle target temperature to 0 - setAllTargetHotends(0); - } - } - - //first three lines are used for printing multiscreen message; last line contains measured and target nozzle temperature - if (screen == 0) { //screen 0 - lcd_display_message_fullscreen_P(_i("MMU needs user attention.")); - screen++; - } - else { //screen 1 - if((degTargetHotend(active_extruder) == 0) && turn_off_nozzle) lcd_display_message_fullscreen_P(_i("Press the knob to resume nozzle temperature.")); - else lcd_display_message_fullscreen_P(_i("Fix the issue and then press button on MMU unit.")); - screen=0; - } - - lcd_set_degree(); - lcd_set_cursor(0, 4); //line 4 - //Print the hotend temperature (9 chars total) and fill rest of the line with space - int chars = lcd_printf_P(_N("%c%3d/%d%c"), LCD_STR_THERMOMETER[0],(int)(degHotend(active_extruder) + 0.5), (int)(degTargetHotend(active_extruder) + 0.5), LCD_STR_DEGREE[0]); - lcd_space(9 - chars); + bool response = false; + mmu_print_saved = false; + bool lcd_update_was_enabled = false; + float hotend_temp_bckp = degTargetHotend(active_extruder); + float z_position_bckp = current_position[Z_AXIS]; + float x_position_bckp = current_position[X_AXIS]; + float y_position_bckp = current_position[Y_AXIS]; + uint8_t screen = 0; //used for showing multiscreen messages + while(!response) + { + response = mmu_get_response(); //wait for "ok" from mmu + if (!response) { //no "ok" was received in reserved time frame, user will fix the issue on mmu unit + if (!mmu_print_saved) { //first occurence, we are saving current position, park print head in certain position and disable nozzle heater + if (lcd_update_enabled) { + lcd_update_was_enabled = true; + lcd_update_enable(false); + } + st_synchronize(); + mmu_print_saved = true; + printf_P(PSTR("MMU not responding\n")); + hotend_temp_bckp = degTargetHotend(active_extruder); + if (move_axes) { + z_position_bckp = current_position[Z_AXIS]; + x_position_bckp = current_position[X_AXIS]; + y_position_bckp = current_position[Y_AXIS]; + + //lift z + current_position[Z_AXIS] += Z_PAUSE_LIFT; + if (current_position[Z_AXIS] > Z_MAX_POS) current_position[Z_AXIS] = Z_MAX_POS; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder); + st_synchronize(); + + //Move XY to side + current_position[X_AXIS] = X_PAUSE_POS; + current_position[Y_AXIS] = Y_PAUSE_POS; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); + st_synchronize(); + } + if (turn_off_nozzle) { + //set nozzle target temperature to 0 + setAllTargetHotends(0); + } + } + //first three lines are used for printing multiscreen message; last line contains measured and target nozzle temperature + if (screen == 0) { //screen 0 + lcd_display_message_fullscreen_P(_i("MMU needs user attention.")); + screen++; + } + else if (screen == 1) { //screen 1 + if((degTargetHotend(active_extruder) == 0) && turn_off_nozzle) lcd_display_message_fullscreen_P(_i("Press the knob to resume nozzle temperature.")); + else lcd_display_message_fullscreen_P(_i("Fix the issue and then press button on MMU unit.")); + screen = 0; + } - //5 seconds delay - for (uint8_t i = 0; i < 50; i++) { - if (lcd_clicked()) { - setTargetHotend(hotend_temp_bckp, active_extruder); - break; - } - delay_keep_alive(100); - } - } - else if (mmu_print_saved) { - printf_P(PSTR("MMU starts responding\n")); - if (turn_off_nozzle) - { - lcd_clear(); - setTargetHotend(hotend_temp_bckp, active_extruder); - if (((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5)) { - lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature...")); - delay_keep_alive(3000); - } - while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) - { - delay_keep_alive(1000); - lcd_wait_for_heater(); - } - } - if (move_axes) { - lcd_clear(); - lcd_display_message_fullscreen_P(_i("MMU OK. Resuming position...")); - current_position[X_AXIS] = x_position_bckp; - current_position[Y_AXIS] = y_position_bckp; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); - st_synchronize(); - current_position[Z_AXIS] = z_position_bckp; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder); - st_synchronize(); + lcd_set_degree(); + lcd_set_cursor(0, 4); //line 4 + //Print the hotend temperature (9 chars total) and fill rest of the line with space + int chars = lcd_printf_P(_N("%c%3d/%d%c"), LCD_STR_THERMOMETER[0],(int)(degHotend(active_extruder) + 0.5), (int)(degTargetHotend(active_extruder) + 0.5), LCD_STR_DEGREE[0]); + lcd_space(9 - chars); + + + //5 seconds delay + for (uint8_t i = 0; i < 50; i++) { + if (lcd_clicked()) { + setTargetHotend(hotend_temp_bckp, active_extruder); + if (mmuFSensorLoading) { + if (!fsensor_enabled) fsensor_enable(); + if (!fsensor_autoload_enabled) fsensor_autoload_enabled = true; + fsensor_autoload_check_stop(); + } + break; + } + delay_keep_alive(100); + } } - else { - lcd_clear(); - lcd_display_message_fullscreen_P(_i("MMU OK. Resuming...")); - delay_keep_alive(1000); //delay just for showing MMU OK message for a while in case that there are no xyz movements + else if (mmu_print_saved) { + printf_P(PSTR("MMU starts responding\n")); + if (turn_off_nozzle) + { + lcd_clear(); + setTargetHotend(hotend_temp_bckp, active_extruder); + if (((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5)) { + lcd_display_message_fullscreen_P(_i("MMU OK. Resuming temperature...")); + delay_keep_alive(3000); + } + while ((degTargetHotend(active_extruder) - degHotend(active_extruder)) > 5) + { + delay_keep_alive(1000); + lcd_wait_for_heater(); + } + } + if (move_axes) { + lcd_clear(); + lcd_display_message_fullscreen_P(_i("MMU OK. Resuming position...")); + current_position[X_AXIS] = x_position_bckp; + current_position[Y_AXIS] = y_position_bckp; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 50, active_extruder); + st_synchronize(); + current_position[Z_AXIS] = z_position_bckp; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 15, active_extruder); + st_synchronize(); + } else { + lcd_clear(); + lcd_display_message_fullscreen_P(_i("MMU OK. Resuming...")); + delay_keep_alive(1000); //delay just for showing MMU OK message for a while in case that there are no xyz movements + } } - } - } - if (lcd_update_was_enabled) lcd_update_enable(true); + } + if (lcd_update_was_enabled) lcd_update_enable(true); #ifdef TMC2130 - //enable extruder motor (disabled in mmu_command, start of T-code processing) - tmc2130_set_pwr(E_AXIS, 1); - //printf_P(PSTR("E-axis enabled\n")); + //enable extruder motor (disabled in mmu_command, start of T-code processing) + tmc2130_set_pwr(E_AXIS, 1); + //printf_P(PSTR("E-axis enabled\n")); #endif //TMC2130 } @@ -774,13 +748,12 @@ void mmu_M600_load_filament(bool automatic) // mmu_printf_P(PSTR("T%d\n"), tmp_extruder); mmu_command(MMU_CMD_T0 + tmp_extruder); - manage_response(false, true); - delay(1500); - mmu_command(MMU_CMD_C0); - mmu_extruder = tmp_extruder; //filament change is finished - mmu_load_to_nozzle(); - load_filament_final_feed(); - st_synchronize(); + manage_response(false, true); + mmu_command(MMU_CMD_C0); + mmu_extruder = tmp_extruder; //filament change is finished + mmu_load_to_nozzle(); + load_filament_final_feed(); + st_synchronize(); } @@ -1058,12 +1031,12 @@ void extr_unload() lcd_return_to_status(); max_feedrate[E_AXIS] = 50; #endif //SNMM - } - else - { - show_preheat_nozzle_warning(); - } - //lcd_return_to_status(); + } + else + { + show_preheat_nozzle_warning(); + } + //lcd_return_to_status(); } //wrapper functions for loading filament @@ -1117,29 +1090,29 @@ void extr_adj_4() #endif } -void mmu_load_to_nozzle_0() +void mmu_load_to_nozzle_0() { - lcd_mmu_load_to_nozzle(0); + lcd_mmu_load_to_nozzle(0); } -void mmu_load_to_nozzle_1() +void mmu_load_to_nozzle_1() { - lcd_mmu_load_to_nozzle(1); + lcd_mmu_load_to_nozzle(1); } -void mmu_load_to_nozzle_2() +void mmu_load_to_nozzle_2() { - lcd_mmu_load_to_nozzle(2); + lcd_mmu_load_to_nozzle(2); } -void mmu_load_to_nozzle_3() +void mmu_load_to_nozzle_3() { - lcd_mmu_load_to_nozzle(3); + lcd_mmu_load_to_nozzle(3); } -void mmu_load_to_nozzle_4() +void mmu_load_to_nozzle_4() { - lcd_mmu_load_to_nozzle(4); + lcd_mmu_load_to_nozzle(4); } void mmu_eject_fil_0() @@ -1213,37 +1186,37 @@ void extr_change_3() //wrapper functions for unloading filament void extr_unload_all() { - if (degHotend0() > EXTRUDE_MINTEMP) - { - for (int i = 0; i < 4; i++) + if (degHotend0() > EXTRUDE_MINTEMP) { - change_extr(i); - extr_unload(); + for (int i = 0; i < 4; i++) + { + change_extr(i); + extr_unload(); + } + } + else + { + show_preheat_nozzle_warning(); + lcd_return_to_status(); } - } - else - { - show_preheat_nozzle_warning(); - lcd_return_to_status(); - } } //unloading just used filament (for snmm) void extr_unload_used() { - if (degHotend0() > EXTRUDE_MINTEMP) { - for (int i = 0; i < 4; i++) { - if (snmm_filaments_used & (1 << i)) { - change_extr(i); - extr_unload(); - } + if (degHotend0() > EXTRUDE_MINTEMP) { + for (int i = 0; i < 4; i++) { + if (snmm_filaments_used & (1 << i)) { + change_extr(i); + extr_unload(); + } + } + snmm_filaments_used = 0; + } + else { + show_preheat_nozzle_warning(); + lcd_return_to_status(); } - snmm_filaments_used = 0; - } - else { - show_preheat_nozzle_warning(); - lcd_return_to_status(); - } } #endif //SNMM @@ -1290,34 +1263,34 @@ void mmu_show_warning() void lcd_mmu_load_to_nozzle(uint8_t filament_nr) { - if (degHotend0() > EXTRUDE_MINTEMP) - { - tmp_extruder = filament_nr; - lcd_update_enable(false); - lcd_clear(); - lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_LOADING_FILAMENT)); - lcd_print(" "); - lcd_print(tmp_extruder + 1); - mmu_command(MMU_CMD_T0 + tmp_extruder); - manage_response(true, true); - delay(1500); - mmu_command(MMU_CMD_C0); - mmu_extruder = tmp_extruder; //filament change is finished - mmu_load_to_nozzle(); - load_filament_final_feed(); - st_synchronize(); - custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; - lcd_setstatuspgm(_T(MSG_LOADING_FILAMENT)); - lcd_return_to_status(); - lcd_update_enable(true); - lcd_load_filament_color_check(); - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = CUSTOM_MSG_TYPE_STATUS; - } - else - { - show_preheat_nozzle_warning(); - } + if (degHotend0() > EXTRUDE_MINTEMP) + { + tmp_extruder = filament_nr; + lcd_update_enable(false); + lcd_clear(); + lcd_set_cursor(0, 1); + lcd_puts_P(_T(MSG_LOADING_FILAMENT)); + lcd_print(" "); + lcd_print(tmp_extruder + 1); + mmu_command(MMU_CMD_T0 + tmp_extruder); + manage_response(true, true); + mmu_command(MMU_CMD_C0); + mmu_extruder = tmp_extruder; //filament change is finished + mmu_load_to_nozzle(); + load_filament_final_feed(); + st_synchronize(); + custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; + lcd_setstatuspgm(_T(MSG_LOADING_FILAMENT)); + lcd_return_to_status(); + lcd_update_enable(true); + lcd_load_filament_color_check(); + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = CUSTOM_MSG_TYPE_STATUS; + } + else + { + show_preheat_nozzle_warning(); + } } void mmu_eject_filament(uint8_t filament, bool recover) @@ -1347,14 +1320,14 @@ void mmu_eject_filament(uint8_t filament, bool recover) } } + } + else + { + show_preheat_nozzle_warning(); + } } else { - show_preheat_nozzle_warning(); + puts_P(PSTR("Filament nr out of range!")); } - } - else - { - puts_P(PSTR("Filament nr out of range!")); - } } diff --git a/Firmware/mmu.h b/Firmware/mmu.h index b90b2930b8..dfa36f59b9 100644 --- a/Firmware/mmu.h +++ b/Firmware/mmu.h @@ -47,15 +47,12 @@ extern int8_t mmu_rx_echo(void); extern int8_t mmu_rx_ok(void); -extern int8_t mmu_rx_not_ok(void); - extern int8_t mmu_rx_sensFilatBoot(void); extern void mmu_init(void); extern void mmu_loop(void); - extern void mmu_reset(void); extern int8_t mmu_set_filament_type(uint8_t extruder, uint8_t filament); diff --git a/Firmware/motion_control.cpp b/Firmware/motion_control.cpp index b26cbafc8d..86dd2e585f 100755 --- a/Firmware/motion_control.cpp +++ b/Firmware/motion_control.cpp @@ -4,7 +4,7 @@ Copyright (c) 2009-2011 Simen Svale Skogsrud Copyright (c) 2011 Sungeun K. Jeon - + Grbl 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 @@ -23,123 +23,129 @@ #include "stepper.h" #include "planner.h" -// The arc is approximated by generating a huge number of tiny, linear segments. The length of each -// segment is configured in settings.mm_per_arc_segment. -void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1, - uint8_t axis_linear, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder) -{ - // int acceleration_manager_was_enabled = plan_is_acceleration_manager_enabled(); - // plan_set_acceleration_manager_enabled(false); // disable acceleration management for the duration of the arc - float center_axis0 = position[axis_0] + offset[axis_0]; - float center_axis1 = position[axis_1] + offset[axis_1]; - float linear_travel = target[axis_linear] - position[axis_linear]; - float extruder_travel = target[E_AXIS] - position[E_AXIS]; - float r_axis0 = -offset[axis_0]; // Radius vector from center to current location - float r_axis1 = -offset[axis_1]; - float rt_axis0 = target[axis_0] - center_axis0; - float rt_axis1 = target[axis_1] - center_axis1; - - // CCW angle between position and target from circle center. Only one atan2() trig computation required. - float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1); - if (angular_travel < 0) { angular_travel += 2*M_PI; } - if (isclockwise) { angular_travel -= 2*M_PI; } - - //20141002:full circle for G03 did not work, e.g. G03 X80 Y80 I20 J0 F2000 is giving an Angle of zero so head is not moving - //to compensate when start pos = target pos && angle is zero -> angle = 2Pi - if (position[axis_0] == target[axis_0] && position[axis_1] == target[axis_1] && angular_travel == 0) - { - angular_travel += 2*M_PI; - } - //end fix G03 - - float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel)); - if (millimeters_of_travel < 0.001) { return; } - uint16_t segments = floor(millimeters_of_travel/MM_PER_ARC_SEGMENT); - if(segments == 0) segments = 1; - - /* - // Multiply inverse feed_rate to compensate for the fact that this movement is approximated - // by a number of discrete segments. The inverse feed_rate should be correct for the sum of - // all segments. - if (invert_feed_rate) { feed_rate *= segments; } - */ - float theta_per_segment = angular_travel/segments; - float linear_per_segment = linear_travel/segments; - float extruder_per_segment = extruder_travel/segments; - - /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, - and phi is the angle of rotation. Based on the solution approach by Jens Geisler. - r_T = [cos(phi) -sin(phi); - sin(phi) cos(phi] * r ; - - For arc generation, the center of the circle is the axis of rotation and the radius vector is - defined from the circle center to the initial position. Each line segment is formed by successive - vector rotations. This requires only two cos() and sin() computations to form the rotation - matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since - all double numbers are single precision on the Arduino. (True double precision will not have - round off issues for CNC applications.) Single precision error can accumulate to be greater than - tool precision in some cases. Therefore, arc path correction is implemented. - - Small angle approximation may be used to reduce computation overhead further. This approximation - holds for everything, but very small circles and large mm_per_arc_segment values. In other words, - theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large - to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for - numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an - issue for CNC machines with the single precision Arduino calculations. - - This approximation also allows mc_arc to immediately insert a line segment into the planner - without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied - a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead. - This is important when there are successive arc motions. - */ - // Vector rotation matrix values - float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation - float sin_T = theta_per_segment; - - float arc_target[4]; - float sin_Ti; - float cos_Ti; - float r_axisi; - uint16_t i; - int8_t count = 0; - - // Initialize the linear axis - arc_target[axis_linear] = position[axis_linear]; - - // Initialize the extruder axis - arc_target[E_AXIS] = position[E_AXIS]; - - for (i = 1; i angle = 2Pi + if (position[axis_0] == target[axis_0] && position[axis_1] == target[axis_1] && angular_travel == 0) + { + angular_travel += 2*M_PI; } + //end fix G03 + + float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel)); + if (millimeters_of_travel < 0.001) { + return; + } + uint16_t segments = floor(millimeters_of_travel/MM_PER_ARC_SEGMENT); + if(segments == 0) segments = 1; + + /* + // Multiply inverse feed_rate to compensate for the fact that this movement is approximated + // by a number of discrete segments. The inverse feed_rate should be correct for the sum of + // all segments. + if (invert_feed_rate) { feed_rate *= segments; } + */ + float theta_per_segment = angular_travel/segments; + float linear_per_segment = linear_travel/segments; + float extruder_per_segment = extruder_travel/segments; + + /* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector, + and phi is the angle of rotation. Based on the solution approach by Jens Geisler. + r_T = [cos(phi) -sin(phi); + sin(phi) cos(phi] * r ; + + For arc generation, the center of the circle is the axis of rotation and the radius vector is + defined from the circle center to the initial position. Each line segment is formed by successive + vector rotations. This requires only two cos() and sin() computations to form the rotation + matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since + all double numbers are single precision on the Arduino. (True double precision will not have + round off issues for CNC applications.) Single precision error can accumulate to be greater than + tool precision in some cases. Therefore, arc path correction is implemented. - // Update arc_target location - arc_target[axis_0] = center_axis0 + r_axis0; - arc_target[axis_1] = center_axis1 + r_axis1; - arc_target[axis_linear] += linear_per_segment; - arc_target[E_AXIS] += extruder_per_segment; + Small angle approximation may be used to reduce computation overhead further. This approximation + holds for everything, but very small circles and large mm_per_arc_segment values. In other words, + theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large + to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for + numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an + issue for CNC machines with the single precision Arduino calculations. - clamp_to_software_endstops(arc_target); - plan_buffer_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], arc_target[E_AXIS], feed_rate, extruder); - - } - // Ensure last segment arrives at target location. - plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, extruder); + This approximation also allows mc_arc to immediately insert a line segment into the planner + without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied + a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead. + This is important when there are successive arc motions. + */ + // Vector rotation matrix values + float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation + float sin_T = theta_per_segment; + + float arc_target[4]; + float sin_Ti; + float cos_Ti; + float r_axisi; + uint16_t i; + int8_t count = 0; + + // Initialize the linear axis + arc_target[axis_linear] = position[axis_linear]; + + // Initialize the extruder axis + arc_target[E_AXIS] = position[E_AXIS]; + + for (i = 1; i boot_timeout) - // Timeout expired, continue with the application. - return; - } - ch = UDR0; - if (pgm_read_byte(ptr ++) != ch) - // Magic was not received correctly, continue with the application - return; - watchdogReset(); + // Wait for one second until a magic string (constant entry_magic) is received + // from the serial line. + ptr = entry_magic_receive; + end = strlen_P(entry_magic_receive) + ptr; + while (ptr != end) { + while (! RECV_READY) { + watchdogReset(); + delayMicroseconds(1); + if (++ boot_timer > boot_timeout) + // Timeout expired, continue with the application. + return; + } + ch = UDR0; + if (pgm_read_byte(ptr ++) != ch) + // Magic was not received correctly, continue with the application + return; + watchdogReset(); + } + // Send the cfm magic string. + ptr = entry_magic_cfm; + while (ptr != end) + putch(pgm_read_byte(ptr ++)); } - // Send the cfm magic string. - ptr = entry_magic_cfm; - while (ptr != end) - putch(pgm_read_byte(ptr ++)); - } - spi_init(); - w25x20cl_init(); - watchdogConfig(WATCHDOG_OFF); + spi_init(); + w25x20cl_init(); + watchdogConfig(WATCHDOG_OFF); - /* Forever loop: exits by causing WDT reset */ - for (;;) { - /* get character from UART */ - ch = getch(); + /* Forever loop: exits by causing WDT reset */ + for (;;) { + /* get character from UART */ + ch = getch(); - if(ch == STK_GET_PARAMETER) { - unsigned char which = getch(); - verifySpace(); - /* - * Send optiboot version as "SW version" - * Note that the references to memory are optimized away. - */ - if (which == STK_SW_MINOR) { - putch(optiboot_version & 0xFF); - } else if (which == STK_SW_MAJOR) { - putch(optiboot_version >> 8); - } else { - /* - * GET PARAMETER returns a generic 0x03 reply for - * other parameters - enough to keep Avrdude happy - */ - putch(0x03); - } - } - else if(ch == STK_SET_DEVICE) { - // SET DEVICE is ignored - getNch(20); - } - else if(ch == STK_SET_DEVICE_EXT) { - // SET DEVICE EXT is ignored - getNch(5); - } - else if(ch == STK_LOAD_ADDRESS) { - // LOAD ADDRESS - uint16_t newAddress; - // Workaround for the infamous ';' bug in the Prusa3D usb to serial converter. - // Send the binary data by nibbles to avoid transmitting the ';' character. - newAddress = getch(); - newAddress |= getch(); - newAddress |= (((uint16_t)getch()) << 8); - newAddress |= (((uint16_t)getch()) << 8); - // Transfer top bit to LSB in rampz - if (newAddress & 0x8000) - rampz |= 0x01; - else - rampz &= 0xFE; - newAddress += newAddress; // Convert from word address to byte address - address = newAddress; - verifySpace(); - } - else if(ch == STK_UNIVERSAL) { - // LOAD_EXTENDED_ADDRESS is needed in STK_UNIVERSAL for addressing more than 128kB - if ( AVR_OP_LOAD_EXT_ADDR == getch() ) { - // get address - getch(); // get '0' - rampz = (rampz & 0x01) | ((getch() << 1) & 0xff); // get address and put it in rampz - getNch(1); // get last '0' - // response - putch(0x00); - } - else { - // everything else is ignored - getNch(3); - putch(0x00); - } - } - /* Write memory, length is big endian and is in bytes */ - else if(ch == STK_PROG_PAGE) { - // PROGRAM PAGE - we support flash programming only, not EEPROM - uint8_t desttype; - uint8_t *bufPtr; - pagelen_t savelength; - // Read the page length, with the length transferred each nibble separately to work around - // the Prusa's USB to serial infamous semicolon issue. - length = ((pagelen_t)getch()) << 8; - length |= ((pagelen_t)getch()) << 8; - length |= getch(); - length |= getch(); + if(ch == STK_GET_PARAMETER) { + unsigned char which = getch(); + verifySpace(); + /* + * Send optiboot version as "SW version" + * Note that the references to memory are optimized away. + */ + if (which == STK_SW_MINOR) { + putch(optiboot_version & 0xFF); + } else if (which == STK_SW_MAJOR) { + putch(optiboot_version >> 8); + } else { + /* + * GET PARAMETER returns a generic 0x03 reply for + * other parameters - enough to keep Avrdude happy + */ + putch(0x03); + } + } + else if(ch == STK_SET_DEVICE) { + // SET DEVICE is ignored + getNch(20); + } + else if(ch == STK_SET_DEVICE_EXT) { + // SET DEVICE EXT is ignored + getNch(5); + } + else if(ch == STK_LOAD_ADDRESS) { + // LOAD ADDRESS + uint16_t newAddress; + // Workaround for the infamous ';' bug in the Prusa3D usb to serial converter. + // Send the binary data by nibbles to avoid transmitting the ';' character. + newAddress = getch(); + newAddress |= getch(); + newAddress |= (((uint16_t)getch()) << 8); + newAddress |= (((uint16_t)getch()) << 8); + // Transfer top bit to LSB in rampz + if (newAddress & 0x8000) + rampz |= 0x01; + else + rampz &= 0xFE; + newAddress += newAddress; // Convert from word address to byte address + address = newAddress; + verifySpace(); + } + else if(ch == STK_UNIVERSAL) { + // LOAD_EXTENDED_ADDRESS is needed in STK_UNIVERSAL for addressing more than 128kB + if ( AVR_OP_LOAD_EXT_ADDR == getch() ) { + // get address + getch(); // get '0' + rampz = (rampz & 0x01) | ((getch() << 1) & 0xff); // get address and put it in rampz + getNch(1); // get last '0' + // response + putch(0x00); + } + else { + // everything else is ignored + getNch(3); + putch(0x00); + } + } + /* Write memory, length is big endian and is in bytes */ + else if(ch == STK_PROG_PAGE) { + // PROGRAM PAGE - we support flash programming only, not EEPROM + uint8_t desttype; + uint8_t *bufPtr; + pagelen_t savelength; + // Read the page length, with the length transferred each nibble separately to work around + // the Prusa's USB to serial infamous semicolon issue. + length = ((pagelen_t)getch()) << 8; + length |= ((pagelen_t)getch()) << 8; + length |= getch(); + length |= getch(); - savelength = length; - // Read the destination type. It should always be 'F' as flash. - desttype = getch(); + savelength = length; + // Read the destination type. It should always be 'F' as flash. + desttype = getch(); - // read a page worth of contents - bufPtr = buff; - do *bufPtr++ = getch(); - while (--length); + // read a page worth of contents + bufPtr = buff; + do *bufPtr++ = getch(); + while (--length); - // Read command terminator, start reply - verifySpace(); - if (desttype == 'E') { - while (1) ; // Error: wait for WDT - } else { - uint32_t addr = (((uint32_t)rampz) << 16) | address; - // During a single bootloader run, only erase a 64kB block once. - // An 8bit bitmask 'pages_erased' covers 512kB of FLASH memory. - if (address == 0 && (pages_erased & (1 << addr)) == 0) { - w25x20cl_wait_busy(); - w25x20cl_enable_wr(); - w25x20cl_block64_erase(addr); - pages_erased |= (1 << addr); + // Read command terminator, start reply + verifySpace(); + if (desttype == 'E') { + while (1) ; // Error: wait for WDT + } else { + uint32_t addr = (((uint32_t)rampz) << 16) | address; + // During a single bootloader run, only erase a 64kB block once. + // An 8bit bitmask 'pages_erased' covers 512kB of FLASH memory. + if (address == 0 && (pages_erased & (1 << addr)) == 0) { + w25x20cl_wait_busy(); + w25x20cl_enable_wr(); + w25x20cl_block64_erase(addr); + pages_erased |= (1 << addr); + } + w25x20cl_wait_busy(); + w25x20cl_enable_wr(); + w25x20cl_page_program(addr, buff, savelength); + w25x20cl_wait_busy(); + w25x20cl_disable_wr(); + } } - w25x20cl_wait_busy(); - w25x20cl_enable_wr(); - w25x20cl_page_program(addr, buff, savelength); - w25x20cl_wait_busy(); - w25x20cl_disable_wr(); - } - } - /* Read memory block mode, length is big endian. */ - else if(ch == STK_READ_PAGE) { - uint32_t addr = (((uint32_t)rampz) << 16) | address; - register pagelen_t i; - // Read the page length, with the length transferred each nibble separately to work around - // the Prusa's USB to serial infamous semicolon issue. - length = ((pagelen_t)getch()) << 8; - length |= ((pagelen_t)getch()) << 8; - length |= getch(); - length |= getch(); - // Read the destination type. It should always be 'F' as flash. It is not checked. - (void)getch(); - verifySpace(); - w25x20cl_wait_busy(); - w25x20cl_rd_data(addr, buff, length); - for (i = 0; i < length; ++ i) - putch(buff[i]); - } - /* Get device signature bytes */ - else if(ch == STK_READ_SIGN) { - // READ SIGN - return what Avrdude wants to hear - verifySpace(); - putch(W25X20CL_SIGNATURE_0); - putch(W25X20CL_SIGNATURE_1); - putch(W25X20CL_SIGNATURE_2); - } - else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */ - // Adaboot no-wait mod - watchdogConfig(WATCHDOG_16MS); - verifySpace(); - } - else { - // This covers the response to commands like STK_ENTER_PROGMODE - verifySpace(); + /* Read memory block mode, length is big endian. */ + else if(ch == STK_READ_PAGE) { + uint32_t addr = (((uint32_t)rampz) << 16) | address; + register pagelen_t i; + // Read the page length, with the length transferred each nibble separately to work around + // the Prusa's USB to serial infamous semicolon issue. + length = ((pagelen_t)getch()) << 8; + length |= ((pagelen_t)getch()) << 8; + length |= getch(); + length |= getch(); + // Read the destination type. It should always be 'F' as flash. It is not checked. + (void)getch(); + verifySpace(); + w25x20cl_wait_busy(); + w25x20cl_rd_data(addr, buff, length); + for (i = 0; i < length; ++ i) + putch(buff[i]); + } + /* Get device signature bytes */ + else if(ch == STK_READ_SIGN) { + // READ SIGN - return what Avrdude wants to hear + verifySpace(); + putch(W25X20CL_SIGNATURE_0); + putch(W25X20CL_SIGNATURE_1); + putch(W25X20CL_SIGNATURE_2); + } + else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */ + // Adaboot no-wait mod + watchdogConfig(WATCHDOG_16MS); + verifySpace(); + } + else { + // This covers the response to commands like STK_ENTER_PROGMODE + verifySpace(); + } + putch(STK_OK); } - putch(STK_OK); - } } diff --git a/Firmware/pat9125.c b/Firmware/pat9125.c old mode 100755 new mode 100644 index 7b7353dde8..5185ce5b89 --- a/Firmware/pat9125.c +++ b/Firmware/pat9125.c @@ -33,6 +33,7 @@ #include "swi2c.h" #endif //PAT9125_SWI2C +#define PAT9125_NEW_INIT uint8_t pat9125_PID1 = 0; uint8_t pat9125_PID2 = 0; @@ -44,9 +45,9 @@ uint8_t pat9125_s = 0; // Init sequence, address & value. const PROGMEM uint8_t pat9125_init_seq1[] = { - // Disable write protect. - PAT9125_WP, 0x5a, - // Set the X resolution to zero to let the sensor know that it could safely ignore movement in the X axis. + // Disable write protect. + PAT9125_WP, 0x5a, + // Set the X resolution to zero to let the sensor know that it could safely ignore movement in the X axis. PAT9125_RES_X, PAT9125_XRES, // Set the Y resolution to a maximum (or nearly a maximum). PAT9125_RES_Y, PAT9125_YRES, @@ -64,33 +65,33 @@ const PROGMEM uint8_t pat9125_init_seq1[] = { // Init sequence, address & value. const PROGMEM uint8_t pat9125_init_seq2[] = { - // Magic sequence to enforce full frame rate of the sensor. - 0x06, 0x028, - 0x33, 0x0d0, - 0x36, 0x0c2, - 0x3e, 0x001, - 0x3f, 0x015, - 0x41, 0x032, - 0x42, 0x03b, - 0x43, 0x0f2, - 0x44, 0x03b, - 0x45, 0x0f2, - 0x46, 0x022, - 0x47, 0x03b, - 0x48, 0x0f2, - 0x49, 0x03b, - 0x4a, 0x0f0, - 0x58, 0x098, - 0x59, 0x00c, - 0x5a, 0x008, - 0x5b, 0x00c, - 0x5c, 0x008, - 0x61, 0x010, - 0x67, 0x09b, - 0x6e, 0x022, - 0x71, 0x007, - 0x72, 0x008, - // stopper + // Magic sequence to enforce full frame rate of the sensor. + 0x06, 0x028, + 0x33, 0x0d0, + 0x36, 0x0c2, + 0x3e, 0x001, + 0x3f, 0x015, + 0x41, 0x032, + 0x42, 0x03b, + 0x43, 0x0f2, + 0x44, 0x03b, + 0x45, 0x0f2, + 0x46, 0x022, + 0x47, 0x03b, + 0x48, 0x0f2, + 0x49, 0x03b, + 0x4a, 0x0f0, + 0x58, 0x098, + 0x59, 0x00c, + 0x5a, 0x008, + 0x5b, 0x00c, + 0x5c, 0x008, + 0x61, 0x010, + 0x67, 0x09b, + 0x6e, 0x022, + 0x71, 0x007, + 0x72, 0x008, + // stopper 0x0ff }; @@ -106,176 +107,176 @@ extern FILE _uartout; uint8_t pat9125_init(void) { #ifdef PAT9125_SWSPI - swspi_init(); + swspi_init(); #endif //PAT9125_SWSPI #ifdef PAT9125_SWI2C - swi2c_init(); + swi2c_init(); #endif //PAT9125_SWI2C - // Verify that the sensor responds with its correct product ID. - pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1); - pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2); - if ((pat9125_PID1 != 0x31) || (pat9125_PID2 != 0x91)) - { - pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1); - pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2); - if ((pat9125_PID1 != 0x31) || (pat9125_PID2 != 0x91)) - return 0; - } + // Verify that the sensor responds with its correct product ID. + pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1); + pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2); + if ((pat9125_PID1 != 0x31) || (pat9125_PID2 != 0x91)) + { + pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1); + pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2); + if ((pat9125_PID1 != 0x31) || (pat9125_PID2 != 0x91)) + return 0; + } #ifdef PAT9125_NEW_INIT - // Switch to bank0, not allowed to perform OTS_RegWriteRead. - pat9125_wr_reg(PAT9125_BANK_SELECTION, 0); - // Software reset (i.e. set bit7 to 1). It will reset to 0 automatically. - // After the reset, OTS_RegWriteRead is not allowed. - pat9125_wr_reg(PAT9125_CONFIG, 0x97); - // Wait until the sensor reboots. - // Delay 1ms. - _delay_us(1000); - { - const uint8_t *ptr = pat9125_init_seq1; - for (;;) { - const uint8_t addr = pgm_read_byte_near(ptr ++); - if (addr == 0x0ff) - break; - if (! pat9125_wr_reg_verify(addr, pgm_read_byte_near(ptr ++))) - // Verification of the register write failed. - return 0; - } - } - // Delay 10ms. - _delay_ms(10); - // Switch to bank1, not allowed to perform OTS_RegWrite. - pat9125_wr_reg(PAT9125_BANK_SELECTION, 0x01); - { - const uint8_t *ptr = pat9125_init_seq2; - for (;;) { - const uint8_t addr = pgm_read_byte_near(ptr ++); - if (addr == 0x0ff) - break; - if (! pat9125_wr_reg_verify(addr, pgm_read_byte_near(ptr ++))) - // Verification of the register write failed. - return 0; - } - } - // Switch to bank0, not allowed to perform OTS_RegWriteRead. - pat9125_wr_reg(PAT9125_BANK_SELECTION, 0x00); - // Enable write protect. - pat9125_wr_reg(PAT9125_WP, 0x00); + // Switch to bank0, not allowed to perform OTS_RegWriteRead. + pat9125_wr_reg(PAT9125_BANK_SELECTION, 0); + // Software reset (i.e. set bit7 to 1). It will reset to 0 automatically. + // After the reset, OTS_RegWriteRead is not allowed. + pat9125_wr_reg(PAT9125_CONFIG, 0x97); + // Wait until the sensor reboots. + // Delay 1ms. + _delay_us(1000); + { + const uint8_t *ptr = pat9125_init_seq1; + for (;;) { + const uint8_t addr = pgm_read_byte_near(ptr ++); + if (addr == 0x0ff) + break; + if (! pat9125_wr_reg_verify(addr, pgm_read_byte_near(ptr ++))) + // Verification of the register write failed. + return 0; + } + } + // Delay 10ms. + _delay_ms(10); + // Switch to bank1, not allowed to perform OTS_RegWrite. + pat9125_wr_reg(PAT9125_BANK_SELECTION, 0x01); + { + const uint8_t *ptr = pat9125_init_seq2; + for (;;) { + const uint8_t addr = pgm_read_byte_near(ptr ++); + if (addr == 0x0ff) + break; + if (! pat9125_wr_reg_verify(addr, pgm_read_byte_near(ptr ++))) + // Verification of the register write failed. + return 0; + } + } + // Switch to bank0, not allowed to perform OTS_RegWriteRead. + pat9125_wr_reg(PAT9125_BANK_SELECTION, 0x00); + // Enable write protect. + pat9125_wr_reg(PAT9125_WP, 0x00); - pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1); - pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2); + pat9125_PID1 = pat9125_rd_reg(PAT9125_PID1); + pat9125_PID2 = pat9125_rd_reg(PAT9125_PID2); #endif //PAT9125_NEW_INIT - pat9125_wr_reg(PAT9125_RES_X, PAT9125_XRES); - pat9125_wr_reg(PAT9125_RES_Y, PAT9125_YRES); - fprintf_P(uartout, PSTR("PAT9125_RES_X=%hhu\n"), pat9125_rd_reg(PAT9125_RES_X)); - fprintf_P(uartout, PSTR("PAT9125_RES_Y=%hhu\n"), pat9125_rd_reg(PAT9125_RES_Y)); - return 1; + pat9125_wr_reg(PAT9125_RES_X, PAT9125_XRES); + pat9125_wr_reg(PAT9125_RES_Y, PAT9125_YRES); + fprintf_P(uartout, PSTR("PAT9125_RES_X=%hhu\n"), pat9125_rd_reg(PAT9125_RES_X)); + fprintf_P(uartout, PSTR("PAT9125_RES_Y=%hhu\n"), pat9125_rd_reg(PAT9125_RES_Y)); + return 1; } uint8_t pat9125_update(void) { - if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91)) - { - uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION); - pat9125_b = pat9125_rd_reg(PAT9125_FRAME); - pat9125_s = pat9125_rd_reg(PAT9125_SHUTTER); - if (pat9125_PID1 == 0xff) return 0; - if (ucMotion & 0x80) - { - uint8_t ucXL = pat9125_rd_reg(PAT9125_DELTA_XL); - uint8_t ucYL = pat9125_rd_reg(PAT9125_DELTA_YL); - uint8_t ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH); - if (pat9125_PID1 == 0xff) return 0; - int16_t iDX = ucXL | ((ucXYH << 4) & 0xf00); - int16_t iDY = ucYL | ((ucXYH << 8) & 0xf00); - if (iDX & 0x800) iDX -= 4096; - if (iDY & 0x800) iDY -= 4096; - pat9125_x += iDX; - pat9125_y -= iDY; //negative number, because direction switching does not work - } - return 1; - } - return 0; + if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91)) + { + uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION); + pat9125_b = pat9125_rd_reg(PAT9125_FRAME); + pat9125_s = pat9125_rd_reg(PAT9125_SHUTTER); + if (pat9125_PID1 == 0xff) return 0; + if (ucMotion & 0x80) + { + uint8_t ucXL = pat9125_rd_reg(PAT9125_DELTA_XL); + uint8_t ucYL = pat9125_rd_reg(PAT9125_DELTA_YL); + uint8_t ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH); + if (pat9125_PID1 == 0xff) return 0; + int16_t iDX = ucXL | ((ucXYH << 4) & 0xf00); + int16_t iDY = ucYL | ((ucXYH << 8) & 0xf00); + if (iDX & 0x800) iDX -= 4096; + if (iDY & 0x800) iDY -= 4096; + pat9125_x += iDX; + pat9125_y -= iDY; //negative number, because direction switching does not work + } + return 1; + } + return 0; } uint8_t pat9125_update_y(void) { - if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91)) - { - uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION); - if (pat9125_PID1 == 0xff) return 0; - if (ucMotion & 0x80) - { - uint8_t ucYL = pat9125_rd_reg(PAT9125_DELTA_YL); - uint8_t ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH); - if (pat9125_PID1 == 0xff) return 0; - int16_t iDY = ucYL | ((ucXYH << 8) & 0xf00); - if (iDY & 0x800) iDY -= 4096; - pat9125_y -= iDY; //negative number, because direction switching does not work - } - return 1; - } - return 0; + if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91)) + { + uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION); + if (pat9125_PID1 == 0xff) return 0; + if (ucMotion & 0x80) + { + uint8_t ucYL = pat9125_rd_reg(PAT9125_DELTA_YL); + uint8_t ucXYH = pat9125_rd_reg(PAT9125_DELTA_XYH); + if (pat9125_PID1 == 0xff) return 0; + int16_t iDY = ucYL | ((ucXYH << 8) & 0xf00); + if (iDY & 0x800) iDY -= 4096; + pat9125_y -= iDY; //negative number, because direction switching does not work + } + return 1; + } + return 0; } uint8_t pat9125_update_y2(void) { - if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91)) - { - uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION); - if (pat9125_PID1 == 0xff) return 0; //NOACK error - if (ucMotion & 0x80) - { - int8_t dy = pat9125_rd_reg(PAT9125_DELTA_YL); - if (pat9125_PID1 == 0xff) return 0; //NOACK error - pat9125_y -= dy; //negative number, because direction switching does not work - } - return 1; - } - return 0; + if ((pat9125_PID1 == 0x31) && (pat9125_PID2 == 0x91)) + { + uint8_t ucMotion = pat9125_rd_reg(PAT9125_MOTION); + if (pat9125_PID1 == 0xff) return 0; //NOACK error + if (ucMotion & 0x80) + { + int8_t dy = pat9125_rd_reg(PAT9125_DELTA_YL); + if (pat9125_PID1 == 0xff) return 0; //NOACK error + pat9125_y -= dy; //negative number, because direction switching does not work + } + return 1; + } + return 0; } uint8_t pat9125_rd_reg(uint8_t addr) { - uint8_t data = 0; + uint8_t data = 0; #ifdef PAT9125_SWSPI - swspi_start(); - swspi_tx(addr & 0x7f); - data = swspi_rx(); - swspi_stop(); + swspi_start(); + swspi_tx(addr & 0x7f); + data = swspi_rx(); + swspi_stop(); #endif //PAT9125_SWSPI #ifdef PAT9125_SWI2C - if (!swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error - { - pat9125_PID1 = 0xff; - pat9125_PID2 = 0xff; - return 0; - } + if (!swi2c_readByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error + { + pat9125_PID1 = 0xff; + pat9125_PID2 = 0xff; + return 0; + } #endif //PAT9125_SWI2C - return data; + return data; } void pat9125_wr_reg(uint8_t addr, uint8_t data) { #ifdef PAT9125_SWSPI - swspi_start(); - swspi_tx(addr | 0x80); - swspi_tx(data); - swspi_stop(); + swspi_start(); + swspi_tx(addr | 0x80); + swspi_tx(data); + swspi_stop(); #endif //PAT9125_SWSPI #ifdef PAT9125_SWI2C - if (!swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error - { - pat9125_PID1 = 0xff; - pat9125_PID2 = 0xff; - return; - } + if (!swi2c_writeByte_A8(PAT9125_I2C_ADDR, addr, &data)) //NO ACK error + { + pat9125_PID1 = 0xff; + pat9125_PID2 = 0xff; + return; + } #endif //PAT9125_SWI2C } uint8_t pat9125_wr_reg_verify(uint8_t addr, uint8_t data) { - pat9125_wr_reg(addr, data); - return pat9125_rd_reg(addr) == data; + pat9125_wr_reg(addr, data); + return pat9125_rd_reg(addr) == data; } diff --git a/Firmware/pins.h b/Firmware/pins.h index a0b6f462f3..4df18acd15 100755 --- a/Firmware/pins.h +++ b/Firmware/pins.h @@ -42,44 +42,44 @@ //List of pins which to ignore when asked to change by gcode, 0 and 1 are RX and TX, do not mess with those! #define _E0_PINS E0_STEP_PIN, E0_DIR_PIN, E0_ENABLE_PIN, HEATER_0_PIN, #if EXTRUDERS > 1 - #define _E1_PINS E1_STEP_PIN, E1_DIR_PIN, E1_ENABLE_PIN, HEATER_1_PIN, +#define _E1_PINS E1_STEP_PIN, E1_DIR_PIN, E1_ENABLE_PIN, HEATER_1_PIN, #else - #define _E1_PINS +#define _E1_PINS #endif #if EXTRUDERS > 2 - #define _E2_PINS E2_STEP_PIN, E2_DIR_PIN, E2_ENABLE_PIN, HEATER_2_PIN, +#define _E2_PINS E2_STEP_PIN, E2_DIR_PIN, E2_ENABLE_PIN, HEATER_2_PIN, #else - #define _E2_PINS +#define _E2_PINS #endif #ifdef X_STOP_PIN - #if X_HOME_DIR < 0 - #define X_MIN_PIN X_STOP_PIN - #define X_MAX_PIN -1 - #else - #define X_MIN_PIN -1 - #define X_MAX_PIN X_STOP_PIN - #endif +#if X_HOME_DIR < 0 +#define X_MIN_PIN X_STOP_PIN +#define X_MAX_PIN -1 +#else +#define X_MIN_PIN -1 +#define X_MAX_PIN X_STOP_PIN +#endif #endif #ifdef Y_STOP_PIN - #if Y_HOME_DIR < 0 - #define Y_MIN_PIN Y_STOP_PIN - #define Y_MAX_PIN -1 - #else - #define Y_MIN_PIN -1 - #define Y_MAX_PIN Y_STOP_PIN - #endif +#if Y_HOME_DIR < 0 +#define Y_MIN_PIN Y_STOP_PIN +#define Y_MAX_PIN -1 +#else +#define Y_MIN_PIN -1 +#define Y_MAX_PIN Y_STOP_PIN +#endif #endif #ifdef Z_STOP_PIN - #if Z_HOME_DIR < 0 - #define Z_MIN_PIN Z_STOP_PIN - #define Z_MAX_PIN -1 - #else - #define Z_MIN_PIN -1 - #define Z_MAX_PIN Z_STOP_PIN - #endif +#if Z_HOME_DIR < 0 +#define Z_MIN_PIN Z_STOP_PIN +#define Z_MAX_PIN -1 +#else +#define Z_MIN_PIN -1 +#define Z_MAX_PIN Z_STOP_PIN +#endif #endif #ifdef DISABLE_MAX_ENDSTOPS diff --git a/Firmware/pins_Einsy_1_0.h b/Firmware/pins_Einsy_1_0.h index eabdb4abb4..4c5dddf79e 100755 --- a/Firmware/pins_Einsy_1_0.h +++ b/Firmware/pins_Einsy_1_0.h @@ -6,7 +6,7 @@ #define KNOWN_BOARD #ifndef __AVR_ATmega2560__ - #error Oops! Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu. +#error Oops! Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu. #endif #define TMC2130 @@ -119,7 +119,7 @@ #define SDCARDDETECT 15 #define TACH_0 79 // !!! changed from 81 (EINY03) -#define TACH_1 80 +#define TACH_1 80 // Support for an 8 bit logic analyzer, for example the Saleae. diff --git a/Firmware/pins_Rambo_1_0.h b/Firmware/pins_Rambo_1_0.h index 1e3a142c9b..c044aa2674 100755 --- a/Firmware/pins_Rambo_1_0.h +++ b/Firmware/pins_Rambo_1_0.h @@ -6,7 +6,7 @@ #define KNOWN_BOARD #ifndef __AVR_ATmega2560__ - #error Oops! Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu. +#error Oops! Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu. #endif #define PINDA_THERMISTOR @@ -64,9 +64,9 @@ #define E0_MS1_PIN 65 #define E0_MS2_PIN 66 -#ifdef SNMM - #define E_MUX0_PIN 17 - #define E_MUX1_PIN 16 +#ifdef SNMM +#define E_MUX0_PIN 17 +#define E_MUX1_PIN 16 #endif diff --git a/Firmware/pins_Rambo_1_3.h b/Firmware/pins_Rambo_1_3.h index a9a6b390d8..7a8d2bedc4 100755 --- a/Firmware/pins_Rambo_1_3.h +++ b/Firmware/pins_Rambo_1_3.h @@ -6,7 +6,7 @@ #define KNOWN_BOARD #ifndef __AVR_ATmega2560__ - #error Oops! Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu. +#error Oops! Make sure you have 'Arduino Mega 2560 or Rambo' selected from the 'Tools -> Boards' menu. #endif #define PINDA_THERMISTOR @@ -64,9 +64,9 @@ #define E0_MS1_PIN 65 #define E0_MS2_PIN 66 -#ifdef SNMM - #define E_MUX0_PIN 17 - #define E_MUX1_PIN 16 +#ifdef SNMM +#define E_MUX0_PIN 17 +#define E_MUX1_PIN 16 #endif diff --git a/Firmware/planner.cpp b/Firmware/planner.cpp index c465c938a0..b5c762eee0 100755 --- a/Firmware/planner.cpp +++ b/Firmware/planner.cpp @@ -1,53 +1,53 @@ /* planner.c - buffers movement commands and manages the acceleration profile plan Part of Grbl - + Copyright (c) 2009-2011 Simen Svale Skogsrud - + Grbl 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. - + Grbl 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 Grbl. If not, see . */ /* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */ -/* +/* Reasoning behind the mathematics in this module (in the key of 'Mathematica'): - + s == speed, a == acceleration, t == time, d == distance - + Basic definitions: - - Speed[s_, a_, t_] := s + (a*t) + + Speed[s_, a_, t_] := s + (a*t) Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t] - + Distance to reach a specific speed with a constant acceleration: - + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t] d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance() - + Speed after a given distance of travel with constant acceleration: - + Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t] - m -> Sqrt[2 a d + s^2] - + m -> Sqrt[2 a d + s^2] + DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2] - + When to start braking (di) to reach a specified destionation speed (s2) after accelerating from initial speed s1 without ever stopping at a plateau: - + Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di] di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance() - + IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a) */ @@ -83,9 +83,9 @@ 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, + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0, }; #endif // #ifdef ENABLE_AUTO_BED_LEVELING @@ -114,7 +114,7 @@ volatile unsigned char block_buffer_head; // Index of the next block t volatile unsigned char block_buffer_tail; // Index of the block to process now #ifdef PLANNER_DIAGNOSTICS -// Diagnostic function: Minimum number of planned moves since the last +// Diagnostic function: Minimum number of planned moves since the last static uint8_t g_cntr_planner_queue_min = 0; #endif /* PLANNER_DIAGNOSTICS */ @@ -126,159 +126,159 @@ float extrude_min_temp=EXTRUDE_MINTEMP; #endif #ifdef LIN_ADVANCE - float extruder_advance_k = LIN_ADVANCE_K, - advance_ed_ratio = LIN_ADVANCE_E_D_RATIO, - position_float[NUM_AXIS] = { 0 }; +float extruder_advance_k = LIN_ADVANCE_K, + advance_ed_ratio = LIN_ADVANCE_E_D_RATIO, + position_float[NUM_AXIS] = { 0 }; #endif // Returns the index of the next block in the ring buffer // NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication. static inline int8_t next_block_index(int8_t block_index) { - if (++ block_index == BLOCK_BUFFER_SIZE) - block_index = 0; - return block_index; + if (++ block_index == BLOCK_BUFFER_SIZE) + block_index = 0; + return block_index; } // Returns the index of the previous block in the ring buffer static inline int8_t prev_block_index(int8_t block_index) { - if (block_index == 0) - block_index = BLOCK_BUFFER_SIZE; - -- block_index; - return block_index; + if (block_index == 0) + block_index = BLOCK_BUFFER_SIZE; + -- block_index; + return block_index; } //=========================================================================== //=============================functions ============================ //=========================================================================== -// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the +// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the // given acceleration: FORCE_INLINE float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration) { - if (acceleration!=0) { - return((target_rate*target_rate-initial_rate*initial_rate)/ - (2.0*acceleration)); - } - else { - return 0.0; // acceleration was 0, set acceleration distance to 0 - } + if (acceleration!=0) { + return((target_rate*target_rate-initial_rate*initial_rate)/ + (2.0*acceleration)); + } + else { + return 0.0; // acceleration was 0, set acceleration distance to 0 + } } -// This function gives you the point at which you must start braking (at the rate of -acceleration) if +// This function gives you the point at which you must start braking (at the rate of -acceleration) if // you started at speed initial_rate and accelerated until this point and want to end at the final_rate after // a total travel of distance. This can be used to compute the intersection point between acceleration and // deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed) -FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) +FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) { - if (acceleration!=0) { - return((2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ - (4.0*acceleration) ); - } - else { - return 0.0; // acceleration was 0, set intersection distance to 0 - } + if (acceleration!=0) { + return((2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/ + (4.0*acceleration) ); + } + else { + return 0.0; // acceleration was 0, set intersection distance to 0 + } } // Minimum stepper rate 120Hz. #define MINIMAL_STEP_RATE 120 // Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors. -void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) +void calculate_trapezoid_for_block(block_t *block, float entry_speed, float exit_speed) { - // These two lines are the only floating point calculations performed in this routine. - // initial_rate, final_rate in Hz. - // Minimum stepper rate 120Hz, maximum 40kHz. If the stepper rate goes above 10kHz, - // the stepper interrupt routine groups the pulses by 2 or 4 pulses per interrupt tick. - uint32_t initial_rate = ceil(entry_speed * block->speed_factor); // (step/min) - uint32_t final_rate = ceil(exit_speed * block->speed_factor); // (step/min) - - // Limit minimal step rate (Otherwise the timer will overflow.) - if (initial_rate < MINIMAL_STEP_RATE) - initial_rate = MINIMAL_STEP_RATE; - if (initial_rate > block->nominal_rate) - initial_rate = block->nominal_rate; - if (final_rate < MINIMAL_STEP_RATE) - final_rate = MINIMAL_STEP_RATE; - if (final_rate > block->nominal_rate) - final_rate = block->nominal_rate; - - uint32_t acceleration = block->acceleration_st; - if (acceleration == 0) - // Don't allow zero acceleration. - acceleration = 1; - // estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration) - // (target_rate*target_rate-initial_rate*initial_rate)/(2.0*acceleration)); - uint32_t initial_rate_sqr = initial_rate*initial_rate; - //FIXME assert that this result fits a 64bit unsigned int. - uint32_t nominal_rate_sqr = block->nominal_rate*block->nominal_rate; - uint32_t final_rate_sqr = final_rate*final_rate; - uint32_t acceleration_x2 = acceleration << 1; - // ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration)); - uint32_t accelerate_steps = (nominal_rate_sqr - initial_rate_sqr + acceleration_x2 - 1) / acceleration_x2; - // floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration)); - uint32_t decelerate_steps = (nominal_rate_sqr - final_rate_sqr) / acceleration_x2; - uint32_t accel_decel_steps = accelerate_steps + decelerate_steps; - // Size of Plateau of Nominal Rate. - uint32_t plateau_steps = 0; - - // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will - // 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 (accel_decel_steps < block->step_event_count.wide) { - plateau_steps = block->step_event_count.wide - accel_decel_steps; - } else { - uint32_t acceleration_x4 = acceleration << 2; - // Avoid negative numbers - if (final_rate_sqr >= initial_rate_sqr) { - // accelerate_steps = ceil(intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count)); - // intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) - // (2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4.0*acceleration); + // These two lines are the only floating point calculations performed in this routine. + // initial_rate, final_rate in Hz. + // Minimum stepper rate 120Hz, maximum 40kHz. If the stepper rate goes above 10kHz, + // the stepper interrupt routine groups the pulses by 2 or 4 pulses per interrupt tick. + uint32_t initial_rate = ceil(entry_speed * block->speed_factor); // (step/min) + uint32_t final_rate = ceil(exit_speed * block->speed_factor); // (step/min) + + // Limit minimal step rate (Otherwise the timer will overflow.) + if (initial_rate < MINIMAL_STEP_RATE) + initial_rate = MINIMAL_STEP_RATE; + if (initial_rate > block->nominal_rate) + initial_rate = block->nominal_rate; + if (final_rate < MINIMAL_STEP_RATE) + final_rate = MINIMAL_STEP_RATE; + if (final_rate > block->nominal_rate) + final_rate = block->nominal_rate; + + uint32_t acceleration = block->acceleration_st; + if (acceleration == 0) + // Don't allow zero acceleration. + acceleration = 1; + // estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration) + // (target_rate*target_rate-initial_rate*initial_rate)/(2.0*acceleration)); + uint32_t initial_rate_sqr = initial_rate*initial_rate; + //FIXME assert that this result fits a 64bit unsigned int. + uint32_t nominal_rate_sqr = block->nominal_rate*block->nominal_rate; + uint32_t final_rate_sqr = final_rate*final_rate; + uint32_t acceleration_x2 = acceleration << 1; + // ceil(estimate_acceleration_distance(initial_rate, block->nominal_rate, acceleration)); + uint32_t accelerate_steps = (nominal_rate_sqr - initial_rate_sqr + acceleration_x2 - 1) / acceleration_x2; + // floor(estimate_acceleration_distance(block->nominal_rate, final_rate, -acceleration)); + uint32_t decelerate_steps = (nominal_rate_sqr - final_rate_sqr) / acceleration_x2; + uint32_t accel_decel_steps = accelerate_steps + decelerate_steps; + // Size of Plateau of Nominal Rate. + uint32_t plateau_steps = 0; + + // Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will + // 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 (accel_decel_steps < block->step_event_count.wide) { + plateau_steps = block->step_event_count.wide - accel_decel_steps; + } else { + uint32_t acceleration_x4 = acceleration << 2; + // Avoid negative numbers + if (final_rate_sqr >= initial_rate_sqr) { + // accelerate_steps = ceil(intersection_distance(initial_rate, final_rate, acceleration, block->step_event_count)); + // intersection_distance(float initial_rate, float final_rate, float acceleration, float distance) + // (2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/(4.0*acceleration); #if 0 - accelerate_steps = (block->step_event_count >> 1) + (final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1 + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4; + accelerate_steps = (block->step_event_count >> 1) + (final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1 + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4; #else - accelerate_steps = final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1; - if (block->step_event_count.wide & 1) - accelerate_steps += acceleration_x2; - accelerate_steps /= acceleration_x4; - accelerate_steps += (block->step_event_count.wide >> 1); + accelerate_steps = final_rate_sqr - initial_rate_sqr + acceleration_x4 - 1; + if (block->step_event_count.wide & 1) + accelerate_steps += acceleration_x2; + accelerate_steps /= acceleration_x4; + accelerate_steps += (block->step_event_count.wide >> 1); #endif - if (accelerate_steps > block->step_event_count.wide) - accelerate_steps = block->step_event_count.wide; - } else { + if (accelerate_steps > block->step_event_count.wide) + accelerate_steps = block->step_event_count.wide; + } else { #if 0 - decelerate_steps = (block->step_event_count >> 1) + (initial_rate_sqr - final_rate_sqr + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4; + decelerate_steps = (block->step_event_count >> 1) + (initial_rate_sqr - final_rate_sqr + (block->step_event_count & 1) * acceleration_x2) / acceleration_x4; #else - decelerate_steps = initial_rate_sqr - final_rate_sqr; - if (block->step_event_count.wide & 1) - decelerate_steps += acceleration_x2; - decelerate_steps /= acceleration_x4; - decelerate_steps += (block->step_event_count.wide >> 1); + decelerate_steps = initial_rate_sqr - final_rate_sqr; + if (block->step_event_count.wide & 1) + decelerate_steps += acceleration_x2; + decelerate_steps /= acceleration_x4; + decelerate_steps += (block->step_event_count.wide >> 1); #endif - if (decelerate_steps > block->step_event_count.wide) - decelerate_steps = block->step_event_count.wide; - accelerate_steps = block->step_event_count.wide - decelerate_steps; + if (decelerate_steps > block->step_event_count.wide) + decelerate_steps = block->step_event_count.wide; + accelerate_steps = block->step_event_count.wide - decelerate_steps; + } + } + + CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section + // This block locks the interrupts globally for 4.38 us, + // which corresponds to a maximum repeat frequency of 228.57 kHz. + // This blocking is safe in the context of a 10kHz stepper driver interrupt + // or a 115200 Bd serial line receive interrupt, which will not trigger faster than 12kHz. + if (! block->busy) { // Don't update variables if block is busy. + block->accelerate_until = accelerate_steps; + block->decelerate_after = accelerate_steps+plateau_steps; + block->initial_rate = initial_rate; + block->final_rate = final_rate; } - } - - CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section - // This block locks the interrupts globally for 4.38 us, - // which corresponds to a maximum repeat frequency of 228.57 kHz. - // This blocking is safe in the context of a 10kHz stepper driver interrupt - // or a 115200 Bd serial line receive interrupt, which will not trigger faster than 12kHz. - if (! block->busy) { // Don't update variables if block is busy. - block->accelerate_until = accelerate_steps; - block->decelerate_after = accelerate_steps+plateau_steps; - block->initial_rate = initial_rate; - block->final_rate = final_rate; - } - CRITICAL_SECTION_END; + CRITICAL_SECTION_END; } -// Calculates the maximum allowable entry speed, when you must be able to reach target_velocity using the +// Calculates the maximum allowable entry speed, when you must be able to reach target_velocity using the // decceleration within the allotted distance. -FORCE_INLINE float max_allowable_entry_speed(float decceleration, float target_velocity, float distance) +FORCE_INLINE float max_allowable_entry_speed(float decceleration, float target_velocity, float distance) { // assert(decceleration < 0); return sqrt(target_velocity*target_velocity-2*decceleration*distance); @@ -286,17 +286,17 @@ FORCE_INLINE float max_allowable_entry_speed(float decceleration, float target_v // Recalculates the motion plan according to the following algorithm: // -// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) +// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor) // so that: // a. The junction jerk is within the set limit -// b. No speed reduction within one block requires faster deceleration than the one, true constant +// b. No speed reduction within one block requires faster deceleration than the one, true constant // acceleration. -// 2. Go over every block in chronological order and dial down junction speed reduction values if -// a. The speed increase within one block would require faster accelleration than the one, true +// 2. Go over every block in chronological order and dial down junction speed reduction values if +// a. The speed increase within one block would require faster accelleration than the one, true // constant acceleration. // -// When these stages are complete all blocks have an entry_factor that will allow all speed changes to -// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than +// When these stages are complete all blocks have an entry_factor that will allow all speed changes to +// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than // the set limit. Finally it will: // // 3. Recalculate trapezoids for all blocks. @@ -308,20 +308,20 @@ FORCE_INLINE float max_allowable_entry_speed(float decceleration, float target_v // Following sources may be used to optimize the 8-bit AVR code: // http://www.mikrocontroller.net/articles/AVR_Arithmetik // http://darcy.rsgc.on.ca/ACES/ICE4M/FixedPoint/avrfix.pdf -// +// // https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/avr/lib1funcs-fixed.S // https://gcc.gnu.org/onlinedocs/gcc/Fixed-Point.html // https://gcc.gnu.org/onlinedocs/gccint/Fixed-point-fractional-library-routines.html -// +// // https://ucexperiment.wordpress.com/2015/04/04/arduino-s15-16-fixed-point-math-routines/ // https://mekonik.wordpress.com/2009/03/18/arduino-avr-gcc-multiplication/ // https://github.com/rekka/avrmultiplication -// +// // https://people.ece.cornell.edu/land/courses/ece4760/Math/Floating_point/ // https://courses.cit.cornell.edu/ee476/Math/ // https://courses.cit.cornell.edu/ee476/Math/GCC644/fixedPt/multASM.S // -void planner_recalculate(const float &safe_final_speed) +void planner_recalculate(const float &safe_final_speed) { // Reverse pass // Make a local copy of block_buffer_tail, because the interrupt can alter it @@ -367,9 +367,9 @@ void planner_recalculate(const float &safe_final_speed) // therefore an optimized assembly 24bit x 24bit -> 32bit multiply would be more than sufficient // together with an assembly 32bit->16bit sqrt function. current->entry_speed = ((current->flag & BLOCK_FLAG_NOMINAL_LENGTH) || current->max_entry_speed <= next->entry_speed) ? - current->max_entry_speed : - // min(current->max_entry_speed, sqrt(next->entry_speed*next->entry_speed+2*current->acceleration*current->millimeters)); - min(current->max_entry_speed, max_allowable_entry_speed(-current->acceleration,next->entry_speed,current->millimeters)); + current->max_entry_speed : + // min(current->max_entry_speed, sqrt(next->entry_speed*next->entry_speed+2*current->acceleration*current->millimeters)); + min(current->max_entry_speed, max_allowable_entry_speed(-current->acceleration,next->entry_speed,current->millimeters)); current->flag |= BLOCK_FLAG_RECALCULATE; } next = current; @@ -421,17 +421,17 @@ void planner_recalculate(const float &safe_final_speed) } void plan_init() { - block_buffer_head = 0; - block_buffer_tail = 0; - memset(position, 0, sizeof(position)); // clear position + block_buffer_head = 0; + block_buffer_tail = 0; + memset(position, 0, sizeof(position)); // clear position #ifdef LIN_ADVANCE - memset(position_float, 0, sizeof(position)); // clear position + memset(position_float, 0, sizeof(position)); // clear position #endif - previous_speed[0] = 0.0; - previous_speed[1] = 0.0; - previous_speed[2] = 0.0; - previous_speed[3] = 0.0; - previous_nominal_speed = 0.0; + previous_speed[0] = 0.0; + previous_speed[1] = 0.0; + previous_speed[2] = 0.0; + previous_speed[3] = 0.0; + previous_nominal_speed = 0.0; } @@ -440,118 +440,118 @@ void plan_init() { #ifdef AUTOTEMP void getHighESpeed() { - static float oldt=0; - if(!autotemp_enabled){ - return; - } - if(degTargetHotend0()+2high) - { - high=se; - } + static float oldt=0; + if(!autotemp_enabled) { + return; } - block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); - } - - float g=autotemp_min+high*autotemp_factor; - float t=g; - if(tautotemp_max) - t=autotemp_max; - if(oldt>t) - { - t=AUTOTEMP_OLDWEIGHT*oldt+(1-AUTOTEMP_OLDWEIGHT)*t; - } - oldt=t; - setTargetHotend0(t); + if(degTargetHotend0()+2high) + { + high=se; + } + } + block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); + } + + float g=autotemp_min+high*autotemp_factor; + float t=g; + if(tautotemp_max) + t=autotemp_max; + if(oldt>t) + { + t=AUTOTEMP_OLDWEIGHT*oldt+(1-AUTOTEMP_OLDWEIGHT)*t; + } + oldt=t; + setTargetHotend0(t); } #endif bool e_active() { - unsigned char e_active = 0; - block_t *block; - if(block_buffer_tail != block_buffer_head) - { - uint8_t block_index = block_buffer_tail; - while(block_index != block_buffer_head) + unsigned char e_active = 0; + block_t *block; + if(block_buffer_tail != block_buffer_head) { - block = &block_buffer[block_index]; - if(block->steps_e.wide != 0) e_active++; - block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); + uint8_t block_index = block_buffer_tail; + while(block_index != block_buffer_head) + { + block = &block_buffer[block_index]; + if(block->steps_e.wide != 0) e_active++; + block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); + } } - } - return (e_active > 0) ? true : false ; + return (e_active > 0) ? true : false ; } void check_axes_activity() { - unsigned char x_active = 0; - unsigned char y_active = 0; - unsigned char z_active = 0; - unsigned char e_active = 0; - unsigned char tail_fan_speed = fanSpeed; - block_t *block; - - if(block_buffer_tail != block_buffer_head) - { - uint8_t block_index = block_buffer_tail; - tail_fan_speed = block_buffer[block_index].fan_speed; - while(block_index != block_buffer_head) + unsigned char x_active = 0; + unsigned char y_active = 0; + unsigned char z_active = 0; + unsigned char e_active = 0; + unsigned char tail_fan_speed = fanSpeed; + block_t *block; + + if(block_buffer_tail != block_buffer_head) + { + uint8_t block_index = block_buffer_tail; + tail_fan_speed = block_buffer[block_index].fan_speed; + while(block_index != block_buffer_head) + { + block = &block_buffer[block_index]; + if(block->steps_x.wide != 0) x_active++; + if(block->steps_y.wide != 0) y_active++; + if(block->steps_z.wide != 0) z_active++; + if(block->steps_e.wide != 0) e_active++; + block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); + } + } + if((DISABLE_X) && (x_active == 0)) disable_x(); + if((DISABLE_Y) && (y_active == 0)) disable_y(); + if((DISABLE_Z) && (z_active == 0)) disable_z(); + if((DISABLE_E) && (e_active == 0)) { - block = &block_buffer[block_index]; - if(block->steps_x.wide != 0) x_active++; - if(block->steps_y.wide != 0) y_active++; - if(block->steps_z.wide != 0) z_active++; - if(block->steps_e.wide != 0) e_active++; - block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1); + disable_e0(); + disable_e1(); + disable_e2(); } - } - if((DISABLE_X) && (x_active == 0)) disable_x(); - if((DISABLE_Y) && (y_active == 0)) disable_y(); - if((DISABLE_Z) && (z_active == 0)) disable_z(); - if((DISABLE_E) && (e_active == 0)) - { - disable_e0(); - disable_e1(); - disable_e2(); - } #if defined(FAN_PIN) && FAN_PIN > -1 - #ifdef FAN_KICKSTART_TIME +#ifdef FAN_KICKSTART_TIME static unsigned long fan_kick_end; if (tail_fan_speed) { - if (fan_kick_end == 0) { - // Just starting up fan - run at full power. - fan_kick_end = millis() + FAN_KICKSTART_TIME; - tail_fan_speed = 255; - } else if (fan_kick_end > millis()) - // Fan still spinning up. - tail_fan_speed = 255; + if (fan_kick_end == 0) { + // Just starting up fan - run at full power. + fan_kick_end = millis() + FAN_KICKSTART_TIME; + tail_fan_speed = 255; + } else if (fan_kick_end > millis()) + // Fan still spinning up. + tail_fan_speed = 255; } else { - fan_kick_end = 0; + fan_kick_end = 0; } - #endif//FAN_KICKSTART_TIME - #ifdef FAN_SOFT_PWM - fanSpeedSoftPwm = tail_fan_speed; - #else - analogWrite(FAN_PIN,tail_fan_speed); - #endif//!FAN_SOFT_PWM +#endif//FAN_KICKSTART_TIME +#ifdef FAN_SOFT_PWM + fanSpeedSoftPwm = tail_fan_speed; +#else + analogWrite(FAN_PIN,tail_fan_speed); +#endif//!FAN_SOFT_PWM #endif//FAN_PIN > -1 #ifdef AUTOTEMP - getHighESpeed(); + getHighESpeed(); #endif } @@ -570,9 +570,9 @@ void planner_abort_soft() #ifdef PLANNER_DIAGNOSTICS static inline void planner_update_queue_min_counter() { - uint8_t new_counter = moves_planned(); - if (new_counter < g_cntr_planner_queue_min) - g_cntr_planner_queue_min = new_counter; + uint8_t new_counter = moves_planned(); + if (new_counter < g_cntr_planner_queue_min) + g_cntr_planner_queue_min = new_counter; } #endif /* PLANNER_DIAGNOSTICS */ @@ -608,17 +608,17 @@ void planner_abort_hard() current_position[Z_AXIS] -= mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS]); else { float t = float(step_events_completed) / float(current_block->step_event_count); - float vec[3] = { - current_block->steps_x / cs.axis_steps_per_unit[X_AXIS], - current_block->steps_y / cs.axis_steps_per_unit[Y_AXIS], - current_block->steps_z / cs.axis_steps_per_unit[Z_AXIS] + float vec[3] = { + current_block->steps_x / cs.axis_steps_per_unit[X_AXIS], + current_block->steps_y / cs.axis_steps_per_unit[Y_AXIS], + current_block->steps_z / cs.axis_steps_per_unit[Z_AXIS] }; float pos1[3], pos2[3]; for (int8_t i = 0; i < 3; ++ i) { - if (current_block->direction_bits & (1<direction_bits & (1<cs.axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH) - { - position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(_i(" cold extrusion prevented"));////MSG_ERR_COLD_EXTRUDE_STOP c=0 r=0 + } + +#ifdef PREVENT_LENGTHY_EXTRUDE + if(labs(target[E_AXIS]-position[E_AXIS])>cs.axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH) + { + position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part #ifdef LIN_ADVANCE - position_float[E_AXIS] = e; - de_float = 0; + position_float[E_AXIS] = e; + de_float = 0; +#endif + SERIAL_ECHO_START; + SERIAL_ECHOLNRPGM(_n(" too long extrusion prevented"));////MSG_ERR_LONG_EXTRUDE_STOP c=0 r=0 + } #endif - SERIAL_ECHO_START; - SERIAL_ECHOLNRPGM(_n(" too long extrusion prevented"));////MSG_ERR_LONG_EXTRUDE_STOP c=0 r=0 } - #endif - } - #endif +#endif - // Prepare to set up new block - block_t *block = &block_buffer[block_buffer_head]; + // Prepare to set up new block + block_t *block = &block_buffer[block_buffer_head]; - // Set sdlen for calculating sd position - block->sdlen = 0; + // Set sdlen for calculating sd position + block->sdlen = 0; - // Mark block as not busy (Not executed by the stepper interrupt, could be still tinkered with.) - block->busy = false; + // Mark block as not busy (Not executed by the stepper interrupt, could be still tinkered with.) + block->busy = false; - // Number of steps for each axis + // Number of steps for each axis #ifndef COREXY // default non-h-bot planning -block->steps_x.wide = labs(target[X_AXIS]-position[X_AXIS]); -block->steps_y.wide = labs(target[Y_AXIS]-position[Y_AXIS]); + block->steps_x.wide = labs(target[X_AXIS]-position[X_AXIS]); + block->steps_y.wide = labs(target[Y_AXIS]-position[Y_AXIS]); #else // corexy planning // these equations follow the form of the dA and dB equations on http://www.corexy.com/theory.html -block->steps_x.wide = labs((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS])); -block->steps_y.wide = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS])); + block->steps_x.wide = labs((target[X_AXIS]-position[X_AXIS]) + (target[Y_AXIS]-position[Y_AXIS])); + block->steps_y.wide = labs((target[X_AXIS]-position[X_AXIS]) - (target[Y_AXIS]-position[Y_AXIS])); #endif - block->steps_z.wide = labs(target[Z_AXIS]-position[Z_AXIS]); - block->steps_e.wide = labs(target[E_AXIS]-position[E_AXIS]); - block->step_event_count.wide = max(block->steps_x.wide, max(block->steps_y.wide, max(block->steps_z.wide, block->steps_e.wide))); + block->steps_z.wide = labs(target[Z_AXIS]-position[Z_AXIS]); + block->steps_e.wide = labs(target[E_AXIS]-position[E_AXIS]); + block->step_event_count.wide = max(block->steps_x.wide, max(block->steps_y.wide, max(block->steps_z.wide, block->steps_e.wide))); - // Bail if this is a zero-length block - if (block->step_event_count.wide <= dropsegments) - { + // Bail if this is a zero-length block + if (block->step_event_count.wide <= dropsegments) + { #ifdef PLANNER_DIAGNOSTICS - planner_update_queue_min_counter(); + planner_update_queue_min_counter(); #endif /* PLANNER_DIAGNOSTICS */ - return; - } + return; + } - block->fan_speed = fanSpeed; + block->fan_speed = fanSpeed; - // Compute direction bits for this block - block->direction_bits = 0; + // Compute direction bits for this block + block->direction_bits = 0; #ifndef COREXY - if (target[X_AXIS] < position[X_AXIS]) - { - block->direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<direction_bits |= (1<active_extruder = extruder; - - //enable active axes - #ifdef COREXY - if((block->steps_x.wide != 0) || (block->steps_y.wide != 0)) - { - enable_x(); - enable_y(); - } - #else - if(block->steps_x.wide != 0) enable_x(); - if(block->steps_y.wide != 0) enable_y(); - #endif - if(block->steps_z.wide != 0) enable_z(); - - // Enable extruder(s) - if(block->steps_e.wide != 0) - { - if (DISABLE_INACTIVE_EXTRUDER) //enable only selected extruder + if (target[Z_AXIS] < position[Z_AXIS]) + { + block->direction_bits |= (1<direction_bits |= (1<active_extruder = extruder; - if(g_uc_extruder_last_move[0] > 0) g_uc_extruder_last_move[0]--; - if(g_uc_extruder_last_move[1] > 0) g_uc_extruder_last_move[1]--; - if(g_uc_extruder_last_move[2] > 0) g_uc_extruder_last_move[2]--; - - switch(extruder) - { - case 0: - enable_e0(); - g_uc_extruder_last_move[0] = BLOCK_BUFFER_SIZE*2; - - if(g_uc_extruder_last_move[1] == 0) {disable_e1();} - if(g_uc_extruder_last_move[2] == 0) {disable_e2();} - break; - case 1: - enable_e1(); - g_uc_extruder_last_move[1] = BLOCK_BUFFER_SIZE*2; - - if(g_uc_extruder_last_move[0] == 0) {disable_e0();} - if(g_uc_extruder_last_move[2] == 0) {disable_e2();} - break; - case 2: - enable_e2(); - g_uc_extruder_last_move[2] = BLOCK_BUFFER_SIZE*2; - - if(g_uc_extruder_last_move[0] == 0) {disable_e0();} - if(g_uc_extruder_last_move[1] == 0) {disable_e1();} - break; - } + //enable active axes +#ifdef COREXY + if((block->steps_x.wide != 0) || (block->steps_y.wide != 0)) + { + enable_x(); + enable_y(); } - else //enable all +#else + if(block->steps_x.wide != 0) enable_x(); + if(block->steps_y.wide != 0) enable_y(); +#endif + if(block->steps_z.wide != 0) enable_z(); + + // Enable extruder(s) + if(block->steps_e.wide != 0) { - enable_e0(); - enable_e1(); - enable_e2(); + if (DISABLE_INACTIVE_EXTRUDER) //enable only selected extruder + { + + if(g_uc_extruder_last_move[0] > 0) g_uc_extruder_last_move[0]--; + if(g_uc_extruder_last_move[1] > 0) g_uc_extruder_last_move[1]--; + if(g_uc_extruder_last_move[2] > 0) g_uc_extruder_last_move[2]--; + + switch(extruder) + { + case 0: + enable_e0(); + g_uc_extruder_last_move[0] = BLOCK_BUFFER_SIZE*2; + + if(g_uc_extruder_last_move[1] == 0) { + disable_e1(); + } + if(g_uc_extruder_last_move[2] == 0) { + disable_e2(); + } + break; + case 1: + enable_e1(); + g_uc_extruder_last_move[1] = BLOCK_BUFFER_SIZE*2; + + if(g_uc_extruder_last_move[0] == 0) { + disable_e0(); + } + if(g_uc_extruder_last_move[2] == 0) { + disable_e2(); + } + break; + case 2: + enable_e2(); + g_uc_extruder_last_move[2] = BLOCK_BUFFER_SIZE*2; + + if(g_uc_extruder_last_move[0] == 0) { + disable_e0(); + } + if(g_uc_extruder_last_move[1] == 0) { + disable_e1(); + } + break; + } + } + else //enable all + { + enable_e0(); + enable_e1(); + enable_e2(); + } } - } - - if (block->steps_e.wide == 0) - { - if(feed_ratesteps_e.wide == 0) + { + if(feed_ratesteps_x.wide <=dropsegments && block->steps_y.wide <=dropsegments && block->steps_z.wide <=dropsegments ) - { - block->millimeters = fabs(delta_mm[E_AXIS]); - } - else - { - #ifndef COREXY - block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS])); - #else - block->millimeters = sqrt(square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD]) + square(delta_mm[Z_AXIS])); - #endif - } - float inverse_millimeters = 1.0/block->millimeters; // Inverse millimeters to remove multiple divides +#endif + delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/cs.axis_steps_per_unit[Z_AXIS]; + delta_mm[E_AXIS] = (target[E_AXIS]-position[E_AXIS])/cs.axis_steps_per_unit[E_AXIS]; + if ( block->steps_x.wide <=dropsegments && block->steps_y.wide <=dropsegments && block->steps_z.wide <=dropsegments ) + { + block->millimeters = fabs(delta_mm[E_AXIS]); + } + else + { +#ifndef COREXY + block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS])); +#else + block->millimeters = sqrt(square(delta_mm[X_HEAD]) + square(delta_mm[Y_HEAD]) + square(delta_mm[Z_AXIS])); +#endif + } + float inverse_millimeters = 1.0/block->millimeters; // Inverse millimeters to remove multiple divides // Calculate speed in mm/second for each axis. No divide by zero due to previous checks. - float inverse_second = feed_rate * inverse_millimeters; + float inverse_second = feed_rate * inverse_millimeters; - int moves_queued = moves_planned(); + int moves_queued = moves_planned(); - // slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill + // slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill #ifdef SLOWDOWN - //FIXME Vojtech: Why moves_queued > 1? Why not >=1? - // Can we somehow differentiate the filling of the buffer at the start of a g-code from a buffer draining situation? - if (moves_queued > 1 && moves_queued < (BLOCK_BUFFER_SIZE >> 1)) { - // segment time in micro seconds - unsigned long segment_time = lround(1000000.0/inverse_second); - if (segment_time < cs.minsegmenttime) - // buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more. - inverse_second=1000000.0/(segment_time+lround(2*(cs.minsegmenttime-segment_time)/moves_queued)); - } + //FIXME Vojtech: Why moves_queued > 1? Why not >=1? + // Can we somehow differentiate the filling of the buffer at the start of a g-code from a buffer draining situation? + if (moves_queued > 1 && moves_queued < (BLOCK_BUFFER_SIZE >> 1)) { + // segment time in micro seconds + unsigned long segment_time = lround(1000000.0/inverse_second); + if (segment_time < cs.minsegmenttime) + // buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more. + inverse_second=1000000.0/(segment_time+lround(2*(cs.minsegmenttime-segment_time)/moves_queued)); + } #endif // SLOWDOWN - block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0 - block->nominal_rate = ceil(block->step_event_count.wide * inverse_second); // (step/sec) Always > 0 + block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0 + block->nominal_rate = ceil(block->step_event_count.wide * inverse_second); // (step/sec) Always > 0 - // Calculate and limit speed in mm/sec for each axis - float current_speed[4]; - float speed_factor = 1.0; //factor <=1 do decrease speed + // Calculate and limit speed in mm/sec for each axis + float current_speed[4]; + float speed_factor = 1.0; //factor <=1 do decrease speed // maxlimit_status &= ~0xf; - for(int i=0; i < 4; i++) - { - current_speed[i] = delta_mm[i] * inverse_second; - if(fabs(current_speed[i]) > max_feedrate[i]) - { - speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i])); - maxlimit_status |= (1 << i); - } - } - - // Correct the speed - if( speed_factor < 1.0) - { - for(unsigned char i=0; i < 4; i++) + for(int i=0; i < 4; i++) + { + current_speed[i] = delta_mm[i] * inverse_second; + if(fabs(current_speed[i]) > max_feedrate[i]) + { + speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i])); + maxlimit_status |= (1 << i); + } + } + + // Correct the speed + if( speed_factor < 1.0) + { + for(unsigned char i=0; i < 4; i++) + { + current_speed[i] *= speed_factor; + } + block->nominal_speed *= speed_factor; + block->nominal_rate *= speed_factor; + } + + // Compute and limit the acceleration rate for the trapezoid generator. + // block->step_event_count ... event count of the fastest axis + // block->millimeters ... Euclidian length of the XYZ movement or the E length, if no XYZ movement. + float steps_per_mm = block->step_event_count.wide/block->millimeters; + if(block->steps_x.wide == 0 && block->steps_y.wide == 0 && block->steps_z.wide == 0) { - current_speed[i] *= speed_factor; + block->acceleration_st = ceil(cs.retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 } - block->nominal_speed *= speed_factor; - block->nominal_rate *= speed_factor; - } - - // Compute and limit the acceleration rate for the trapezoid generator. - // block->step_event_count ... event count of the fastest axis - // block->millimeters ... Euclidian length of the XYZ movement or the E length, if no XYZ movement. - float steps_per_mm = block->step_event_count.wide/block->millimeters; - if(block->steps_x.wide == 0 && block->steps_y.wide == 0 && block->steps_z.wide == 0) - { - block->acceleration_st = ceil(cs.retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 - } - else - { - block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 - // Limit acceleration per axis - //FIXME Vojtech: One shall rather limit a projection of the acceleration vector instead of using the limit. - if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS]) - { block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; maxlimit_status |= (X_AXIS_MASK << 4); } - if(((float)block->acceleration_st * (float)block->steps_y.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[Y_AXIS]) - { block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; maxlimit_status |= (Y_AXIS_MASK << 4); } - if(((float)block->acceleration_st * (float)block->steps_e.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[E_AXIS]) - { block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; maxlimit_status |= (Z_AXIS_MASK << 4); } - if(((float)block->acceleration_st * (float)block->steps_z.wide / (float)block->step_event_count.wide ) > axis_steps_per_sqr_second[Z_AXIS]) - { block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; maxlimit_status |= (E_AXIS_MASK << 4); } - } - // Acceleration of the segment, in mm/sec^2 - block->acceleration = block->acceleration_st / steps_per_mm; + else + { + block->acceleration_st = ceil(cs.acceleration * steps_per_mm); // convert to: acceleration steps/sec^2 + // Limit acceleration per axis + //FIXME Vojtech: One shall rather limit a projection of the acceleration vector instead of using the limit. + if(((float)block->acceleration_st * (float)block->steps_x.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[X_AXIS]) + { + block->acceleration_st = axis_steps_per_sqr_second[X_AXIS]; + maxlimit_status |= (X_AXIS_MASK << 4); + } + if(((float)block->acceleration_st * (float)block->steps_y.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[Y_AXIS]) + { + block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS]; + maxlimit_status |= (Y_AXIS_MASK << 4); + } + if(((float)block->acceleration_st * (float)block->steps_e.wide / (float)block->step_event_count.wide) > axis_steps_per_sqr_second[E_AXIS]) + { + block->acceleration_st = axis_steps_per_sqr_second[E_AXIS]; + maxlimit_status |= (Z_AXIS_MASK << 4); + } + if(((float)block->acceleration_st * (float)block->steps_z.wide / (float)block->step_event_count.wide ) > axis_steps_per_sqr_second[Z_AXIS]) + { + block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS]; + maxlimit_status |= (E_AXIS_MASK << 4); + } + } + // Acceleration of the segment, in mm/sec^2 + block->acceleration = block->acceleration_st / steps_per_mm; #if 0 - // Oversample diagonal movements by a power of 2 up to 8x - // to achieve more accurate diagonal movements. - uint8_t bresenham_oversample = 1; - for (uint8_t i = 0; i < 3; ++ i) { - if (block->nominal_rate >= 5000) // 5kHz - break; - block->nominal_rate << 1; - bresenham_oversample << 1; - block->step_event_count << 1; - } - if (bresenham_oversample > 1) - // Lower the acceleration steps/sec^2 to account for the oversampling. - block->acceleration_st = (block->acceleration_st + (bresenham_oversample >> 1)) / bresenham_oversample; + // Oversample diagonal movements by a power of 2 up to 8x + // to achieve more accurate diagonal movements. + uint8_t bresenham_oversample = 1; + for (uint8_t i = 0; i < 3; ++ i) { + if (block->nominal_rate >= 5000) // 5kHz + break; + block->nominal_rate << 1; + bresenham_oversample << 1; + block->step_event_count << 1; + } + if (bresenham_oversample > 1) + // Lower the acceleration steps/sec^2 to account for the oversampling. + block->acceleration_st = (block->acceleration_st + (bresenham_oversample >> 1)) / bresenham_oversample; #endif - block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0))); - - // Start with a safe speed. - // Safe speed is the speed, from which the machine may halt to stop immediately. - float safe_speed = block->nominal_speed; - bool limited = false; - for (uint8_t axis = 0; axis < 4; ++ axis) { - float jerk = fabs(current_speed[axis]); - if (jerk > cs.max_jerk[axis]) { - // The actual jerk is lower, if it has been limited by the XY jerk. - if (limited) { - // Spare one division by a following gymnastics: - // Instead of jerk *= safe_speed / block->nominal_speed, - // multiply max_jerk[axis] by the divisor. - jerk *= safe_speed; - float mjerk = cs.max_jerk[axis] * block->nominal_speed; - if (jerk > mjerk) { - safe_speed *= mjerk / jerk; - limited = true; - } - } else { - safe_speed = cs.max_jerk[axis]; - limited = true; - } - } - } - - // Reset the block flag. - block->flag = 0; - - // Initial limit on the segment entry velocity. - float vmax_junction; - - //FIXME Vojtech: Why only if at least two lines are planned in the queue? - // Is it because we don't want to tinker with the first buffer line, which - // is likely to be executed by the stepper interrupt routine soon? - if (moves_queued > 1 && previous_nominal_speed > 0.0001f) { - // Estimate a maximum velocity allowed at a joint of two successive segments. - // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities, - // then the machine is not coasting anymore and the safe entry / exit velocities shall be used. - - // The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum. - bool prev_speed_larger = previous_nominal_speed > block->nominal_speed; - float smaller_speed_factor = prev_speed_larger ? (block->nominal_speed / previous_nominal_speed) : (previous_nominal_speed / block->nominal_speed); - // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting. - vmax_junction = prev_speed_larger ? block->nominal_speed : previous_nominal_speed; - // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities. - float v_factor = 1.f; - limited = false; - // Now limit the jerk in all axes. - for (uint8_t axis = 0; axis < 4; ++ axis) { - // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop. - float v_exit = previous_speed[axis]; - float v_entry = current_speed [axis]; - if (prev_speed_larger) - v_exit *= smaller_speed_factor; - if (limited) { - v_exit *= v_factor; - v_entry *= v_factor; - } - // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction. - float jerk = - (v_exit > v_entry) ? - ((v_entry > 0.f || v_exit < 0.f) ? - // coasting - (v_exit - v_entry) : - // axis reversal - max(v_exit, - v_entry)) : - // v_exit <= v_entry - ((v_entry < 0.f || v_exit > 0.f) ? - // coasting - (v_entry - v_exit) : - // axis reversal - max(- v_exit, v_entry)); - if (jerk > cs.max_jerk[axis]) { - v_factor *= cs.max_jerk[axis] / jerk; - limited = true; - } - } - if (limited) - vmax_junction *= v_factor; - // Now the transition velocity is known, which maximizes the shared exit / entry velocity while - // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints. - float vmax_junction_threshold = vmax_junction * 0.99f; - if (previous_safe_speed > vmax_junction_threshold && safe_speed > vmax_junction_threshold) { - // Not coasting. The machine will stop and start the movements anyway, - // better to start the segment from start. - block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT; - vmax_junction = safe_speed; - } - } else { - block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT; - vmax_junction = safe_speed; - } - - // Max entry speed of this block equals the max exit speed of the previous block. - block->max_entry_speed = vmax_junction; - - // Initialize block entry speed. Compute based on deceleration to safe_speed. - double v_allowable = max_allowable_entry_speed(-block->acceleration,safe_speed,block->millimeters); - block->entry_speed = min(vmax_junction, v_allowable); - - // Initialize planner efficiency flags - // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds. - // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then - // the current block and next block junction speeds are guaranteed to always be at their maximum - // junction speeds in deceleration and acceleration, respectively. This is due to how the current - // block nominal speed limits both the current and next maximum junction speeds. Hence, in both - // the reverse and forward planners, the corresponding block junction speed will always be at the - // the maximum junction speed and may always be ignored for any speed reduction checks. - // Always calculate trapezoid for new block - block->flag |= (block->nominal_speed <= v_allowable) ? (BLOCK_FLAG_NOMINAL_LENGTH | BLOCK_FLAG_RECALCULATE) : BLOCK_FLAG_RECALCULATE; - - // Update previous path unit_vector and nominal speed - memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[] - previous_nominal_speed = block->nominal_speed; - previous_safe_speed = safe_speed; + block->acceleration_rate = (long)((float)block->acceleration_st * (16777216.0 / (F_CPU / 8.0))); + + // Start with a safe speed. + // Safe speed is the speed, from which the machine may halt to stop immediately. + float safe_speed = block->nominal_speed; + bool limited = false; + for (uint8_t axis = 0; axis < 4; ++ axis) { + float jerk = fabs(current_speed[axis]); + if (jerk > cs.max_jerk[axis]) { + // The actual jerk is lower, if it has been limited by the XY jerk. + if (limited) { + // Spare one division by a following gymnastics: + // Instead of jerk *= safe_speed / block->nominal_speed, + // multiply max_jerk[axis] by the divisor. + jerk *= safe_speed; + float mjerk = cs.max_jerk[axis] * block->nominal_speed; + if (jerk > mjerk) { + safe_speed *= mjerk / jerk; + limited = true; + } + } else { + safe_speed = cs.max_jerk[axis]; + limited = true; + } + } + } + + // Reset the block flag. + block->flag = 0; + + // Initial limit on the segment entry velocity. + float vmax_junction; + + //FIXME Vojtech: Why only if at least two lines are planned in the queue? + // Is it because we don't want to tinker with the first buffer line, which + // is likely to be executed by the stepper interrupt routine soon? + if (moves_queued > 1 && previous_nominal_speed > 0.0001f) { + // Estimate a maximum velocity allowed at a joint of two successive segments. + // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities, + // then the machine is not coasting anymore and the safe entry / exit velocities shall be used. + + // The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum. + bool prev_speed_larger = previous_nominal_speed > block->nominal_speed; + float smaller_speed_factor = prev_speed_larger ? (block->nominal_speed / previous_nominal_speed) : (previous_nominal_speed / block->nominal_speed); + // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting. + vmax_junction = prev_speed_larger ? block->nominal_speed : previous_nominal_speed; + // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities. + float v_factor = 1.f; + limited = false; + // Now limit the jerk in all axes. + for (uint8_t axis = 0; axis < 4; ++ axis) { + // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop. + float v_exit = previous_speed[axis]; + float v_entry = current_speed [axis]; + if (prev_speed_larger) + v_exit *= smaller_speed_factor; + if (limited) { + v_exit *= v_factor; + v_entry *= v_factor; + } + // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction. + float jerk = + (v_exit > v_entry) ? + ((v_entry > 0.f || v_exit < 0.f) ? + // coasting + (v_exit - v_entry) : + // axis reversal + max(v_exit, - v_entry)) : + // v_exit <= v_entry + ((v_entry < 0.f || v_exit > 0.f) ? + // coasting + (v_entry - v_exit) : + // axis reversal + max(- v_exit, v_entry)); + if (jerk > cs.max_jerk[axis]) { + v_factor *= cs.max_jerk[axis] / jerk; + limited = true; + } + } + if (limited) + vmax_junction *= v_factor; + // Now the transition velocity is known, which maximizes the shared exit / entry velocity while + // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints. + float vmax_junction_threshold = vmax_junction * 0.99f; + if (previous_safe_speed > vmax_junction_threshold && safe_speed > vmax_junction_threshold) { + // Not coasting. The machine will stop and start the movements anyway, + // better to start the segment from start. + block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT; + vmax_junction = safe_speed; + } + } else { + block->flag |= BLOCK_FLAG_START_FROM_FULL_HALT; + vmax_junction = safe_speed; + } + + // Max entry speed of this block equals the max exit speed of the previous block. + block->max_entry_speed = vmax_junction; + + // Initialize block entry speed. Compute based on deceleration to safe_speed. + double v_allowable = max_allowable_entry_speed(-block->acceleration,safe_speed,block->millimeters); + block->entry_speed = min(vmax_junction, v_allowable); + + // Initialize planner efficiency flags + // Set flag if block will always reach maximum junction speed regardless of entry/exit speeds. + // If a block can de/ac-celerate from nominal speed to zero within the length of the block, then + // the current block and next block junction speeds are guaranteed to always be at their maximum + // junction speeds in deceleration and acceleration, respectively. This is due to how the current + // block nominal speed limits both the current and next maximum junction speeds. Hence, in both + // the reverse and forward planners, the corresponding block junction speed will always be at the + // the maximum junction speed and may always be ignored for any speed reduction checks. + // Always calculate trapezoid for new block + block->flag |= (block->nominal_speed <= v_allowable) ? (BLOCK_FLAG_NOMINAL_LENGTH | BLOCK_FLAG_RECALCULATE) : BLOCK_FLAG_RECALCULATE; + + // Update previous path unit_vector and nominal speed + memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[] + previous_nominal_speed = block->nominal_speed; + previous_safe_speed = safe_speed; #ifdef LIN_ADVANCE @@ -1165,72 +1189,72 @@ Having the real displacement of the head, we can calculate the total movement le // de_float > 0.0 : Extruder is running forward (e.g., for "Wipe while retracting" (Slic3r) or "Combing" (Cura) moves) // block->use_advance_lead = block->steps_e.wide - && (block->steps_x.wide || block->steps_y.wide) - && extruder_advance_k - && (uint32_t)block->steps_e.wide != block->step_event_count.wide - && de_float > 0.0; + && (block->steps_x.wide || block->steps_y.wide) + && extruder_advance_k + && (uint32_t)block->steps_e.wide != block->step_event_count.wide + && de_float > 0.0; if (block->use_advance_lead) block->abs_adv_steps_multiplier8 = lround( - extruder_advance_k - * ((advance_ed_ratio < 0.000001) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set - * (block->nominal_speed / (float)block->nominal_rate) - * cs.axis_steps_per_unit[E_AXIS] * 256.0 - ); + extruder_advance_k + * ((advance_ed_ratio < 0.000001) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set + * (block->nominal_speed / (float)block->nominal_rate) + * cs.axis_steps_per_unit[E_AXIS] * 256.0 + ); #endif - - // Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated. - block->speed_factor = block->nominal_rate / block->nominal_speed; - calculate_trapezoid_for_block(block, block->entry_speed, safe_speed); - if (block->step_event_count.wide <= 32767) - block->flag |= BLOCK_FLAG_DDA_LOWRES; + // Precalculate the division, so when all the trapezoids in the planner queue get recalculated, the division is not repeated. + block->speed_factor = block->nominal_rate / block->nominal_speed; + calculate_trapezoid_for_block(block, block->entry_speed, safe_speed); - // Move the buffer head. From now the block may be picked up by the stepper interrupt controller. - block_buffer_head = next_buffer_head; + if (block->step_event_count.wide <= 32767) + block->flag |= BLOCK_FLAG_DDA_LOWRES; - // Update position - memcpy(position, target, sizeof(target)); // position[] = target[] + // Move the buffer head. From now the block may be picked up by the stepper interrupt controller. + block_buffer_head = next_buffer_head; + + // Update position + memcpy(position, target, sizeof(target)); // position[] = target[] #ifdef LIN_ADVANCE - position_float[X_AXIS] = x; - position_float[Y_AXIS] = y; - position_float[Z_AXIS] = z; - position_float[E_AXIS] = e; + position_float[X_AXIS] = x; + position_float[Y_AXIS] = y; + position_float[Z_AXIS] = z; + position_float[E_AXIS] = e; #endif - - // Recalculate the trapezoids to maximize speed at the segment transitions while respecting - // the machine limits (maximum acceleration and maximum jerk). - // This runs asynchronously with the stepper interrupt controller, which may - // interfere with the process. - planner_recalculate(safe_speed); + + // Recalculate the trapezoids to maximize speed at the segment transitions while respecting + // the machine limits (maximum acceleration and maximum jerk). + // This runs asynchronously with the stepper interrupt controller, which may + // interfere with the process. + planner_recalculate(safe_speed); // SERIAL_ECHOPGM("Q"); // SERIAL_ECHO(int(moves_planned())); // SERIAL_ECHOLNPGM(""); #ifdef PLANNER_DIAGNOSTICS - planner_update_queue_min_counter(); + planner_update_queue_min_counter(); #endif /* PLANNER_DIAGNOSTIC */ - // The stepper timer interrupt will run continuously from now on. - // If there are no planner blocks to be executed by the stepper routine, - // the stepper interrupt ticks at 1kHz to wake up and pick a block - // from the planner queue if available. - ENABLE_STEPPER_DRIVER_INTERRUPT(); + // The stepper timer interrupt will run continuously from now on. + // If there are no planner blocks to be executed by the stepper routine, + // the stepper interrupt ticks at 1kHz to wake up and pick a block + // from the planner queue if available. + ENABLE_STEPPER_DRIVER_INTERRUPT(); } #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)); + 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::transpose(plan_bed_level_matrix); - //inverse.debug("in plan_get inverse"); - position.apply_rotation(inverse); - //position.debug("after rotation"); + //position.debug("in plan_get position"); + //plan_bed_level_matrix.debug("in plan_get bed_level"); + matrix_3x3 inverse = matrix_3x3::transpose(plan_bed_level_matrix); + //inverse.debug("in plan_get inverse"); + position.apply_rotation(inverse); + //position.debug("after rotation"); - return position; + return position; } #endif // ENABLE_AUTO_BED_LEVELING @@ -1249,117 +1273,117 @@ void plan_set_position(float x, float y, float z, const float &e) y = world2machine_rotation_and_skew[1][0] * tmpx + world2machine_rotation_and_skew[1][1] * tmpy + world2machine_shift[1]; } - position[X_AXIS] = lround(x*cs.axis_steps_per_unit[X_AXIS]); - position[Y_AXIS] = lround(y*cs.axis_steps_per_unit[Y_AXIS]); + position[X_AXIS] = lround(x*cs.axis_steps_per_unit[X_AXIS]); + position[Y_AXIS] = lround(y*cs.axis_steps_per_unit[Y_AXIS]); #ifdef MESH_BED_LEVELING - position[Z_AXIS] = mbl.active ? - lround((z+mbl.get_z(x, y))*cs.axis_steps_per_unit[Z_AXIS]) : - lround(z*cs.axis_steps_per_unit[Z_AXIS]); + position[Z_AXIS] = mbl.active ? + lround((z+mbl.get_z(x, y))*cs.axis_steps_per_unit[Z_AXIS]) : + lround(z*cs.axis_steps_per_unit[Z_AXIS]); #else - position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]); + position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]); #endif // ENABLE_MESH_BED_LEVELING - position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]); + position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]); #ifdef LIN_ADVANCE - position_float[X_AXIS] = x; - position_float[Y_AXIS] = y; - position_float[Z_AXIS] = z; - position_float[E_AXIS] = e; + position_float[X_AXIS] = x; + position_float[Y_AXIS] = y; + position_float[Z_AXIS] = z; + position_float[E_AXIS] = e; #endif - st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]); - previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest. - previous_speed[0] = 0.0; - previous_speed[1] = 0.0; - previous_speed[2] = 0.0; - previous_speed[3] = 0.0; + st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]); + previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest. + previous_speed[0] = 0.0; + previous_speed[1] = 0.0; + previous_speed[2] = 0.0; + previous_speed[3] = 0.0; } // Only useful in the bed leveling routine, when the mesh bed leveling is off. void plan_set_z_position(const float &z) { - #ifdef LIN_ADVANCE - position_float[Z_AXIS] = z; - #endif +#ifdef LIN_ADVANCE + position_float[Z_AXIS] = z; +#endif position[Z_AXIS] = lround(z*cs.axis_steps_per_unit[Z_AXIS]); st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]); } void plan_set_e_position(const float &e) { - #ifdef LIN_ADVANCE - position_float[E_AXIS] = e; - #endif - position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]); - st_set_e_position(position[E_AXIS]); +#ifdef LIN_ADVANCE + position_float[E_AXIS] = e; +#endif + position[E_AXIS] = lround(e*cs.axis_steps_per_unit[E_AXIS]); + st_set_e_position(position[E_AXIS]); } #ifdef PREVENT_DANGEROUS_EXTRUDE void set_extrude_min_temp(float temp) { - extrude_min_temp=temp; + extrude_min_temp=temp; } #endif // Calculate the steps/s^2 acceleration rates, based on the mm/s^s void reset_acceleration_rates() { - for(int8_t i=0; i < NUM_AXIS; i++) + for(int8_t i=0; i < NUM_AXIS; i++) axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * cs.axis_steps_per_unit[i]; } #ifdef TMC2130 void update_mode_profile() { - if (tmc2130_mode == TMC2130_MODE_NORMAL) - { - max_feedrate = cs.max_feedrate_normal; - max_acceleration_units_per_sq_second = cs.max_acceleration_units_per_sq_second_normal; - } - else if (tmc2130_mode == TMC2130_MODE_SILENT) - { - max_feedrate = cs.max_feedrate_silent; - max_acceleration_units_per_sq_second = cs.max_acceleration_units_per_sq_second_silent; - } - reset_acceleration_rates(); + if (tmc2130_mode == TMC2130_MODE_NORMAL) + { + max_feedrate = cs.max_feedrate_normal; + max_acceleration_units_per_sq_second = cs.max_acceleration_units_per_sq_second_normal; + } + else if (tmc2130_mode == TMC2130_MODE_SILENT) + { + max_feedrate = cs.max_feedrate_silent; + max_acceleration_units_per_sq_second = cs.max_acceleration_units_per_sq_second_silent; + } + reset_acceleration_rates(); } #endif //TMC2130 unsigned char number_of_blocks() { - return (block_buffer_head + BLOCK_BUFFER_SIZE - block_buffer_tail) & (BLOCK_BUFFER_SIZE - 1); + return (block_buffer_head + BLOCK_BUFFER_SIZE - block_buffer_tail) & (BLOCK_BUFFER_SIZE - 1); } #ifdef PLANNER_DIAGNOSTICS uint8_t planner_queue_min() { - return g_cntr_planner_queue_min; + return g_cntr_planner_queue_min; } void planner_queue_min_reset() { - g_cntr_planner_queue_min = moves_planned(); + g_cntr_planner_queue_min = moves_planned(); } #endif /* PLANNER_DIAGNOSTICS */ void planner_add_sd_length(uint16_t sdlen) { - if (block_buffer_head != block_buffer_tail) { - // The planner buffer is not empty. Get the index of the last buffer line entered, - // which is (block_buffer_head - 1) modulo BLOCK_BUFFER_SIZE. - block_buffer[prev_block_index(block_buffer_head)].sdlen += sdlen; - } else { - // There is no line stored in the planner buffer, which means the last command does not need to be revertible, - // at a power panic, so the length of this command may be forgotten. - } + if (block_buffer_head != block_buffer_tail) { + // The planner buffer is not empty. Get the index of the last buffer line entered, + // which is (block_buffer_head - 1) modulo BLOCK_BUFFER_SIZE. + block_buffer[prev_block_index(block_buffer_head)].sdlen += sdlen; + } else { + // There is no line stored in the planner buffer, which means the last command does not need to be revertible, + // at a power panic, so the length of this command may be forgotten. + } } uint16_t planner_calc_sd_length() { - unsigned char _block_buffer_head = block_buffer_head; - unsigned char _block_buffer_tail = block_buffer_tail; - uint16_t sdlen = 0; - while (_block_buffer_head != _block_buffer_tail) - { - sdlen += block_buffer[_block_buffer_tail].sdlen; - _block_buffer_tail = (_block_buffer_tail + 1) & (BLOCK_BUFFER_SIZE - 1); - } - return sdlen; + unsigned char _block_buffer_head = block_buffer_head; + unsigned char _block_buffer_tail = block_buffer_tail; + uint16_t sdlen = 0; + while (_block_buffer_head != _block_buffer_tail) + { + sdlen += block_buffer[_block_buffer_tail].sdlen; + _block_buffer_tail = (_block_buffer_tail + 1) & (BLOCK_BUFFER_SIZE - 1); + } + return sdlen; } diff --git a/Firmware/planner.h b/Firmware/planner.h index b6a9f8361e..0d10a92eaa 100755 --- a/Firmware/planner.h +++ b/Firmware/planner.h @@ -18,7 +18,7 @@ along with Grbl. If not, see . */ -// This module is to be considered a sub-module of stepper.c. Please don't include +// This module is to be considered a sub-module of stepper.c. Please don't include // this file from any other module. #ifndef planner_h @@ -48,79 +48,79 @@ enum BlockFlag { union dda_isteps_t { - int32_t wide; - struct { - int16_t lo; - int16_t hi; - }; + int32_t wide; + struct { + int16_t lo; + int16_t hi; + }; }; union dda_usteps_t { - uint32_t wide; - struct { - uint16_t lo; - uint16_t hi; - }; + uint32_t wide; + struct { + uint16_t lo; + uint16_t hi; + }; }; -// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in +// 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 { - // Fields used by the bresenham algorithm for tracing the line - // steps_x.y,z, step_event_count, acceleration_rate, direction_bits and active_extruder are set by plan_buffer_line(). - dda_isteps_t steps_x, steps_y, steps_z, steps_e; // Step count along each axis - dda_usteps_t step_event_count; // The number of step events required to complete this block - long acceleration_rate; // The acceleration rate used for acceleration calculation - unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) - unsigned char active_extruder; // Selects the active extruder - // accelerate_until and decelerate_after are set by calculate_trapezoid_for_block() and they need to be synchronized with the stepper interrupt controller. - long accelerate_until; // The index of the step event on which to stop acceleration - long decelerate_after; // The index of the step event on which to start decelerating - - // Fields used by the motion planner to manage acceleration + // Fields used by the bresenham algorithm for tracing the line + // steps_x.y,z, step_event_count, acceleration_rate, direction_bits and active_extruder are set by plan_buffer_line(). + dda_isteps_t steps_x, steps_y, steps_z, steps_e; // Step count along each axis + dda_usteps_t step_event_count; // The number of step events required to complete this block + long acceleration_rate; // The acceleration rate used for acceleration calculation + unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h) + unsigned char active_extruder; // Selects the active extruder + // accelerate_until and decelerate_after are set by calculate_trapezoid_for_block() and they need to be synchronized with the stepper interrupt controller. + long accelerate_until; // The index of the step event on which to stop acceleration + long decelerate_after; // The index of the step event on which to start decelerating + + // Fields used by the motion planner to manage acceleration // float speed_x, speed_y, speed_z, speed_e; // Nominal mm/sec for each axis - // The nominal speed for this block in mm/sec. - // This speed may or may not be reached due to the jerk and acceleration limits. - float nominal_speed; - // Entry speed at previous-current junction in mm/sec, respecting the acceleration and jerk limits. - // The entry speed limit of the current block equals the exit speed of the preceding block. - float entry_speed; - // Maximum allowable junction entry speed in mm/sec. This value is also a maximum exit speed of the previous block. - float max_entry_speed; - // The total travel of this block in mm - float millimeters; - // acceleration mm/sec^2 - float acceleration; - - // Bit flags defined by the BlockFlag enum. - uint8_t flag; - - // Settings for the trapezoid generator (runs inside an interrupt handler). - // Changing the following values in the planner needs to be synchronized with the interrupt handler by disabling the interrupts. - //FIXME nominal_rate, initial_rate and final_rate are limited to uint16_t by MultiU24X24toH16 in the stepper interrupt anyway! - unsigned long nominal_rate; // The nominal step rate for this block in step_events/sec - unsigned long initial_rate; // The jerk-adjusted step rate at start of block - unsigned long final_rate; // The minimal rate at exit - unsigned long acceleration_st; // acceleration steps/sec^2 - //FIXME does it have to be unsigned long? Probably uint8_t would be just fine. - unsigned long fan_speed; - volatile char busy; - - - // Pre-calculated division for the calculate_trapezoid_for_block() routine to run faster. - float speed_factor; - + // The nominal speed for this block in mm/sec. + // This speed may or may not be reached due to the jerk and acceleration limits. + float nominal_speed; + // Entry speed at previous-current junction in mm/sec, respecting the acceleration and jerk limits. + // The entry speed limit of the current block equals the exit speed of the preceding block. + float entry_speed; + // Maximum allowable junction entry speed in mm/sec. This value is also a maximum exit speed of the previous block. + float max_entry_speed; + // The total travel of this block in mm + float millimeters; + // acceleration mm/sec^2 + float acceleration; + + // Bit flags defined by the BlockFlag enum. + uint8_t flag; + + // Settings for the trapezoid generator (runs inside an interrupt handler). + // Changing the following values in the planner needs to be synchronized with the interrupt handler by disabling the interrupts. + //FIXME nominal_rate, initial_rate and final_rate are limited to uint16_t by MultiU24X24toH16 in the stepper interrupt anyway! + unsigned long nominal_rate; // The nominal step rate for this block in step_events/sec + unsigned long initial_rate; // The jerk-adjusted step rate at start of block + unsigned long final_rate; // The minimal rate at exit + unsigned long acceleration_st; // acceleration steps/sec^2 + //FIXME does it have to be unsigned long? Probably uint8_t would be just fine. + unsigned long fan_speed; + volatile char busy; + + + // Pre-calculated division for the calculate_trapezoid_for_block() routine to run faster. + float speed_factor; + #ifdef LIN_ADVANCE - bool use_advance_lead; - unsigned long abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float + bool use_advance_lead; + unsigned long abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float #endif - uint16_t sdlen; + uint16_t sdlen; } block_t; #ifdef LIN_ADVANCE - extern float extruder_advance_k, advance_ed_ratio; +extern float extruder_advance_k, advance_ed_ratio; #endif #ifdef ENABLE_AUTO_BED_LEVELING @@ -128,10 +128,10 @@ typedef struct { extern matrix_3x3 plan_bed_level_matrix; #endif // #ifdef ENABLE_AUTO_BED_LEVELING -// Initialize the motion plan subsystem +// 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 +// 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 @@ -163,7 +163,7 @@ extern float* max_feedrate; // Use M201 to override by software -extern unsigned long* max_acceleration_units_per_sq_second; +extern unsigned long* max_acceleration_units_per_sq_second; extern unsigned long axis_steps_per_sqr_second[NUM_AXIS]; extern long position[NUM_AXIS]; @@ -171,48 +171,48 @@ extern uint8_t maxlimit_status; #ifdef AUTOTEMP - extern bool autotemp_enabled; - extern float autotemp_max; - extern float autotemp_min; - extern float autotemp_factor; +extern bool autotemp_enabled; +extern float autotemp_max; +extern float autotemp_min; +extern float autotemp_factor; #endif - + extern block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions // Index of the next block to be pushed into the planner queue. extern volatile unsigned char block_buffer_head; // Index of the first block in the planner queue. -// This is the block, which is being currently processed by the stepper routine, +// This is the block, which is being currently processed by the stepper routine, // or which is first to be processed by the stepper routine. -extern volatile unsigned char block_buffer_tail; +extern volatile unsigned char block_buffer_tail; // Called when the current block is no longer needed. Discards the block and makes the memory -// available for new blocks. -FORCE_INLINE void plan_discard_current_block() +// available for new blocks. +FORCE_INLINE void plan_discard_current_block() { - if (block_buffer_head != block_buffer_tail) { - block_buffer_tail = (block_buffer_tail + 1) & (BLOCK_BUFFER_SIZE - 1); - } + if (block_buffer_head != block_buffer_tail) { + block_buffer_tail = (block_buffer_tail + 1) & (BLOCK_BUFFER_SIZE - 1); + } } // Gets the current block. This is the block to be exectuted by the stepper routine. // Mark this block as busy, so its velocities and acceperations will be no more recalculated // by the planner routine. // Returns NULL if buffer empty -FORCE_INLINE block_t *plan_get_current_block() +FORCE_INLINE block_t *plan_get_current_block() { - if (block_buffer_head == block_buffer_tail) { - return(NULL); - } - block_t *block = &block_buffer[block_buffer_tail]; - block->busy = true; - return(block); + if (block_buffer_head == block_buffer_tail) { + return(NULL); + } + block_t *block = &block_buffer[block_buffer_tail]; + block->busy = true; + return(block); } // Returns true if the buffer has a queued block, false otherwise -FORCE_INLINE bool blocks_queued() { - return (block_buffer_head != block_buffer_tail); +FORCE_INLINE bool blocks_queued() { + return (block_buffer_head != block_buffer_tail); } //return the nr of buffered moves @@ -223,7 +223,7 @@ FORCE_INLINE uint8_t moves_planned() { FORCE_INLINE bool planner_queue_full() { unsigned char next_block_index = block_buffer_head; if (++ next_block_index == BLOCK_BUFFER_SIZE) - next_block_index = 0; + next_block_index = 0; return block_buffer_tail == next_block_index; } diff --git a/Firmware/qr_solve.cpp b/Firmware/qr_solve.cpp index f19d989d41..03033612eb 100755 --- a/Firmware/qr_solve.cpp +++ b/Firmware/qr_solve.cpp @@ -34,17 +34,17 @@ int i4_min ( int i1, int i2 ) Output, int I4_MIN, the smaller of I1 and I2. */ { - int value; - - if ( i1 < i2 ) - { - value = i1; - } - else - { - value = i2; - } - return value; + int value; + + if ( i1 < i2 ) + { + value = i1; + } + else + { + value = i2; + } + return value; } double r8_epsilon ( void ) @@ -80,9 +80,9 @@ double r8_epsilon ( void ) Output, double R8_EPSILON, the R8 round-off unit. */ { - const double value = 2.220446049250313E-016; + const double value = 2.220446049250313E-016; - return value; + return value; } double r8_max ( double x, double y ) @@ -112,17 +112,17 @@ double r8_max ( double x, double y ) Output, double R8_MAX, the maximum of X and Y. */ { - double value; - - if ( y < x ) - { - value = x; - } - else - { - value = y; - } - return value; + double value; + + if ( y < x ) + { + value = x; + } + else + { + value = y; + } + return value; } double r8_abs ( double x ) @@ -152,17 +152,17 @@ double r8_abs ( double x ) Output, double R8_ABS, the absolute value of X. */ { - double value; - - if ( 0.0 <= x ) - { - value = + x; - } - else - { - value = - x; - } - return value; + double value; + + if ( 0.0 <= x ) + { + value = + x; + } + else + { + value = - x; + } + return value; } double r8_sign ( double x ) @@ -192,17 +192,17 @@ double r8_sign ( double x ) Output, double R8_SIGN, the sign of X. */ { - double value; - - if ( x < 0.0 ) - { - value = - 1.0; - } - else - { - value = + 1.0; - } - return value; + double value; + + if ( x < 0.0 ) + { + value = - 1.0; + } + else + { + value = + 1.0; + } + return value; } double r8mat_amax ( int m, int n, double a[] ) @@ -241,23 +241,23 @@ double r8mat_amax ( int m, int n, double a[] ) Output, double R8MAT_AMAX, the maximum absolute value entry of A. */ { - int i; - int j; - double value; + int i; + int j; + double value; - value = r8_abs ( a[0+0*m] ); + value = r8_abs ( a[0+0*m] ); - for ( j = 0; j < n; j++ ) - { - for ( i = 0; i < m; i++ ) + for ( j = 0; j < n; j++ ) { - if ( value < r8_abs ( a[i+j*m] ) ) - { - value = r8_abs ( a[i+j*m] ); - } + for ( i = 0; i < m; i++ ) + { + if ( value < r8_abs ( a[i+j*m] ) ) + { + value = r8_abs ( a[i+j*m] ); + } + } } - } - return value; + return value; } double *r8mat_copy_new ( int m, int n, double a1[] ) @@ -294,21 +294,21 @@ double *r8mat_copy_new ( int m, int n, double a1[] ) Output, double R8MAT_COPY_NEW[M*N], the copy of A1. */ { - double *a2; - int i; - int j; + double *a2; + int i; + int j; - a2 = ( double * ) malloc ( m * n * sizeof ( double ) ); + a2 = ( double * ) malloc ( m * n * sizeof ( double ) ); - for ( j = 0; j < n; j++ ) - { - for ( i = 0; i < m; i++ ) + for ( j = 0; j < n; j++ ) { - a2[i+j*m] = a1[i+j*m]; + for ( i = 0; i < m; i++ ) + { + a2[i+j*m] = a1[i+j*m]; + } } - } - return a2; + return a2; } /******************************************************************************/ @@ -327,7 +327,7 @@ void daxpy ( int n, double da, double dx[], int incx, double dy[], int incy ) Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -345,8 +345,8 @@ void daxpy ( int n, double da, double dx[], int incx, double dy[], int incy ) Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, Basic Linear Algebra Subprograms for Fortran Usage, - Algorithm 539, - ACM Transactions on Mathematical Software, + Algorithm 539, + ACM Transactions on Mathematical Software, Volume 5, Number 3, September 1979, pages 308-323. Parameters: @@ -365,72 +365,72 @@ void daxpy ( int n, double da, double dx[], int incx, double dy[], int incy ) Input, int INCY, the increment between successive entries of DY. */ { - int i; - int ix; - int iy; - int m; - - if ( n <= 0 ) - { - return; - } + int i; + int ix; + int iy; + int m; - 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 + if ( n <= 0 ) { - ix = ( - n + 1 ) * incx; + return; } - if ( 0 <= incy ) + if ( da == 0.0 ) { - iy = 0; + return; } - else + /* + Code for unequal increments or equal increments + not equal to 1. + */ + if ( incx != 1 || incy != 1 ) { - iy = ( - n + 1 ) * incy; - } + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } - 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; + if ( 0 <= incy ) + { + iy = 0; + } + else + { + iy = ( - n + 1 ) * incy; + } - for ( i = 0; i < m; i++ ) - { - dy[i] = dy[i] + da * dx[i]; + for ( i = 0; i < n; i++ ) + { + dy[iy] = dy[iy] + da * dx[ix]; + ix = ix + incx; + iy = iy + incy; + } } - - for ( i = m; i < n; i = i + 4 ) + /* + Code for both increments equal to 1. + */ + else { - 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]; + 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; + return; } /******************************************************************************/ @@ -448,7 +448,7 @@ double ddot ( int n, double dx[], int incx, double dy[], int incy ) Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -466,8 +466,8 @@ double ddot ( int n, double dx[], int incx, double dy[], int incy ) Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, Basic Linear Algebra Subprograms for Fortran Usage, - Algorithm 539, - ACM Transactions on Mathematical Software, + Algorithm 539, + ACM Transactions on Mathematical Software, Volume 5, Number 3, September 1979, pages 308-323. Parameters: @@ -486,71 +486,71 @@ double ddot ( int n, double dx[], int incx, double dy[], int incy ) entries of DX and DY. */ { - double dtemp; - int i; - int ix; - int iy; - int m; + double dtemp; + int i; + int ix; + int iy; + int m; - dtemp = 0.0; + 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 ) + if ( n <= 0 ) { - ix = 0; + return dtemp; } - else + /* + Code for unequal increments or equal increments + not equal to 1. + */ + if ( incx != 1 || incy != 1 ) { - ix = ( - n + 1 ) * incx; - } + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } - if ( 0 <= incy ) - { - iy = 0; + 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 { - 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; + m = n % 5; - for ( i = 0; i < m; i++ ) - { - dtemp = dtemp + dx[i] * dy[i]; - } + 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] + 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; + return dtemp; } /******************************************************************************/ @@ -568,7 +568,7 @@ double dnrm2 ( int n, double x[], int incx ) Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -601,55 +601,55 @@ double dnrm2 ( int n, double x[], int incx ) 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++ ) + double absxi; + int i; + int ix; + double norm; + double scale; + double ssq; + double value; + + if ( n < 1 || incx < 1 ) { - if ( x[ix] != 0.0 ) - { - absxi = r8_abs ( x[ix] ); - if ( scale < absxi ) - { - ssq = 1.0 + ssq * ( scale / absxi ) * ( scale / absxi ); - scale = absxi; - } - else + 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++ ) { - ssq = ssq + ( absxi / scale ) * ( absxi / scale ); + 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; } - } - ix = ix + incx; - } - norm = scale * sqrt ( ssq ); - } + norm = scale * sqrt ( ssq ); + } - return norm; + return norm; } /******************************************************************************/ -void dqrank ( double a[], int lda, int m, int n, double tol, int *kr, - int jpvt[], double qraux[] ) +void dqrank ( double a[], int lda, int m, int n, double tol, int *kr, + int jpvt[], double qraux[] ) /******************************************************************************/ /* @@ -673,7 +673,7 @@ void dqrank ( double a[], int lda, int m, int n, double tol, int *kr, Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -723,42 +723,42 @@ void dqrank ( double a[], int lda, int m, int n, double tol, int *kr, the QR factorization. */ { - int i; - int j; - int job; - int k; - double *work; + int i; + int j; + int job; + int k; + double *work; - for ( i = 0; i < n; i++ ) - { - jpvt[i] = 0; - } + for ( i = 0; i < n; i++ ) + { + jpvt[i] = 0; + } - work = ( double * ) malloc ( n * sizeof ( double ) ); - job = 1; + work = ( double * ) malloc ( n * sizeof ( double ) ); + job = 1; - dqrdc ( a, lda, m, n, qraux, jpvt, work, job ); + dqrdc ( a, lda, m, n, qraux, jpvt, work, job ); - *kr = 0; - k = i4_min ( m, n ); + *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] ) ) + for ( j = 0; j < k; j++ ) { - return; + if ( r8_abs ( a[j+j*lda] ) <= tol * r8_abs ( a[0+0*lda] ) ) + { + return; + } + *kr = j + 1; } - *kr = j + 1; - } - free ( work ); + free ( work ); - return; + return; } /******************************************************************************/ -void dqrdc ( double a[], int lda, int n, int p, double qraux[], int jpvt[], - double work[], int job ) +void dqrdc ( double a[], int lda, int n, int p, double qraux[], int jpvt[], + double work[], int job ) /******************************************************************************/ /* @@ -775,7 +775,7 @@ void dqrdc ( double a[], int lda, int n, int p, double qraux[], int jpvt[], Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -838,176 +838,176 @@ void dqrdc ( double a[], int lda, int n, int p, double qraux[], int jpvt[], 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++ ) + 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 ) { - swapj = ( 0 < jpvt[j-1] ); - - if ( jpvt[j-1] < 0 ) - { - jpvt[j-1] = -j; - } - else - { - jpvt[j-1] = j; - } - - if ( swapj ) - { - if ( j != pl ) + for ( j = 1; j <= p; j++ ) { - 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; + swapj = ( 0 < jpvt[j-1] ); - for ( j = p; 1 <= j; j-- ) - { - if ( jpvt[j-1] < 0 ) - { - jpvt[j-1] = -jpvt[j-1]; + if ( jpvt[j-1] < 0 ) + { + jpvt[j-1] = -j; + } + else + { + jpvt[j-1] = j; + } - 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; + 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 = 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 ); + pu = 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] ) + for ( j = p; 1 <= j; j-- ) { - maxnrm = qraux[j-1]; - maxj = 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; + } } - } - - 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; + /* + Compute the norms of the free columns. + */ + for ( j = pl; j <= pu; j++ ) + { + qraux[j-1] = dnrm2 ( n, a+0+(j-1)*lda, 1 ); + } - if ( l != n ) + for ( j = pl; j <= pu; j++ ) { - nrmxl = dnrm2 ( n-l+1, a+l-1+(l-1)*lda, 1 ); + work[j-1] = qraux[j-1]; + } + /* + Perform the Householder reduction of A. + */ + lup = i4_min ( n, p ); - if ( nrmxl != 0.0 ) - { - if ( a[l-1+(l-1)*lda] != 0.0 ) + for ( l = 1; l <= lup; l++ ) + { + /* + Bring the column of largest norm into the pivot position. + */ + if ( pl <= l && l < pu ) { - nrmxl = nrmxl * r8_sign ( a[l-1+(l-1)*lda] ); + 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; - 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++ ) + if ( l != n ) { - 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 ); + nrmxl = dnrm2 ( n-l+1, a+l-1+(l-1)*lda, 1 ); - if ( pl <= j && j <= pu ) - { - if ( qraux[j-1] != 0.0 ) + if ( nrmxl != 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]; - } + 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; } - } } -/* - Save the transformation. -*/ - qraux[l-1] = a[l-1+(l-1)*lda]; - a[l-1+(l-1)*lda] = -nrmxl; - } } - } - return; + 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 ) +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 ) /******************************************************************************/ /* @@ -1042,7 +1042,7 @@ int dqrls ( double a[], int lda, int m, int n, double tol, int *kr, double b[], Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -1114,54 +1114,54 @@ int dqrls ( double a[], int lda, int m, int n, double tol, int *kr, double b[], -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; - } + int 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 ); + 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; + return ind; } /******************************************************************************/ -void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], - double rsd[], int jpvt[], double qraux[] ) +void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], + double rsd[], int jpvt[], double qraux[] ) /******************************************************************************/ /* @@ -1190,7 +1190,7 @@ void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -1234,52 +1234,52 @@ void dqrlss ( double a[], int lda, int m, int n, int kr, double b[], double x[], 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 ) + int i; + int info; + int j; + int job; + int k; + double t; + + if ( kr != 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]; - } + 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; + 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 ) +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 ) /******************************************************************************/ /* @@ -1344,7 +1344,7 @@ int dqrsl ( double a[], int lda, int n, int k, double qraux[], double y[], Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -1417,223 +1417,223 @@ int dqrsl ( double a[], int lda, int n, int k, double qraux[], double y[], 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 ) + 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 ) { - qy[0] = y[0]; - } + if ( cqy ) + { + qy[0] = y[0]; + } - if ( cqty ) - { - qty[0] = y[0]; - } + if ( cqty ) + { + qty[0] = y[0]; + } - if ( cab ) - { - ab[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 ( 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; + if ( cr ) + { + rsd[0] = 0.0; + } + return info; } - return info; - } -/* - Set up to compute QY or QTY. -*/ - if ( cqy ) - { - for ( i = 1; i <= n; i++ ) + /* + Set up to compute QY or QTY. + */ + if ( cqy ) { - qy[i-1] = y[i-1]; + for ( i = 1; i <= n; i++ ) + { + qy[i-1] = y[i-1]; + } } - } - if ( cqty ) - { - for ( i = 1; i <= n; i++ ) + if ( cqty ) { - qty[i-1] = y[i-1]; + for ( i = 1; i <= n; i++ ) + { + qty[i-1] = y[i-1]; + } } - } -/* - Compute QY. -*/ - if ( cqy ) - { - for ( jj = 1; jj <= ju; jj++ ) + /* + Compute QY. + */ + if ( cqy ) { - 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; - } + 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++ ) + /* + Compute Q'*Y. + */ + if ( cqty ) { - 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; - } + 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++ ) + /* + Set up to compute B, RSD, or AB. + */ + if ( cb ) { - b[i-1] = qty[i-1]; + for ( i = 1; i <= k; i++ ) + { + b[i-1] = qty[i-1]; + } } - } - if ( cab ) - { - for ( i = 1; i <= k; i++ ) + if ( cab ) { - ab[i-1] = qty[i-1]; + for ( i = 1; i <= k; i++ ) + { + ab[i-1] = qty[i-1]; + } } - } - if ( cr && k < n ) - { - for ( i = k+1; i <= n; i++ ) + if ( cr && k < n ) { - rsd[i-1] = qty[i-1]; + 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++ ) + if ( cab && k+1 <= n ) { - ab[i-1] = 0.0; + for ( i = k+1; i <= n; i++ ) + { + ab[i-1] = 0.0; + } } - } - if ( cr ) - { - for ( i = 1; i <= k; i++ ) + if ( cr ) { - rsd[i-1] = 0.0; + for ( i = 1; i <= k; i++ ) + { + rsd[i-1] = 0.0; + } } - } -/* - Compute B. -*/ - if ( cb ) - { - for ( jj = 1; jj <= k; jj++ ) + /* + Compute B. + */ + if ( cb ) { - j = k - jj + 1; + for ( jj = 1; jj <= k; jj++ ) + { + j = k - jj + 1; - if ( a[j-1+(j-1)*lda] == 0.0 ) - { - info = j; - break; - } + if ( a[j-1+(j-1)*lda] == 0.0 ) + { + info = j; + break; + } - b[j-1] = b[j-1] / a[j-1+(j-1)*lda]; + 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 ); - } + 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++ ) + /* + Compute RSD or AB as required. + */ + if ( cr || cab ) { - 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 ) + for ( jj = 1; jj <= ju; jj++ ) { - 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 ); - } + j = ju - jj + 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 ); + 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; + } } - a[j-1+(j-1)*lda] = temp; - } } - } - return info; + return info; } /******************************************************************************/ @@ -1649,7 +1649,7 @@ void dscal ( int n, double sa, double x[], int incx ) Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -1682,49 +1682,49 @@ void dscal ( int n, double sa, double x[], int incx ) 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]; - } + int i; + int ix; + int m; - for ( i = m; i < n; i = i + 5 ) + if ( n <= 0 ) { - 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 ) + else if ( incx == 1 ) { - ix = 0; + 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 { - ix = ( - n + 1 ) * incx; - } + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } - for ( i = 0; i < n; i++ ) - { - x[ix] = sa * x[ix]; - ix = ix + incx; + for ( i = 0; i < n; i++ ) + { + x[ix] = sa * x[ix]; + ix = ix + incx; + } } - } - return; + return; } /******************************************************************************/ @@ -1739,7 +1739,7 @@ void dswap ( int n, double x[], int incx, double y[], int incy ) Licensing: - This code is distributed under the GNU LGPL license. + This code is distributed under the GNU LGPL license. Modified: @@ -1757,8 +1757,8 @@ void dswap ( int n, double x[], int incx, double y[], int incy ) Charles Lawson, Richard Hanson, David Kincaid, Fred Krogh, Basic Linear Algebra Subprograms for Fortran Usage, - Algorithm 539, - ACM Transactions on Mathematical Software, + Algorithm 539, + ACM Transactions on Mathematical Software, Volume 5, Number 3, September 1979, pages 308-323. Parameters: @@ -1774,73 +1774,73 @@ void dswap ( int n, double x[], int incx, double y[], int incy ) 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++ ) + int i; + int ix; + int iy; + int m; + double temp; + + if ( n <= 0 ) { - temp = x[i]; - x[i] = y[i]; - y[i] = temp; } - - for ( i = m; i < n; i = i + 3 ) + else if ( incx == 1 && incy == 1 ) { - temp = x[i]; - x[i] = y[i]; - y[i] = temp; + m = n % 3; - temp = x[i+1]; - x[i+1] = y[i+1]; - y[i+1] = temp; + for ( i = 0; i < m; i++ ) + { + temp = x[i]; + x[i] = y[i]; + y[i] = 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; - } + for ( i = m; i < n; i = i + 3 ) + { + temp = x[i]; + x[i] = y[i]; + y[i] = temp; - if ( 0 <= incy ) - { - iy = 0; + 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 { - iy = ( - n + 1 ) * incy; - } + if ( 0 <= incx ) + { + ix = 0; + } + else + { + ix = ( - n + 1 ) * incx; + } - for ( i = 0; i < n; i++ ) - { - temp = x[ix]; - x[ix] = y[iy]; - y[iy] = temp; - ix = ix + incx; - iy = iy + incy; - } + 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; + } + + return; } /******************************************************************************/ @@ -1896,34 +1896,34 @@ double *qr_solve ( int m, int n, double a[], double b[] ) 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; + 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; } /******************************************************************************/ diff --git a/Firmware/qr_solve.h b/Firmware/qr_solve.h index b38086aad0..b662b3a5c5 100755 --- a/Firmware/qr_solve.h +++ b/Firmware/qr_solve.h @@ -5,16 +5,16 @@ 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 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[] ); diff --git a/Firmware/rbuf.c b/Firmware/rbuf.c index 1adafc5baa..756f900837 100755 --- a/Firmware/rbuf.c +++ b/Firmware/rbuf.c @@ -5,9 +5,9 @@ void rbuf_ini(uint8_t* ptr, uint8_t l) { - ptr[0] = l; - ptr[1] = 0; - ptr[2] = 0; + ptr[0] = l; + ptr[1] = 0; + ptr[2] = 0; } //lock/unlock macros @@ -20,17 +20,17 @@ void rbuf_ini(uint8_t* ptr, uint8_t l) int rbuf_put(uint8_t* ptr, uint8_t b) { //#ifdef _NO_ASM - _lock(); //lock - uint8_t buf_w = ptr[1]; //get write index - uint8_t buf_r = ptr[2]; //get read index - _unlock(); //unlock - ptr[4 + buf_w] = b; //store byte to buffer - buf_w++; //incerment write index - uint8_t buf_l = ptr[0]; //get length - if (buf_w >= buf_l) buf_w = 0; //rotate write index - if (buf_w == buf_r) return -1; //return -1 to signal buffer full - ptr[1] = buf_w; //store write index - return 0; //return 0 to signal success + _lock(); //lock + uint8_t buf_w = ptr[1]; //get write index + uint8_t buf_r = ptr[2]; //get read index + _unlock(); //unlock + ptr[4 + buf_w] = b; //store byte to buffer + buf_w++; //incerment write index + uint8_t buf_l = ptr[0]; //get length + if (buf_w >= buf_l) buf_w = 0; //rotate write index + if (buf_w == buf_r) return -1; //return -1 to signal buffer full + ptr[1] = buf_w; //store write index + return 0; //return 0 to signal success //#else //_NO_ASM // TODO - optimized assembler version // asm("movw r26, r24"); @@ -47,17 +47,17 @@ int rbuf_put(uint8_t* ptr, uint8_t b) int rbuf_get(uint8_t* ptr) { //#ifdef _NO_ASM - _lock(); //lock - uint8_t buf_w = ptr[1]; //get write index - uint8_t buf_r = ptr[2]; //get read index - _unlock(); //unlock - if (buf_r == buf_w) return -1; //return -1 to signal buffer empty - int ret = ptr[4 + buf_r]; //get byte from buffer - buf_r++; //increment read index - uint8_t buf_l = ptr[0]; //get length - if (buf_r >= buf_l) buf_r = 0; //rotate read index - ptr[2] = buf_r; //store read index - return ret; //return byte (0-255) + _lock(); //lock + uint8_t buf_w = ptr[1]; //get write index + uint8_t buf_r = ptr[2]; //get read index + _unlock(); //unlock + if (buf_r == buf_w) return -1; //return -1 to signal buffer empty + int ret = ptr[4 + buf_r]; //get byte from buffer + buf_r++; //increment read index + uint8_t buf_l = ptr[0]; //get length + if (buf_r >= buf_l) buf_r = 0; //rotate read index + ptr[2] = buf_r; //store read index + return ret; //return byte (0-255) // return 0; //return 0 to signal success //#else //_NO_ASM // TODO - optimized assembler version diff --git a/Firmware/sm4.c b/Firmware/sm4.c index 34cf8a3c91..d9386a4ad8 100755 --- a/Firmware/sm4.c +++ b/Firmware/sm4.c @@ -47,148 +47,180 @@ uint16_t sm4_cpu_time = 0; uint8_t sm4_get_dir(uint8_t axis) { - switch (axis) - { + switch (axis) + { #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3)) - case 0: return (PORTL & 2)?0:1; - case 1: return (PORTL & 1)?0:1; - case 2: return (PORTL & 4)?0:1; - case 3: return (PORTL & 64)?1:0; + case 0: + return (PORTL & 2)?0:1; + case 1: + return (PORTL & 1)?0:1; + case 2: + return (PORTL & 4)?0:1; + case 3: + return (PORTL & 64)?1:0; #elif ((MOTHERBOARD == BOARD_EINSY_1_0a)) - case 0: return (PORTL & 1)?1:0; - case 1: return (PORTL & 2)?0:1; - case 2: return (PORTL & 4)?1:0; - case 3: return (PORTL & 64)?0:1; + case 0: + return (PORTL & 1)?1:0; + case 1: + return (PORTL & 2)?0:1; + case 2: + return (PORTL & 4)?1:0; + case 3: + return (PORTL & 64)?0:1; #endif - } - return 0; + } + return 0; } void sm4_set_dir(uint8_t axis, uint8_t dir) { - switch (axis) - { + switch (axis) + { #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3)) - case 0: if (!dir) PORTL |= 2; else PORTL &= ~2; break; - case 1: if (!dir) PORTL |= 1; else PORTL &= ~1; break; - case 2: if (!dir) PORTL |= 4; else PORTL &= ~4; break; - case 3: if (dir) PORTL |= 64; else PORTL &= ~64; break; + case 0: + if (!dir) PORTL |= 2; + else PORTL &= ~2; + break; + case 1: + if (!dir) PORTL |= 1; + else PORTL &= ~1; + break; + case 2: + if (!dir) PORTL |= 4; + else PORTL &= ~4; + break; + case 3: + if (dir) PORTL |= 64; + else PORTL &= ~64; + break; #elif ((MOTHERBOARD == BOARD_EINSY_1_0a)) - case 0: if (dir) PORTL |= 1; else PORTL &= ~1; break; - case 1: if (!dir) PORTL |= 2; else PORTL &= ~2; break; - case 2: if (dir) PORTL |= 4; else PORTL &= ~4; break; - case 3: if (!dir) PORTL |= 64; else PORTL &= ~64; break; + case 0: + if (dir) PORTL |= 1; + else PORTL &= ~1; + break; + case 1: + if (!dir) PORTL |= 2; + else PORTL &= ~2; + break; + case 2: + if (dir) PORTL |= 4; + else PORTL &= ~4; + break; + case 3: + if (!dir) PORTL |= 64; + else PORTL &= ~64; + break; #endif - } - asm("nop"); + } + asm("nop"); } uint8_t sm4_get_dir_bits(void) { register uint8_t dir_bits = 0; register uint8_t portL = PORTL; - //TODO -optimize in asm + //TODO -optimize in asm #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3)) - if (portL & 2) dir_bits |= 1; - if (portL & 1) dir_bits |= 2; - if (portL & 4) dir_bits |= 4; - if (portL & 64) dir_bits |= 8; - dir_bits ^= 0x07; //invert XYZ, do not invert E + if (portL & 2) dir_bits |= 1; + if (portL & 1) dir_bits |= 2; + if (portL & 4) dir_bits |= 4; + if (portL & 64) dir_bits |= 8; + dir_bits ^= 0x07; //invert XYZ, do not invert E #elif ((MOTHERBOARD == BOARD_EINSY_1_0a)) - if (portL & 1) dir_bits |= 1; - if (portL & 2) dir_bits |= 2; - if (portL & 4) dir_bits |= 4; - if (portL & 64) dir_bits |= 8; - dir_bits ^= 0x0a; //invert YE, do not invert XZ + if (portL & 1) dir_bits |= 1; + if (portL & 2) dir_bits |= 2; + if (portL & 4) dir_bits |= 4; + if (portL & 64) dir_bits |= 8; + dir_bits ^= 0x0a; //invert YE, do not invert XZ #endif - return dir_bits; + return dir_bits; } void sm4_set_dir_bits(uint8_t dir_bits) { register uint8_t portL = PORTL; - portL &= 0xb8; //set direction bits to zero - //TODO -optimize in asm + portL &= 0xb8; //set direction bits to zero + //TODO -optimize in asm #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3)) - dir_bits ^= 0x07; //invert XYZ, do not invert E - if (dir_bits & 1) portL |= 2; //set X direction bit - if (dir_bits & 2) portL |= 1; //set Y direction bit - if (dir_bits & 4) portL |= 4; //set Z direction bit - if (dir_bits & 8) portL |= 64; //set E direction bit + dir_bits ^= 0x07; //invert XYZ, do not invert E + if (dir_bits & 1) portL |= 2; //set X direction bit + if (dir_bits & 2) portL |= 1; //set Y direction bit + if (dir_bits & 4) portL |= 4; //set Z direction bit + if (dir_bits & 8) portL |= 64; //set E direction bit #elif ((MOTHERBOARD == BOARD_EINSY_1_0a)) - dir_bits ^= 0x0a; //invert YE, do not invert XZ - if (dir_bits & 1) portL |= 1; //set X direction bit - if (dir_bits & 2) portL |= 2; //set Y direction bit - if (dir_bits & 4) portL |= 4; //set Z direction bit - if (dir_bits & 8) portL |= 64; //set E direction bit + dir_bits ^= 0x0a; //invert YE, do not invert XZ + if (dir_bits & 1) portL |= 1; //set X direction bit + if (dir_bits & 2) portL |= 2; //set Y direction bit + if (dir_bits & 4) portL |= 4; //set Z direction bit + if (dir_bits & 8) portL |= 64; //set E direction bit #endif - PORTL = portL; - asm("nop"); + PORTL = portL; + asm("nop"); } void sm4_do_step(uint8_t axes_mask) { #if ((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3) || (MOTHERBOARD == BOARD_EINSY_1_0a)) register uint8_t portC = PORTC & 0xf0; - PORTC = portC | (axes_mask & 0x0f); //set step signals by mask - asm("nop"); - PORTC = portC; //set step signals to zero - asm("nop"); + PORTC = portC | (axes_mask & 0x0f); //set step signals by mask + asm("nop"); + PORTC = portC; //set step signals to zero + asm("nop"); #endif //((MOTHERBOARD == BOARD_RAMBO_MINI_1_0) || (MOTHERBOARD == BOARD_RAMBO_MINI_1_3) || (MOTHERBOARD == BOARD_EINSY_1_0a)) } uint16_t sm4_line_xyze_ui(uint16_t dx, uint16_t dy, uint16_t dz, uint16_t de) { - uint16_t dd = (uint16_t)(sqrt((float)(((uint32_t)dx)*dx + ((uint32_t)dy*dy) + ((uint32_t)dz*dz) + ((uint32_t)de*de))) + 0.5); - uint16_t nd = dd; - uint16_t cx = dd; - uint16_t cy = dd; - uint16_t cz = dd; - uint16_t ce = dd; - uint16_t x = 0; - uint16_t y = 0; - uint16_t z = 0; - uint16_t e = 0; - while (nd) - { - if (sm4_stop_cb && (*sm4_stop_cb)()) break; - uint8_t sm = 0; //step mask - if (cx <= dx) - { - sm |= 1; - cx += dd; - x++; - } - if (cy <= dy) - { - sm |= 2; - cy += dd; - y++; - } - if (cz <= dz) - { - sm |= 4; - cz += dd; - z++; - } - if (ce <= de) - { - sm |= 4; - ce += dd; - e++; - } - cx -= dx; - cy -= dy; - cz -= dz; - ce -= de; - sm4_do_step(sm); - uint16_t delay = SM4_DEFDELAY; - if (sm4_calc_delay_cb) delay = (*sm4_calc_delay_cb)(nd, dd); - if (delay) delayMicroseconds(delay); - nd--; - } - if (sm4_update_pos_cb) (*sm4_update_pos_cb)(x, y, z, e); - return nd; + uint16_t dd = (uint16_t)(sqrt((float)(((uint32_t)dx)*dx + ((uint32_t)dy*dy) + ((uint32_t)dz*dz) + ((uint32_t)de*de))) + 0.5); + uint16_t nd = dd; + uint16_t cx = dd; + uint16_t cy = dd; + uint16_t cz = dd; + uint16_t ce = dd; + uint16_t x = 0; + uint16_t y = 0; + uint16_t z = 0; + uint16_t e = 0; + while (nd) + { + if (sm4_stop_cb && (*sm4_stop_cb)()) break; + uint8_t sm = 0; //step mask + if (cx <= dx) + { + sm |= 1; + cx += dd; + x++; + } + if (cy <= dy) + { + sm |= 2; + cy += dd; + y++; + } + if (cz <= dz) + { + sm |= 4; + cz += dd; + z++; + } + if (ce <= de) + { + sm |= 4; + ce += dd; + e++; + } + cx -= dx; + cy -= dy; + cz -= dz; + ce -= de; + sm4_do_step(sm); + uint16_t delay = SM4_DEFDELAY; + if (sm4_calc_delay_cb) delay = (*sm4_calc_delay_cb)(nd, dd); + if (delay) delayMicroseconds(delay); + nd--; + } + if (sm4_update_pos_cb) (*sm4_update_pos_cb)(x, y, z, e); + return nd; } diff --git a/Firmware/sound.cpp b/Firmware/sound.cpp index ba6ea726a1..2519a80363 100755 --- a/Firmware/sound.cpp +++ b/Firmware/sound.cpp @@ -21,107 +21,107 @@ static void Sound_DoSound_Alert(bool bOnce); void Sound_Init(void) { -SET_OUTPUT(BEEPER); -eSoundMode=(eSOUND_MODE)eeprom_read_byte((uint8_t*)EEPROM_SOUND_MODE); -if(eSoundMode==e_SOUND_MODE_NULL) - Sound_Default(); // je potreba provest i ulozeni do EEPROM + SET_OUTPUT(BEEPER); + eSoundMode=(eSOUND_MODE)eeprom_read_byte((uint8_t*)EEPROM_SOUND_MODE); + if(eSoundMode==e_SOUND_MODE_NULL) + Sound_Default(); // je potreba provest i ulozeni do EEPROM } void Sound_Default(void) { -eSoundMode=e_SOUND_MODE_DEFAULT; -Sound_SaveMode(); + eSoundMode=e_SOUND_MODE_DEFAULT; + Sound_SaveMode(); } void Sound_SaveMode(void) { -eeprom_update_byte((uint8_t*)EEPROM_SOUND_MODE,(uint8_t)eSoundMode); + eeprom_update_byte((uint8_t*)EEPROM_SOUND_MODE,(uint8_t)eSoundMode); } void Sound_CycleState(void) { -switch(eSoundMode) - { - case e_SOUND_MODE_LOUD: - eSoundMode=e_SOUND_MODE_ONCE; - break; - case e_SOUND_MODE_ONCE: - eSoundMode=e_SOUND_MODE_SILENT; - break; - case e_SOUND_MODE_SILENT: - eSoundMode=e_SOUND_MODE_MUTE; - break; - case e_SOUND_MODE_MUTE: - eSoundMode=e_SOUND_MODE_LOUD; - break; - default: - eSoundMode=e_SOUND_MODE_LOUD; - } -Sound_SaveMode(); + switch(eSoundMode) + { + case e_SOUND_MODE_LOUD: + eSoundMode=e_SOUND_MODE_ONCE; + break; + case e_SOUND_MODE_ONCE: + eSoundMode=e_SOUND_MODE_SILENT; + break; + case e_SOUND_MODE_SILENT: + eSoundMode=e_SOUND_MODE_MUTE; + break; + case e_SOUND_MODE_MUTE: + eSoundMode=e_SOUND_MODE_LOUD; + break; + default: + eSoundMode=e_SOUND_MODE_LOUD; + } + Sound_SaveMode(); } void Sound_MakeSound(eSOUND_TYPE eSoundType) { -switch(eSoundMode) - { - case e_SOUND_MODE_LOUD: - if(eSoundType==e_SOUND_TYPE_ButtonEcho) - Sound_DoSound_Echo(); - if(eSoundType==e_SOUND_TYPE_StandardPrompt) - Sound_DoSound_Prompt(); - if(eSoundType==e_SOUND_TYPE_StandardAlert) - Sound_DoSound_Alert(false); - break; - case e_SOUND_MODE_ONCE: - if(eSoundType==e_SOUND_TYPE_ButtonEcho) - Sound_DoSound_Echo(); - if(eSoundType==e_SOUND_TYPE_StandardPrompt) - Sound_DoSound_Prompt(); - if(eSoundType==e_SOUND_TYPE_StandardAlert) - Sound_DoSound_Alert(true); - break; - case e_SOUND_MODE_SILENT: - if(eSoundType==e_SOUND_TYPE_StandardAlert) - Sound_DoSound_Alert(true); - break; - case e_SOUND_MODE_MUTE: - break; - default: - ; - } + switch(eSoundMode) + { + case e_SOUND_MODE_LOUD: + if(eSoundType==e_SOUND_TYPE_ButtonEcho) + Sound_DoSound_Echo(); + if(eSoundType==e_SOUND_TYPE_StandardPrompt) + Sound_DoSound_Prompt(); + if(eSoundType==e_SOUND_TYPE_StandardAlert) + Sound_DoSound_Alert(false); + break; + case e_SOUND_MODE_ONCE: + if(eSoundType==e_SOUND_TYPE_ButtonEcho) + Sound_DoSound_Echo(); + if(eSoundType==e_SOUND_TYPE_StandardPrompt) + Sound_DoSound_Prompt(); + if(eSoundType==e_SOUND_TYPE_StandardAlert) + Sound_DoSound_Alert(true); + break; + case e_SOUND_MODE_SILENT: + if(eSoundType==e_SOUND_TYPE_StandardAlert) + Sound_DoSound_Alert(true); + break; + case e_SOUND_MODE_MUTE: + break; + default: + ; + } } static void Sound_DoSound_Echo(void) { -uint8_t nI; - -for(nI=0;nI<10;nI++) - { - WRITE(BEEPER,HIGH); - delayMicroseconds(100); - WRITE(BEEPER,LOW); - delayMicroseconds(100); - } + uint8_t nI; + + for(nI=0; nI<10; nI++) + { + WRITE(BEEPER,HIGH); + delayMicroseconds(100); + WRITE(BEEPER,LOW); + delayMicroseconds(100); + } } static void Sound_DoSound_Prompt(void) { -WRITE(BEEPER,HIGH); -delay_keep_alive(500); -WRITE(BEEPER,LOW); + WRITE(BEEPER,HIGH); + delay_keep_alive(500); + WRITE(BEEPER,LOW); } static void Sound_DoSound_Alert(bool bOnce) { -uint8_t nI,nMax; - -nMax=bOnce?1:3; -for(nI=0;nI 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; - } - else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times - step_rate = (step_rate >> 1)&0x7fff; - step_loops = 2; - } - else { - step_loops = 1; - } + 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; + } + else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times + step_rate = (step_rate >> 1)&0x7fff; + step_loops = 2; + } + else { + step_loops = 1; + } // 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 - 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); - MultiU16X8toH16(timer, tmp_step_rate, gain); - timer = (unsigned short)pgm_read_word_near(table_address) - timer; - } - else { // lower step rates - unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; - table_address += ((step_rate)>>1) & 0xfffc; - timer = (unsigned short)pgm_read_word_near(table_address); - timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); - } - if(timer < 100) { timer = 100; MYSERIAL.print(_N("Steprate too high: ")); MYSERIAL.println(step_rate); }//(20kHz this should never happen)////MSG_STEPPER_TOO_HIGH c=0 r=0 - return timer; + 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 + 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); + MultiU16X8toH16(timer, tmp_step_rate, gain); + timer = (unsigned short)pgm_read_word_near(table_address) - timer; + } + else { // lower step rates + unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0]; + table_address += ((step_rate)>>1) & 0xfffc; + timer = (unsigned short)pgm_read_word_near(table_address); + timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3); + } + if(timer < 100) { + timer = 100; //(20kHz this should never happen)////MSG_STEPPER_TOO_HIGH c=0 r=0 + MYSERIAL.print(_N("Steprate too high: ")); + MYSERIAL.println(step_rate); + } + return timer; } // "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) { #ifdef DEBUG_STACK_MONITOR - uint16_t sp = SPL + 256 * SPH; - if (sp < SP_min) SP_min = sp; + uint16_t sp = SPL + 256 * SPH; + if (sp < SP_min) SP_min = sp; #endif //DEBUG_STACK_MONITOR #ifdef LIN_ADVANCE - // If there are any e_steps planned, tick them. - bool run_main_isr = false; - if (e_steps) { - //WRITE_NC(LOGIC_ANALYZER_CH7, true); - uint8_t cnt = 0; - for (uint8_t i = estep_loops; e_steps && i --;) { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - -- e_steps; - cnt++; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); - } + // If there are any e_steps planned, tick them. + bool run_main_isr = false; + if (e_steps) { + //WRITE_NC(LOGIC_ANALYZER_CH7, true); + uint8_t cnt = 0; + for (uint8_t i = estep_loops; e_steps && i --;) { + WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); + -- e_steps; + cnt++; + WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); + } #ifdef FILAMENT_SENSOR - if (READ(E0_DIR_PIN) == INVERT_E0_DIR) - { - if (count_direction[E_AXIS] == 1) - fsensor_counter -= cnt; - else - fsensor_counter += cnt; - } - else - { - if (count_direction[E_AXIS] == 1) - fsensor_counter += cnt; - else - fsensor_counter -= cnt; - } + if (READ(E0_DIR_PIN) == INVERT_E0_DIR) + { + if (count_direction[E_AXIS] == 1) + fsensor_counter -= cnt; + else + fsensor_counter += cnt; + } + else + { + if (count_direction[E_AXIS] == 1) + fsensor_counter += cnt; + else + fsensor_counter -= cnt; + } #endif //FILAMENT_SENSOR - if (e_steps) { - // Plan another Linear Advance tick. - OCR1A = eISR_Rate; - nextMainISR -= eISR_Rate; - } else if (! (nextMainISR & 0x8000) || nextMainISR < 16) { - // The timer did not overflow and it is big enough, so it makes sense to plan it. - OCR1A = nextMainISR; - } else { - // The timer has overflown, or it is too small. Run the main ISR just after the Linear Advance routine - // in the current interrupt tick. - run_main_isr = true; - //FIXME pick the serial line. - } - //WRITE_NC(LOGIC_ANALYZER_CH7, false); - } else - run_main_isr = true; + if (e_steps) { + // Plan another Linear Advance tick. + OCR1A = eISR_Rate; + nextMainISR -= eISR_Rate; + } else if (! (nextMainISR & 0x8000) || nextMainISR < 16) { + // The timer did not overflow and it is big enough, so it makes sense to plan it. + OCR1A = nextMainISR; + } else { + // The timer has overflown, or it is too small. Run the main ISR just after the Linear Advance routine + // in the current interrupt tick. + run_main_isr = true; + //FIXME pick the serial line. + } + //WRITE_NC(LOGIC_ANALYZER_CH7, false); + } else + run_main_isr = true; - if (run_main_isr) + if (run_main_isr) #endif - isr(); + isr(); - // Don't run the ISR faster than possible - // Is there a 8us time left before the next interrupt triggers? - if (OCR1A < TCNT1 + 16) { + // Don't run the ISR faster than possible + // Is there a 8us time left before the next interrupt triggers? + if (OCR1A < TCNT1 + 16) { #ifdef DEBUG_STEPPER_TIMER_MISSED - // Verify whether the next planned timer interrupt has not been missed already. - // This debugging test takes < 1.125us - // This skews the profiling slightly as the fastest stepper timer - // interrupt repeats at a 100us rate (10kHz). - if (OCR1A + 40 < TCNT1) { - // The interrupt was delayed by more than 20us (which is 1/5th of the 10kHz ISR repeat rate). - // Give a warning. - stepper_timer_overflow_state = true; - stepper_timer_overflow_last = TCNT1 - OCR1A; - // Beep, the beeper will be cleared at the stepper_timer_overflow() called from the main thread. - WRITE(BEEPER, HIGH); - } + // Verify whether the next planned timer interrupt has not been missed already. + // This debugging test takes < 1.125us + // This skews the profiling slightly as the fastest stepper timer + // interrupt repeats at a 100us rate (10kHz). + if (OCR1A + 40 < TCNT1) { + // The interrupt was delayed by more than 20us (which is 1/5th of the 10kHz ISR repeat rate). + // Give a warning. + stepper_timer_overflow_state = true; + stepper_timer_overflow_last = TCNT1 - OCR1A; + // Beep, the beeper will be cleared at the stepper_timer_overflow() called from the main thread. + WRITE(BEEPER, HIGH); + } #endif - // Fix the next interrupt to be executed after 8us from now. - OCR1A = TCNT1 + 16; - } + // Fix the next interrupt to be executed after 8us from now. + OCR1A = TCNT1 + 16; + } } uint8_t last_dir_bits = 0; @@ -437,836 +441,836 @@ uint8_t st_backlash_y = 0; FORCE_INLINE void stepper_next_block() { - // Anything in the buffer? - //WRITE_NC(LOGIC_ANALYZER_CH2, true); - current_block = plan_get_current_block(); - if (current_block != NULL) { + // Anything in the buffer? + //WRITE_NC(LOGIC_ANALYZER_CH2, true); + current_block = plan_get_current_block(); + if (current_block != NULL) { #ifdef BACKLASH_X - if (current_block->steps_x.wide) - { //X-axis movement - if ((current_block->direction_bits ^ last_dir_bits) & 1) - { - printf_P(PSTR("BL %d\n"), (current_block->direction_bits & 1)?st_backlash_x:-st_backlash_x); - if (current_block->direction_bits & 1) - WRITE_NC(X_DIR_PIN, INVERT_X_DIR); - else - WRITE_NC(X_DIR_PIN, !INVERT_X_DIR); - _delay_us(100); - for (uint8_t i = 0; i < st_backlash_x; i++) - { - WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); - _delay_us(100); - WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); - _delay_us(900); - } - } - last_dir_bits &= ~1; - last_dir_bits |= current_block->direction_bits & 1; - } + if (current_block->steps_x.wide) + { //X-axis movement + if ((current_block->direction_bits ^ last_dir_bits) & 1) + { + printf_P(PSTR("BL %d\n"), (current_block->direction_bits & 1)?st_backlash_x:-st_backlash_x); + if (current_block->direction_bits & 1) + WRITE_NC(X_DIR_PIN, INVERT_X_DIR); + else + WRITE_NC(X_DIR_PIN, !INVERT_X_DIR); + _delay_us(100); + for (uint8_t i = 0; i < st_backlash_x; i++) + { + WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); + _delay_us(100); + WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); + _delay_us(900); + } + } + last_dir_bits &= ~1; + last_dir_bits |= current_block->direction_bits & 1; + } #endif #ifdef BACKLASH_Y - if (current_block->steps_y.wide) - { //Y-axis movement - if ((current_block->direction_bits ^ last_dir_bits) & 2) - { - printf_P(PSTR("BL %d\n"), (current_block->direction_bits & 2)?st_backlash_y:-st_backlash_y); - if (current_block->direction_bits & 2) - WRITE_NC(Y_DIR_PIN, INVERT_Y_DIR); - else - WRITE_NC(Y_DIR_PIN, !INVERT_Y_DIR); - _delay_us(100); - for (uint8_t i = 0; i < st_backlash_y; i++) - { - WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); - _delay_us(100); - WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); - _delay_us(900); - } - } - last_dir_bits &= ~2; - last_dir_bits |= current_block->direction_bits & 2; - } + if (current_block->steps_y.wide) + { //Y-axis movement + if ((current_block->direction_bits ^ last_dir_bits) & 2) + { + printf_P(PSTR("BL %d\n"), (current_block->direction_bits & 2)?st_backlash_y:-st_backlash_y); + if (current_block->direction_bits & 2) + WRITE_NC(Y_DIR_PIN, INVERT_Y_DIR); + else + WRITE_NC(Y_DIR_PIN, !INVERT_Y_DIR); + _delay_us(100); + for (uint8_t i = 0; i < st_backlash_y; i++) + { + WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + _delay_us(100); + WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); + _delay_us(900); + } + } + last_dir_bits &= ~2; + last_dir_bits |= current_block->direction_bits & 2; + } #endif #ifdef FILAMENT_SENSOR - fsensor_counter = 0; - fsensor_st_block_begin(current_block); + fsensor_counter = 0; + fsensor_st_block_begin(current_block); #endif //FILAMENT_SENSOR - // The busy flag is set by the plan_get_current_block() call. - // current_block->busy = true; - // Initializes the trapezoid generator from the current block. Called whenever a new - // block begins. - deceleration_time = 0; - // Set the nominal step loops to zero to indicate, that the timer value is not known yet. - // That means, delay the initialization of nominal step rate and step loops until the steady - // state is reached. - step_loops_nominal = 0; - acc_step_rate = uint16_t(current_block->initial_rate); - acceleration_time = calc_timer(acc_step_rate); + // The busy flag is set by the plan_get_current_block() call. + // current_block->busy = true; + // Initializes the trapezoid generator from the current block. Called whenever a new + // block begins. + deceleration_time = 0; + // Set the nominal step loops to zero to indicate, that the timer value is not known yet. + // That means, delay the initialization of nominal step rate and step loops until the steady + // state is reached. + step_loops_nominal = 0; + acc_step_rate = uint16_t(current_block->initial_rate); + acceleration_time = calc_timer(acc_step_rate); #ifdef LIN_ADVANCE - current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; + current_estep_rate = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; #endif /* LIN_ADVANCE */ - if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) { - counter_x.lo = -(current_block->step_event_count.lo >> 1); - counter_y.lo = counter_x.lo; - counter_z.lo = counter_x.lo; - counter_e.lo = counter_x.lo; - } else { - counter_x.wide = -(current_block->step_event_count.wide >> 1); - counter_y.wide = counter_x.wide; - counter_z.wide = counter_x.wide; - counter_e.wide = counter_x.wide; - } - step_events_completed.wide = 0; - // Set directions. - out_bits = current_block->direction_bits; - // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) - if((out_bits & (1<flag & BLOCK_FLAG_DDA_LOWRES) { + counter_x.lo = -(current_block->step_event_count.lo >> 1); + counter_y.lo = counter_x.lo; + counter_z.lo = counter_x.lo; + counter_e.lo = counter_x.lo; + } else { + counter_x.wide = -(current_block->step_event_count.wide >> 1); + counter_y.wide = counter_x.wide; + counter_z.wide = counter_x.wide; + counter_e.wide = counter_x.wide; + } + step_events_completed.wide = 0; + // Set directions. + out_bits = current_block->direction_bits; + // Set the direction bits (X_AXIS=A_AXIS and Y_AXIS=B_AXIS for COREXY) + if((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMINLIMIT) - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on - x_min_endstop = (READ(X_TMC2130_DIAG) != 0); - #else - // Normal homing - x_min_endstop = (READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); - #endif - if(x_min_endstop && old_x_min_endstop && (current_block->steps_x.wide > 0)) { - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_x_min_endstop = x_min_endstop; - #endif - } else { // +direction - #if ( (defined(X_MAX_PIN) && (X_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMAXLIMIT) - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on +#ifndef COREXY + if ((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMINLIMIT) +#ifdef TMC2130_SG_HOMING + // Stall guard homing turned on + x_min_endstop = (READ(X_TMC2130_DIAG) != 0); +#else + // Normal homing + x_min_endstop = (READ(X_MIN_PIN) != X_MIN_ENDSTOP_INVERTING); +#endif + if(x_min_endstop && old_x_min_endstop && (current_block->steps_x.wide > 0)) { + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_x_min_endstop = x_min_endstop; +#endif + } else { // +direction +#if ( (defined(X_MAX_PIN) && (X_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_XMAXLIMIT) +#ifdef TMC2130_SG_HOMING + // Stall guard homing turned on x_max_endstop = (READ(X_TMC2130_DIAG) != 0); - #else - // Normal homing - x_max_endstop = (READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); - #endif - if(x_max_endstop && old_x_max_endstop && (current_block->steps_x.wide > 0)){ - endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; - endstop_x_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; +#else + // Normal homing + x_max_endstop = (READ(X_MAX_PIN) != X_MAX_ENDSTOP_INVERTING); +#endif + if(x_max_endstop && old_x_max_endstop && (current_block->steps_x.wide > 0)) { + endstops_trigsteps[X_AXIS] = count_position[X_AXIS]; + endstop_x_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_x_max_endstop = x_max_endstop; +#endif } - old_x_max_endstop = x_max_endstop; - #endif - } - #ifndef COREXY - if ((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMINLIMIT) - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on - y_min_endstop = (READ(Y_TMC2130_DIAG) != 0); - #else - // Normal homing - y_min_endstop = (READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); - #endif - if(y_min_endstop && old_y_min_endstop && (current_block->steps_y.wide > 0)) { - endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; - endstop_y_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_y_min_endstop = y_min_endstop; - #endif - } else { // +direction - #if ( (defined(Y_MAX_PIN) && (Y_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMAXLIMIT) - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on +#ifndef COREXY + if ((out_bits & (1< -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMINLIMIT) +#ifdef TMC2130_SG_HOMING + // Stall guard homing turned on + y_min_endstop = (READ(Y_TMC2130_DIAG) != 0); +#else + // Normal homing + y_min_endstop = (READ(Y_MIN_PIN) != Y_MIN_ENDSTOP_INVERTING); +#endif + if(y_min_endstop && old_y_min_endstop && (current_block->steps_y.wide > 0)) { + endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; + endstop_y_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_y_min_endstop = y_min_endstop; +#endif + } else { // +direction +#if ( (defined(Y_MAX_PIN) && (Y_MAX_PIN > -1)) || defined(TMC2130_SG_HOMING) ) && !defined(DEBUG_DISABLE_YMAXLIMIT) +#ifdef TMC2130_SG_HOMING + // Stall guard homing turned on y_max_endstop = (READ(Y_TMC2130_DIAG) != 0); - #else - // Normal homing - y_max_endstop = (READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); - #endif - if(y_max_endstop && old_y_max_endstop && (current_block->steps_y.wide > 0)){ - endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; - endstop_y_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; +#else + // Normal homing + y_max_endstop = (READ(Y_MAX_PIN) != Y_MAX_ENDSTOP_INVERTING); +#endif + if(y_max_endstop && old_y_max_endstop && (current_block->steps_y.wide > 0)) { + endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS]; + endstop_y_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_y_max_endstop = y_max_endstop; +#endif } - old_y_max_endstop = y_max_endstop; - #endif - } - if ((out_bits & (1< -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) - if (! check_z_endstop) { - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on + if ((out_bits & (1< -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) + if (! check_z_endstop) { +#ifdef TMC2130_SG_HOMING + // Stall guard homing turned on #ifdef TMC2130_STEALTH_Z - if ((tmc2130_mode == TMC2130_MODE_SILENT) && !(tmc2130_sg_homing_axes_mask & 0x04)) - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); - else + if ((tmc2130_mode == TMC2130_MODE_SILENT) && !(tmc2130_sg_homing_axes_mask & 0x04)) + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); + else #endif //TMC2130_STEALTH_Z - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); - #else - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); - #endif //TMC2130_SG_HOMING - if(z_min_endstop && old_z_min_endstop && (current_block->steps_z.wide > 0)) { - endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; - endstop_z_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_z_min_endstop = z_min_endstop; - } - #endif - } else { // +direction - #if defined(Z_MAX_PIN) && (Z_MAX_PIN > -1) && !defined(DEBUG_DISABLE_ZMAXLIMIT) - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); +#else + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); +#endif //TMC2130_SG_HOMING + if(z_min_endstop && old_z_min_endstop && (current_block->steps_z.wide > 0)) { + endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; + endstop_z_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_z_min_endstop = z_min_endstop; + } +#endif + } else { // +direction +#if defined(Z_MAX_PIN) && (Z_MAX_PIN > -1) && !defined(DEBUG_DISABLE_ZMAXLIMIT) +#ifdef TMC2130_SG_HOMING + // Stall guard homing turned on #ifdef TMC2130_STEALTH_Z - if ((tmc2130_mode == TMC2130_MODE_SILENT) && !(tmc2130_sg_homing_axes_mask & 0x04)) - z_max_endstop = false; - else + if ((tmc2130_mode == TMC2130_MODE_SILENT) && !(tmc2130_sg_homing_axes_mask & 0x04)) + z_max_endstop = false; + else #endif //TMC2130_STEALTH_Z - z_max_endstop = (READ(Z_TMC2130_DIAG) != 0); - #else - z_max_endstop = (READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); - #endif //TMC2130_SG_HOMING - if(z_max_endstop && old_z_max_endstop && (current_block->steps_z.wide > 0)) { - endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; - endstop_z_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; + z_max_endstop = (READ(Z_TMC2130_DIAG) != 0); +#else + z_max_endstop = (READ(Z_MAX_PIN) != Z_MAX_ENDSTOP_INVERTING); +#endif //TMC2130_SG_HOMING + if(z_max_endstop && old_z_max_endstop && (current_block->steps_z.wide > 0)) { + endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; + endstop_z_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_z_max_endstop = z_max_endstop; +#endif } - old_z_max_endstop = z_max_endstop; - #endif } - } - - // Supporting stopping on a trigger of the Z-stop induction sensor, not only for the Z-minus movements. - #if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) - if (check_z_endstop) { - // Check the Z min end-stop no matter what. - // Good for searching for the center of an induction target. - #ifdef TMC2130_SG_HOMING - // Stall guard homing turned on + + // Supporting stopping on a trigger of the Z-stop induction sensor, not only for the Z-minus movements. +#if defined(Z_MIN_PIN) && (Z_MIN_PIN > -1) && !defined(DEBUG_DISABLE_ZMINLIMIT) + if (check_z_endstop) { + // Check the Z min end-stop no matter what. + // Good for searching for the center of an induction target. +#ifdef TMC2130_SG_HOMING + // Stall guard homing turned on #ifdef TMC2130_STEALTH_Z - if ((tmc2130_mode == TMC2130_MODE_SILENT) && !(tmc2130_sg_homing_axes_mask & 0x04)) - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); - else + if ((tmc2130_mode == TMC2130_MODE_SILENT) && !(tmc2130_sg_homing_axes_mask & 0x04)) + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); + else #endif //TMC2130_STEALTH_Z - z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); - #else + z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING) || (READ(Z_TMC2130_DIAG) != 0); +#else z_min_endstop = (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING); - #endif //TMC2130_SG_HOMING - if(z_min_endstop && old_z_min_endstop) { - endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; - endstop_z_hit=true; - step_events_completed.wide = current_block->step_event_count.wide; - } - old_z_min_endstop = z_min_endstop; - } - #endif +#endif //TMC2130_SG_HOMING + if(z_min_endstop && old_z_min_endstop) { + endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS]; + endstop_z_hit=true; + step_events_completed.wide = current_block->step_event_count.wide; + } + old_z_min_endstop = z_min_endstop; + } +#endif } FORCE_INLINE void stepper_tick_lowres() { - for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) - MSerial.checkRx(); // Check for serial chars. - // Step in X axis - counter_x.lo += current_block->steps_x.lo; - if (counter_x.lo > 0) { - WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); + for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) + MSerial.checkRx(); // Check for serial chars. + // Step in X axis + counter_x.lo += current_block->steps_x.lo; + if (counter_x.lo > 0) { + WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); #ifdef DEBUG_XSTEP_DUP_PIN - WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); + WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); #endif //DEBUG_XSTEP_DUP_PIN - counter_x.lo -= current_block->step_event_count.lo; - count_position[X_AXIS]+=count_direction[X_AXIS]; - WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); + counter_x.lo -= current_block->step_event_count.lo; + count_position[X_AXIS]+=count_direction[X_AXIS]; + WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); #ifdef DEBUG_XSTEP_DUP_PIN - WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); + WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); #endif //DEBUG_XSTEP_DUP_PIN - } - // Step in Y axis - counter_y.lo += current_block->steps_y.lo; - if (counter_y.lo > 0) { - WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + } + // Step in Y axis + counter_y.lo += current_block->steps_y.lo; + if (counter_y.lo > 0) { + WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); #ifdef DEBUG_YSTEP_DUP_PIN - WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN); + WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN); #endif //DEBUG_YSTEP_DUP_PIN - counter_y.lo -= current_block->step_event_count.lo; - count_position[Y_AXIS]+=count_direction[Y_AXIS]; - WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); + counter_y.lo -= current_block->step_event_count.lo; + count_position[Y_AXIS]+=count_direction[Y_AXIS]; + WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); #ifdef DEBUG_YSTEP_DUP_PIN - WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); + WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); #endif //DEBUG_YSTEP_DUP_PIN - } - // Step in Z axis - counter_z.lo += current_block->steps_z.lo; - if (counter_z.lo > 0) { - WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - counter_z.lo -= current_block->step_event_count.lo; - count_position[Z_AXIS]+=count_direction[Z_AXIS]; - WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); - } - // Step in E axis - counter_e.lo += current_block->steps_e.lo; - if (counter_e.lo > 0) { + } + // Step in Z axis + counter_z.lo += current_block->steps_z.lo; + if (counter_z.lo > 0) { + WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); + counter_z.lo -= current_block->step_event_count.lo; + count_position[Z_AXIS]+=count_direction[Z_AXIS]; + WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); + } + // Step in E axis + counter_e.lo += current_block->steps_e.lo; + if (counter_e.lo > 0) { #ifndef LIN_ADVANCE - WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); + WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); #endif /* LIN_ADVANCE */ - counter_e.lo -= current_block->step_event_count.lo; - count_position[E_AXIS] += count_direction[E_AXIS]; + counter_e.lo -= current_block->step_event_count.lo; + count_position[E_AXIS] += count_direction[E_AXIS]; #ifdef LIN_ADVANCE - ++ e_steps; + ++ e_steps; #else - #ifdef FILAMENT_SENSOR - ++ fsensor_counter; - #endif //FILAMENT_SENSOR - WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); +#ifdef FILAMENT_SENSOR + ++ fsensor_counter; +#endif //FILAMENT_SENSOR + WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif + } + if(++ step_events_completed.lo >= current_block->step_event_count.lo) + break; } - if(++ step_events_completed.lo >= current_block->step_event_count.lo) - break; - } } FORCE_INLINE void stepper_tick_highres() { - for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) - MSerial.checkRx(); // Check for serial chars. - // Step in X axis - counter_x.wide += current_block->steps_x.wide; - if (counter_x.wide > 0) { - WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); + for (uint8_t i=0; i < step_loops; ++ i) { // Take multiple steps per interrupt (For high speed moves) + MSerial.checkRx(); // Check for serial chars. + // Step in X axis + counter_x.wide += current_block->steps_x.wide; + if (counter_x.wide > 0) { + WRITE_NC(X_STEP_PIN, !INVERT_X_STEP_PIN); #ifdef DEBUG_XSTEP_DUP_PIN - WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); + WRITE_NC(DEBUG_XSTEP_DUP_PIN,!INVERT_X_STEP_PIN); #endif //DEBUG_XSTEP_DUP_PIN - counter_x.wide -= current_block->step_event_count.wide; - count_position[X_AXIS]+=count_direction[X_AXIS]; - WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); + counter_x.wide -= current_block->step_event_count.wide; + count_position[X_AXIS]+=count_direction[X_AXIS]; + WRITE_NC(X_STEP_PIN, INVERT_X_STEP_PIN); #ifdef DEBUG_XSTEP_DUP_PIN - WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); + WRITE_NC(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); #endif //DEBUG_XSTEP_DUP_PIN - } - // Step in Y axis - counter_y.wide += current_block->steps_y.wide; - if (counter_y.wide > 0) { - WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); + } + // Step in Y axis + counter_y.wide += current_block->steps_y.wide; + if (counter_y.wide > 0) { + WRITE_NC(Y_STEP_PIN, !INVERT_Y_STEP_PIN); #ifdef DEBUG_YSTEP_DUP_PIN - WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN); + WRITE_NC(DEBUG_YSTEP_DUP_PIN,!INVERT_Y_STEP_PIN); #endif //DEBUG_YSTEP_DUP_PIN - counter_y.wide -= current_block->step_event_count.wide; - count_position[Y_AXIS]+=count_direction[Y_AXIS]; - WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); + counter_y.wide -= current_block->step_event_count.wide; + count_position[Y_AXIS]+=count_direction[Y_AXIS]; + WRITE_NC(Y_STEP_PIN, INVERT_Y_STEP_PIN); #ifdef DEBUG_YSTEP_DUP_PIN - WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); + WRITE_NC(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); #endif //DEBUG_YSTEP_DUP_PIN - } - // Step in Z axis - counter_z.wide += current_block->steps_z.wide; - if (counter_z.wide > 0) { - WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); - counter_z.wide -= current_block->step_event_count.wide; - count_position[Z_AXIS]+=count_direction[Z_AXIS]; - WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); - } - // Step in E axis - counter_e.wide += current_block->steps_e.wide; - if (counter_e.wide > 0) { + } + // Step in Z axis + counter_z.wide += current_block->steps_z.wide; + if (counter_z.wide > 0) { + WRITE_NC(Z_STEP_PIN, !INVERT_Z_STEP_PIN); + counter_z.wide -= current_block->step_event_count.wide; + count_position[Z_AXIS]+=count_direction[Z_AXIS]; + WRITE_NC(Z_STEP_PIN, INVERT_Z_STEP_PIN); + } + // Step in E axis + counter_e.wide += current_block->steps_e.wide; + if (counter_e.wide > 0) { #ifndef LIN_ADVANCE - WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); + WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN); #endif /* LIN_ADVANCE */ - counter_e.wide -= current_block->step_event_count.wide; - count_position[E_AXIS]+=count_direction[E_AXIS]; + counter_e.wide -= current_block->step_event_count.wide; + count_position[E_AXIS]+=count_direction[E_AXIS]; #ifdef LIN_ADVANCE - ++ e_steps; + ++ e_steps; #else - #ifdef FILAMENT_SENSOR - ++ fsensor_counter; - #endif //FILAMENT_SENSOR - WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); +#ifdef FILAMENT_SENSOR + ++ fsensor_counter; +#endif //FILAMENT_SENSOR + WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN); #endif + } + if(++ step_events_completed.wide >= current_block->step_event_count.wide) + break; } - if(++ step_events_completed.wide >= current_block->step_event_count.wide) - break; - } } // 50us delay #define LIN_ADV_FIRST_TICK_DELAY 100 FORCE_INLINE void isr() { - //WRITE_NC(LOGIC_ANALYZER_CH0, true); + //WRITE_NC(LOGIC_ANALYZER_CH0, true); - //if (UVLO) uvlo(); - // If there is no current block, attempt to pop one from the buffer - if (current_block == NULL) - stepper_next_block(); + //if (UVLO) uvlo(); + // If there is no current block, attempt to pop one from the buffer + if (current_block == NULL) + stepper_next_block(); - if (current_block != NULL) - { - stepper_check_endstops(); + if (current_block != NULL) + { + stepper_check_endstops(); #ifdef LIN_ADVANCE - e_steps = 0; + e_steps = 0; #endif /* LIN_ADVANCE */ - if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) - stepper_tick_lowres(); - else - stepper_tick_highres(); + if (current_block->flag & BLOCK_FLAG_DDA_LOWRES) + stepper_tick_lowres(); + else + stepper_tick_highres(); #ifdef LIN_ADVANCE - if (out_bits&(1<use_advance_lead) { - //int esteps_inc = 0; - //esteps_inc = current_estep_rate - current_adv_steps; - //e_steps += esteps_inc; - e_steps += current_estep_rate - current_adv_steps; + if (out_bits&(1<use_advance_lead) { + //int esteps_inc = 0; + //esteps_inc = current_estep_rate - current_adv_steps; + //e_steps += esteps_inc; + e_steps += current_estep_rate - current_adv_steps; #if 0 - if (abs(esteps_inc) > 4) { - LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc); - if (esteps_inc < -511 || esteps_inc > 511) - LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc >> 9); - } + if (abs(esteps_inc) > 4) { + LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc); + if (esteps_inc < -511 || esteps_inc > 511) + LOGIC_ANALYZER_SERIAL_TX_WRITE(esteps_inc >> 9); + } #endif - current_adv_steps = current_estep_rate; - } - // If we have esteps to execute, step some of them now. - if (e_steps) { - //WRITE_NC(LOGIC_ANALYZER_CH7, true); - // Set the step direction. - bool neg = e_steps < 0; - { - bool dir = - #ifdef SNMM - (neg == (mmu_extruder & 1)) - #else - neg - #endif - ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder. - WRITE_NC(E0_DIR_PIN, dir); - if (neg) - // Flip the e_steps counter to be always positive. - e_steps = - e_steps; + current_adv_steps = current_estep_rate; } - // Tick min(step_loops, abs(e_steps)). - estep_loops = (e_steps & 0x0ff00) ? 4 : e_steps; - if (step_loops < estep_loops) - estep_loops = step_loops; + // If we have esteps to execute, step some of them now. + if (e_steps) { + //WRITE_NC(LOGIC_ANALYZER_CH7, true); + // Set the step direction. + bool neg = e_steps < 0; + { + bool dir = +#ifdef SNMM + (neg == (mmu_extruder & 1)) +#else + neg +#endif + ? INVERT_E0_DIR : !INVERT_E0_DIR; //If we have SNMM, reverse every second extruder. + WRITE_NC(E0_DIR_PIN, dir); + if (neg) + // Flip the e_steps counter to be always positive. + e_steps = - e_steps; + } + // Tick min(step_loops, abs(e_steps)). + estep_loops = (e_steps & 0x0ff00) ? 4 : e_steps; + if (step_loops < estep_loops) + estep_loops = step_loops; #ifdef FILAMENT_SENSOR - if (READ(E0_DIR_PIN) == INVERT_E0_DIR) - { - if (count_direction[E_AXIS] == 1) - fsensor_counter -= estep_loops; - else - fsensor_counter += estep_loops; - } - else - { - if (count_direction[E_AXIS] == 1) - fsensor_counter += estep_loops; - else - fsensor_counter -= estep_loops; - } + if (READ(E0_DIR_PIN) == INVERT_E0_DIR) + { + if (count_direction[E_AXIS] == 1) + fsensor_counter -= estep_loops; + else + fsensor_counter += estep_loops; + } + else + { + if (count_direction[E_AXIS] == 1) + fsensor_counter += estep_loops; + else + fsensor_counter -= estep_loops; + } #endif //FILAMENT_SENSOR - do { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - -- e_steps; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); - } while (-- estep_loops != 0); - //WRITE_NC(LOGIC_ANALYZER_CH7, false); - MSerial.checkRx(); // Check for serial chars. - } + do { + WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); + -- e_steps; + WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); + } while (-- estep_loops != 0); + //WRITE_NC(LOGIC_ANALYZER_CH7, false); + MSerial.checkRx(); // Check for serial chars. + } #endif - // Calculare new timer value - // 13.38-14.63us for steady state, - // 25.12us for acceleration / deceleration. - { - //WRITE_NC(LOGIC_ANALYZER_CH1, true); - if (step_events_completed.wide <= (unsigned long int)current_block->accelerate_until) { - // v = t * a -> acc_step_rate = acceleration_time * current_block->acceleration_rate - MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); - acc_step_rate += uint16_t(current_block->initial_rate); - // upper limit - if(acc_step_rate > uint16_t(current_block->nominal_rate)) - acc_step_rate = current_block->nominal_rate; - // step_rate to timer interval - uint16_t timer = calc_timer(acc_step_rate); - _NEXT_ISR(timer); - acceleration_time += timer; - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - // int32_t = (uint16_t * uint32_t) >> 17 - current_estep_rate = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; - #endif - } - else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { - uint16_t step_rate; - MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); - step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. - if ((step_rate & 0x8000) || step_rate < uint16_t(current_block->final_rate)) { - // Result is negative or too small. - step_rate = uint16_t(current_block->final_rate); - } - // Step_rate to timer interval. - uint16_t timer = calc_timer(step_rate); - _NEXT_ISR(timer); - deceleration_time += timer; - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - current_estep_rate = ((uint32_t)step_rate * current_block->abs_adv_steps_multiplier8) >> 17; - #endif - } - else { - if (! step_loops_nominal) { - // Calculation of the steady state timer rate has been delayed to the 1st tick of the steady state to lower - // the initial interrupt blocking. - OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate)); - step_loops_nominal = step_loops; - #ifdef LIN_ADVANCE - if (current_block->use_advance_lead) - current_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17; - #endif + // Calculare new timer value + // 13.38-14.63us for steady state, + // 25.12us for acceleration / deceleration. + { + //WRITE_NC(LOGIC_ANALYZER_CH1, true); + if (step_events_completed.wide <= (unsigned long int)current_block->accelerate_until) { + // v = t * a -> acc_step_rate = acceleration_time * current_block->acceleration_rate + MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate); + acc_step_rate += uint16_t(current_block->initial_rate); + // upper limit + if(acc_step_rate > uint16_t(current_block->nominal_rate)) + acc_step_rate = current_block->nominal_rate; + // step_rate to timer interval + uint16_t timer = calc_timer(acc_step_rate); + _NEXT_ISR(timer); + acceleration_time += timer; +#ifdef LIN_ADVANCE + if (current_block->use_advance_lead) + // int32_t = (uint16_t * uint32_t) >> 17 + current_estep_rate = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17; +#endif + } + else if (step_events_completed.wide > (unsigned long int)current_block->decelerate_after) { + uint16_t step_rate; + MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate); + step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point. + if ((step_rate & 0x8000) || step_rate < uint16_t(current_block->final_rate)) { + // Result is negative or too small. + step_rate = uint16_t(current_block->final_rate); + } + // Step_rate to timer interval. + uint16_t timer = calc_timer(step_rate); + _NEXT_ISR(timer); + deceleration_time += timer; +#ifdef LIN_ADVANCE + if (current_block->use_advance_lead) + current_estep_rate = ((uint32_t)step_rate * current_block->abs_adv_steps_multiplier8) >> 17; +#endif + } + else { + if (! step_loops_nominal) { + // Calculation of the steady state timer rate has been delayed to the 1st tick of the steady state to lower + // the initial interrupt blocking. + OCR1A_nominal = calc_timer(uint16_t(current_block->nominal_rate)); + step_loops_nominal = step_loops; +#ifdef LIN_ADVANCE + if (current_block->use_advance_lead) + current_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17; +#endif + } + _NEXT_ISR(OCR1A_nominal); + } + //WRITE_NC(LOGIC_ANALYZER_CH1, false); } - _NEXT_ISR(OCR1A_nominal); - } - //WRITE_NC(LOGIC_ANALYZER_CH1, false); - } #ifdef LIN_ADVANCE - if (e_steps && current_block->use_advance_lead) { - //WRITE_NC(LOGIC_ANALYZER_CH7, true); - MSerial.checkRx(); // Check for serial chars. - // Some of the E steps were not ticked yet. Plan additional interrupts. - uint16_t now = TCNT1; - // Plan the first linear advance interrupt after 50us from now. - uint16_t to_go = nextMainISR - now - LIN_ADV_FIRST_TICK_DELAY; - eISR_Rate = 0; - if ((to_go & 0x8000) == 0) { - // The to_go number is not negative. - // Count the number of 7812,5 ticks, that fit into to_go 2MHz ticks. - uint8_t ticks = to_go >> 8; - if (ticks == 1) { - // Avoid running the following loop for a very short interval. - estep_loops = 255; - eISR_Rate = 1; - } else if ((e_steps & 0x0ff00) == 0) { - // e_steps <= 0x0ff - if (uint8_t(e_steps) <= ticks) { - // Spread the e_steps along the whole go_to interval. - eISR_Rate = to_go / uint8_t(e_steps); - estep_loops = 1; - } else if (ticks != 0) { - // At least one tick fits into the to_go interval. Calculate the e-step grouping. - uint8_t e = uint8_t(e_steps) >> 1; - estep_loops = 2; - while (e > ticks) { - e >>= 1; - estep_loops <<= 1; + if (e_steps && current_block->use_advance_lead) { + //WRITE_NC(LOGIC_ANALYZER_CH7, true); + MSerial.checkRx(); // Check for serial chars. + // Some of the E steps were not ticked yet. Plan additional interrupts. + uint16_t now = TCNT1; + // Plan the first linear advance interrupt after 50us from now. + uint16_t to_go = nextMainISR - now - LIN_ADV_FIRST_TICK_DELAY; + eISR_Rate = 0; + if ((to_go & 0x8000) == 0) { + // The to_go number is not negative. + // Count the number of 7812,5 ticks, that fit into to_go 2MHz ticks. + uint8_t ticks = to_go >> 8; + if (ticks == 1) { + // Avoid running the following loop for a very short interval. + estep_loops = 255; + eISR_Rate = 1; + } else if ((e_steps & 0x0ff00) == 0) { + // e_steps <= 0x0ff + if (uint8_t(e_steps) <= ticks) { + // Spread the e_steps along the whole go_to interval. + eISR_Rate = to_go / uint8_t(e_steps); + estep_loops = 1; + } else if (ticks != 0) { + // At least one tick fits into the to_go interval. Calculate the e-step grouping. + uint8_t e = uint8_t(e_steps) >> 1; + estep_loops = 2; + while (e > ticks) { + e >>= 1; + estep_loops <<= 1; + } + // Now the estep_loops contains the number of loops of power of 2, that will be sufficient + // to squeeze enough of Linear Advance ticks until nextMainISR. + // Calculate the tick rate. + eISR_Rate = to_go / ticks; + } + } else { + // This is an exterme case with too many e_steps inserted by the linear advance. + // At least one tick fits into the to_go interval. Calculate the e-step grouping. + estep_loops = 2; + uint16_t e = e_steps >> 1; + while (e & 0x0ff00) { + e >>= 1; + estep_loops <<= 1; + } + while (uint8_t(e) > ticks) { + e >>= 1; + estep_loops <<= 1; + } + // Now the estep_loops contains the number of loops of power of 2, that will be sufficient + // to squeeze enough of Linear Advance ticks until nextMainISR. + // Calculate the tick rate. + eISR_Rate = to_go / ticks; + } } - // Now the estep_loops contains the number of loops of power of 2, that will be sufficient - // to squeeze enough of Linear Advance ticks until nextMainISR. - // Calculate the tick rate. - eISR_Rate = to_go / ticks; - } - } else { - // This is an exterme case with too many e_steps inserted by the linear advance. - // At least one tick fits into the to_go interval. Calculate the e-step grouping. - estep_loops = 2; - uint16_t e = e_steps >> 1; - while (e & 0x0ff00) { - e >>= 1; - estep_loops <<= 1; - } - while (uint8_t(e) > ticks) { - e >>= 1; - estep_loops <<= 1; - } - // Now the estep_loops contains the number of loops of power of 2, that will be sufficient - // to squeeze enough of Linear Advance ticks until nextMainISR. - // Calculate the tick rate. - eISR_Rate = to_go / ticks; - } - } - if (eISR_Rate == 0) { - // There is not enough time to fit even a single additional tick. - // Tick all the extruder ticks now. - MSerial.checkRx(); // Check for serial chars. + if (eISR_Rate == 0) { + // There is not enough time to fit even a single additional tick. + // Tick all the extruder ticks now. + MSerial.checkRx(); // Check for serial chars. #ifdef FILAMENT_SENSOR - if (READ(E0_DIR_PIN) == INVERT_E0_DIR) - { - if (count_direction[E_AXIS] == 1) - fsensor_counter -= e_steps; - else - fsensor_counter += e_steps; - } - else - { - if (count_direction[E_AXIS] == 1) - fsensor_counter += e_steps; - else - fsensor_counter -= e_steps; - } + if (READ(E0_DIR_PIN) == INVERT_E0_DIR) + { + if (count_direction[E_AXIS] == 1) + fsensor_counter -= e_steps; + else + fsensor_counter += e_steps; + } + else + { + if (count_direction[E_AXIS] == 1) + fsensor_counter += e_steps; + else + fsensor_counter -= e_steps; + } #endif //FILAMENT_SENSOR - do { - WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); - -- e_steps; - WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); - } while (e_steps); - OCR1A = nextMainISR; - } else { - // Tick the 1st Linear Advance interrupt after 50us from now. - nextMainISR -= LIN_ADV_FIRST_TICK_DELAY; - OCR1A = now + LIN_ADV_FIRST_TICK_DELAY; - } - //WRITE_NC(LOGIC_ANALYZER_CH7, false); - } else - OCR1A = nextMainISR; + do { + WRITE_NC(E0_STEP_PIN, !INVERT_E_STEP_PIN); + -- e_steps; + WRITE_NC(E0_STEP_PIN, INVERT_E_STEP_PIN); + } while (e_steps); + OCR1A = nextMainISR; + } else { + // Tick the 1st Linear Advance interrupt after 50us from now. + nextMainISR -= LIN_ADV_FIRST_TICK_DELAY; + OCR1A = now + LIN_ADV_FIRST_TICK_DELAY; + } + //WRITE_NC(LOGIC_ANALYZER_CH7, false); + } else + OCR1A = nextMainISR; #endif - // If current block is finished, reset pointer - if (step_events_completed.wide >= current_block->step_event_count.wide) { + // If current block is finished, reset pointer + if (step_events_completed.wide >= current_block->step_event_count.wide) { #ifdef FILAMENT_SENSOR - fsensor_st_block_chunk(current_block, fsensor_counter); - fsensor_counter = 0; + fsensor_st_block_chunk(current_block, fsensor_counter); + fsensor_counter = 0; #endif //FILAMENT_SENSOR - current_block = NULL; - plan_discard_current_block(); - } + current_block = NULL; + plan_discard_current_block(); + } #ifdef FILAMENT_SENSOR - else if ((fsensor_counter >= fsensor_chunk_len)) - { - fsensor_st_block_chunk(current_block, fsensor_counter); - fsensor_counter = 0; - } + else if ((fsensor_counter >= fsensor_chunk_len)) + { + fsensor_st_block_chunk(current_block, fsensor_counter); + fsensor_counter = 0; + } #endif //FILAMENT_SENSOR - } + } #ifdef TMC2130 - tmc2130_st_isr(); + tmc2130_st_isr(); #endif //TMC2130 - //WRITE_NC(LOGIC_ANALYZER_CH0, false); + //WRITE_NC(LOGIC_ANALYZER_CH0, false); } #ifdef LIN_ADVANCE void clear_current_adv_vars() { - e_steps = 0; //Should be already 0 at an filament change event, but just to be sure.. - current_adv_steps = 0; + e_steps = 0; //Should be already 0 at an filament change event, but just to be sure.. + current_adv_steps = 0; } #endif // LIN_ADVANCE - + void st_init() { #ifdef TMC2130 - tmc2130_init(); + tmc2130_init(); #endif //TMC2130 - st_current_init(); //Initialize Digipot Motor Current - microstep_init(); //Initialize Microstepping Pins + st_current_init(); //Initialize Digipot Motor Current + microstep_init(); //Initialize Microstepping Pins - //Initialize Dir Pins - #if defined(X_DIR_PIN) && X_DIR_PIN > -1 + //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 +#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 +#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(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); - #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(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 SET_OUTPUT(E0_DIR_PIN); - #endif - #if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1) +#endif +#if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1) SET_OUTPUT(E1_DIR_PIN); - #endif - #if defined(E2_DIR_PIN) && (E2_DIR_PIN > -1) +#endif +#if defined(E2_DIR_PIN) && (E2_DIR_PIN > -1) SET_OUTPUT(E2_DIR_PIN); - #endif +#endif - //Initialize Enable Pins - steppers default to disabled. + //Initialize Enable Pins - steppers default to disabled. - #if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 +#if defined(X_ENABLE_PIN) && X_ENABLE_PIN > -1 SET_OUTPUT(X_ENABLE_PIN); if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH); - #endif - #if defined(X2_ENABLE_PIN) && X2_ENABLE_PIN > -1 +#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 +#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 + +#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); - #endif - #endif - #if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1) +#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); +#endif +#endif +#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1) SET_OUTPUT(E0_ENABLE_PIN); if(!E_ENABLE_ON) WRITE(E0_ENABLE_PIN,HIGH); - #endif - #if defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1) +#endif +#if defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1) SET_OUTPUT(E1_ENABLE_PIN); if(!E_ENABLE_ON) WRITE(E1_ENABLE_PIN,HIGH); - #endif - #if defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1) +#endif +#if defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1) SET_OUTPUT(E2_ENABLE_PIN); if(!E_ENABLE_ON) WRITE(E2_ENABLE_PIN,HIGH); - #endif +#endif - //endstops and pullups + //endstops and pullups - #ifdef TMC2130_SG_HOMING +#ifdef TMC2130_SG_HOMING SET_INPUT(X_TMC2130_DIAG); WRITE(X_TMC2130_DIAG,HIGH); - + SET_INPUT(Y_TMC2130_DIAG); WRITE(Y_TMC2130_DIAG,HIGH); - + SET_INPUT(Z_TMC2130_DIAG); WRITE(Z_TMC2130_DIAG,HIGH); - SET_INPUT(E0_TMC2130_DIAG); + SET_INPUT(E0_TMC2130_DIAG); WRITE(E0_TMC2130_DIAG,HIGH); - - #endif - - #if defined(X_MIN_PIN) && X_MIN_PIN > -1 + +#endif + +#if defined(X_MIN_PIN) && X_MIN_PIN > -1 SET_INPUT(X_MIN_PIN); - #ifdef ENDSTOPPULLUP_XMIN - WRITE(X_MIN_PIN,HIGH); - #endif - #endif +#ifdef ENDSTOPPULLUP_XMIN + WRITE(X_MIN_PIN,HIGH); +#endif +#endif - #if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 +#if defined(Y_MIN_PIN) && Y_MIN_PIN > -1 SET_INPUT(Y_MIN_PIN); - #ifdef ENDSTOPPULLUP_YMIN - WRITE(Y_MIN_PIN,HIGH); - #endif - #endif +#ifdef ENDSTOPPULLUP_YMIN + WRITE(Y_MIN_PIN,HIGH); +#endif +#endif - #if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 +#if defined(Z_MIN_PIN) && Z_MIN_PIN > -1 SET_INPUT(Z_MIN_PIN); - #ifdef ENDSTOPPULLUP_ZMIN - WRITE(Z_MIN_PIN,HIGH); - #endif - #endif +#ifdef ENDSTOPPULLUP_ZMIN + WRITE(Z_MIN_PIN,HIGH); +#endif +#endif - #if defined(X_MAX_PIN) && X_MAX_PIN > -1 +#if defined(X_MAX_PIN) && X_MAX_PIN > -1 SET_INPUT(X_MAX_PIN); - #ifdef ENDSTOPPULLUP_XMAX - WRITE(X_MAX_PIN,HIGH); - #endif - #endif +#ifdef ENDSTOPPULLUP_XMAX + WRITE(X_MAX_PIN,HIGH); +#endif +#endif - #if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 +#if defined(Y_MAX_PIN) && Y_MAX_PIN > -1 SET_INPUT(Y_MAX_PIN); - #ifdef ENDSTOPPULLUP_YMAX - WRITE(Y_MAX_PIN,HIGH); - #endif - #endif +#ifdef ENDSTOPPULLUP_YMAX + WRITE(Y_MAX_PIN,HIGH); +#endif +#endif - #if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 +#if defined(Z_MAX_PIN) && Z_MAX_PIN > -1 SET_INPUT(Z_MAX_PIN); - #ifdef ENDSTOPPULLUP_ZMAX - WRITE(Z_MAX_PIN,HIGH); - #endif - #endif +#ifdef ENDSTOPPULLUP_ZMAX + WRITE(Z_MAX_PIN,HIGH); +#endif +#endif - #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1)) - SET_INPUT(TACH_0); - #ifdef TACH0PULLUP - WRITE(TACH_0, HIGH); - #endif - #endif +#if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1)) + SET_INPUT(TACH_0); +#ifdef TACH0PULLUP + WRITE(TACH_0, HIGH); +#endif +#endif - //Initialize Step Pins + //Initialize Step Pins #if defined(X_STEP_PIN) && (X_STEP_PIN > -1) SET_OUTPUT(X_STEP_PIN); WRITE(X_STEP_PIN,INVERT_X_STEP_PIN); @@ -1275,168 +1279,168 @@ void st_init() WRITE(DEBUG_XSTEP_DUP_PIN,INVERT_X_STEP_PIN); #endif //DEBUG_XSTEP_DUP_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); #ifdef DEBUG_YSTEP_DUP_PIN SET_OUTPUT(DEBUG_YSTEP_DUP_PIN); WRITE(DEBUG_YSTEP_DUP_PIN,INVERT_Y_STEP_PIN); #endif //DEBUG_YSTEP_DUP_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 +#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) - SET_OUTPUT(Z2_STEP_PIN); - WRITE(Z2_STEP_PIN,INVERT_Z_STEP_PIN); - #endif +#if defined(Z_DUAL_STEPPER_DRIVERS) && defined(Z2_STEP_PIN) && (Z2_STEP_PIN > -1) + SET_OUTPUT(Z2_STEP_PIN); + 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 - - // waveform generation = 0100 = CTC - TCCR1B &= ~(1< -1 - pinMode(E1_MS1_PIN,OUTPUT); - pinMode(E1_MS2_PIN,OUTPUT); - #endif - - #if defined(X_MS1_PIN) && X_MS1_PIN > -1 - const uint8_t microstep_modes[] = MICROSTEP_MODES; - pinMode(X_MS1_PIN,OUTPUT); - pinMode(X_MS2_PIN,OUTPUT); - pinMode(Y_MS1_PIN,OUTPUT); - pinMode(Y_MS2_PIN,OUTPUT); - pinMode(Z_MS1_PIN,OUTPUT); - pinMode(Z_MS2_PIN,OUTPUT); - pinMode(E0_MS1_PIN,OUTPUT); - pinMode(E0_MS2_PIN,OUTPUT); - for(int i=0;i<=4;i++) microstep_mode(i,microstep_modes[i]); - #endif +#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 + const uint8_t microstep_modes[] = MICROSTEP_MODES; + pinMode(X_MS1_PIN,OUTPUT); + pinMode(X_MS2_PIN,OUTPUT); + pinMode(Y_MS1_PIN,OUTPUT); + pinMode(Y_MS2_PIN,OUTPUT); + pinMode(Z_MS1_PIN,OUTPUT); + pinMode(Z_MS2_PIN,OUTPUT); + pinMode(E0_MS1_PIN,OUTPUT); + pinMode(E0_MS2_PIN,OUTPUT); + for(int i=0; i<=4; i++) microstep_mode(i,microstep_modes[i]); +#endif } @@ -1621,59 +1626,89 @@ void microstep_init() 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; - #if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 - case 4: digitalWrite(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; - #if defined(E1_MS2_PIN) && E1_MS2_PIN > -1 - case 4: digitalWrite(E1_MS2_PIN,ms2); break; - #endif - } + 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; +#if defined(E1_MS1_PIN) && E1_MS1_PIN > -1 + case 4: + digitalWrite(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; +#if defined(E1_MS2_PIN) && E1_MS2_PIN > -1 + case 4: + digitalWrite(E1_MS2_PIN,ms2); + break; +#endif + } } void microstep_mode(uint8_t driver, uint8_t stepping_mode) { - switch(stepping_mode) - { - case 1: microstep_ms(driver,MICROSTEP1); break; - case 2: microstep_ms(driver,MICROSTEP2); break; - case 4: microstep_ms(driver,MICROSTEP4); break; - case 8: microstep_ms(driver,MICROSTEP8); break; - case 16: microstep_ms(driver,MICROSTEP16); break; - } + switch(stepping_mode) + { + case 1: + microstep_ms(driver,MICROSTEP1); + break; + case 2: + microstep_ms(driver,MICROSTEP2); + break; + case 4: + microstep_ms(driver,MICROSTEP4); + break; + case 8: + microstep_ms(driver,MICROSTEP8); + break; + case 16: + microstep_ms(driver,MICROSTEP16); + break; + } } 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_PROTOCOLPGM("Y: "); - SERIAL_PROTOCOL( digitalRead(Y_MS1_PIN)); - SERIAL_PROTOCOLLN( digitalRead(Y_MS2_PIN)); - SERIAL_PROTOCOLPGM("Z: "); - SERIAL_PROTOCOL( digitalRead(Z_MS1_PIN)); - SERIAL_PROTOCOLLN( digitalRead(Z_MS2_PIN)); - 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 + SERIAL_PROTOCOLPGM("MS1,MS2 Pins\n"); + SERIAL_PROTOCOLPGM("X: "); + SERIAL_PROTOCOL( digitalRead(X_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(X_MS2_PIN)); + SERIAL_PROTOCOLPGM("Y: "); + SERIAL_PROTOCOL( digitalRead(Y_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(Y_MS2_PIN)); + SERIAL_PROTOCOLPGM("Z: "); + SERIAL_PROTOCOL( digitalRead(Z_MS1_PIN)); + SERIAL_PROTOCOLLN( digitalRead(Z_MS2_PIN)); + 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 } #endif //TMC2130 diff --git a/Firmware/stepper.h b/Firmware/stepper.h index 6130f3bb13..72b4bf85b2 100755 --- a/Firmware/stepper.h +++ b/Firmware/stepper.h @@ -19,7 +19,7 @@ */ #ifndef stepper_h -#define stepper_h +#define stepper_h #include "planner.h" @@ -38,9 +38,9 @@ void st_init(); void isr(); #ifdef LIN_ADVANCE - void advance_isr(); - void advance_isr_scheduler(); - void clear_current_adv_vars(); //Used to reset the built up pretension and remaining esteps on filament change. +void advance_isr(); +void advance_isr_scheduler(); +void clear_current_adv_vars(); //Used to reset the built up pretension and remaining esteps on filament change. #endif // Block until all buffered steps are executed @@ -64,12 +64,12 @@ float st_get_position_mm(uint8_t axis); // to avoid a stepper timer overflow. FORCE_INLINE void st_reset_timer() { - // Clear a possible pending interrupt on OCR1A overflow. - TIFR1 |= 1 << OCF1A; - // Reset the counter. - TCNT1 = 0; - // Wake up after 1ms from now. - OCR1A = 2000; + // Clear a possible pending interrupt on OCR1A overflow. + TIFR1 |= 1 << OCF1A; + // Reset the counter. + TCNT1 = 0; + // Wake up after 1ms from now. + OCR1A = 2000; } void checkHitEndstops(); //call from somewhere to create an serial error message with the locations the endstops where hit, in case they were triggered @@ -104,9 +104,9 @@ 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 +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/Firmware/swi2c.c b/Firmware/swi2c.c index 49fbc5efc7..a6a618c809 100755 --- a/Firmware/swi2c.c +++ b/Firmware/swi2c.c @@ -16,136 +16,148 @@ void __delay(void) { - _delay_us(1.5); + _delay_us(1.5); } void swi2c_init(void) { - PIN_OUT(SWI2C_SDA); - PIN_OUT(SWI2C_SCL); - PIN_SET(SWI2C_SDA); - PIN_SET(SWI2C_SCL); - uint8_t i; for (i = 0; i < 100; i++) - __delay(); + PIN_OUT(SWI2C_SDA); + PIN_OUT(SWI2C_SCL); + PIN_SET(SWI2C_SDA); + PIN_SET(SWI2C_SCL); + uint8_t i; + for (i = 0; i < 100; i++) + __delay(); } void swi2c_start(void) { - PIN_CLR(SWI2C_SDA); - __delay(); - PIN_CLR(SWI2C_SCL); - __delay(); + PIN_CLR(SWI2C_SDA); + __delay(); + PIN_CLR(SWI2C_SCL); + __delay(); } void swi2c_stop(void) { - PIN_SET(SWI2C_SCL); - __delay(); - PIN_SET(SWI2C_SDA); - __delay(); + PIN_SET(SWI2C_SCL); + __delay(); + PIN_SET(SWI2C_SDA); + __delay(); } void swi2c_ack(void) { - PIN_CLR(SWI2C_SDA); - __delay(); - PIN_SET(SWI2C_SCL); - __delay(); - PIN_CLR(SWI2C_SCL); - __delay(); + PIN_CLR(SWI2C_SDA); + __delay(); + PIN_SET(SWI2C_SCL); + __delay(); + PIN_CLR(SWI2C_SCL); + __delay(); } uint8_t swi2c_wait_ack() { - PIN_INP(SWI2C_SDA); - __delay(); + PIN_INP(SWI2C_SDA); + __delay(); // PIN_SET(SWI2C_SDA); - __delay(); - PIN_SET(SWI2C_SCL); + __delay(); + PIN_SET(SWI2C_SCL); // __delay(); - uint8_t ack = 0; - uint16_t ackto = SWI2C_TMO; - while (!(ack = (PIN_GET(SWI2C_SDA)?0:1)) && ackto--) __delay(); - PIN_CLR(SWI2C_SCL); - __delay(); - PIN_OUT(SWI2C_SDA); - __delay(); - PIN_CLR(SWI2C_SDA); - __delay(); - return ack; + uint8_t ack = 0; + uint16_t ackto = SWI2C_TMO; + while (!(ack = (PIN_GET(SWI2C_SDA)?0:1)) && ackto--) __delay(); + PIN_CLR(SWI2C_SCL); + __delay(); + PIN_OUT(SWI2C_SDA); + __delay(); + PIN_CLR(SWI2C_SDA); + __delay(); + return ack; } uint8_t swi2c_read(void) { - PIN_SET(SWI2C_SDA); - __delay(); - PIN_INP(SWI2C_SDA); - uint8_t data = 0; - int8_t bit; for (bit = 7; bit >= 0; bit--) - { - PIN_SET(SWI2C_SCL); - __delay(); - data |= (PIN_GET(SWI2C_SDA)?1:0) << bit; - PIN_CLR(SWI2C_SCL); - __delay(); - } - PIN_OUT(SWI2C_SDA); - return data; + PIN_SET(SWI2C_SDA); + __delay(); + PIN_INP(SWI2C_SDA); + uint8_t data = 0; + int8_t bit; + for (bit = 7; bit >= 0; bit--) + { + PIN_SET(SWI2C_SCL); + __delay(); + data |= (PIN_GET(SWI2C_SDA)?1:0) << bit; + PIN_CLR(SWI2C_SCL); + __delay(); + } + PIN_OUT(SWI2C_SDA); + return data; } void swi2c_write(uint8_t data) { - int8_t bit; for (bit = 7; bit >= 0; bit--) - { - if (data & (1 << bit)) PIN_SET(SWI2C_SDA); - else PIN_CLR(SWI2C_SDA); - __delay(); - PIN_SET(SWI2C_SCL); - __delay(); - PIN_CLR(SWI2C_SCL); - __delay(); - } + int8_t bit; + for (bit = 7; bit >= 0; bit--) + { + if (data & (1 << bit)) PIN_SET(SWI2C_SDA); + else PIN_CLR(SWI2C_SDA); + __delay(); + PIN_SET(SWI2C_SCL); + __delay(); + PIN_CLR(SWI2C_SCL); + __delay(); + } } uint8_t swi2c_check(uint8_t dev_addr) { - swi2c_start(); - swi2c_write((dev_addr & SWI2C_DMSK) << SWI2C_ASHF); - if (!swi2c_wait_ack()) { swi2c_stop(); return 0; } - swi2c_stop(); - return 1; + swi2c_start(); + swi2c_write((dev_addr & SWI2C_DMSK) << SWI2C_ASHF); + if (!swi2c_wait_ack()) { + swi2c_stop(); + return 0; + } + swi2c_stop(); + return 1; } #ifdef SWI2C_A8 //8bit address uint8_t swi2c_readByte_A8(uint8_t dev_addr, uint8_t addr, uint8_t* pbyte) { - swi2c_start(); - swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); - if (!swi2c_wait_ack()) { swi2c_stop(); return 0; } - swi2c_write(addr & 0xff); - if (!swi2c_wait_ack()) return 0; - swi2c_stop(); - swi2c_start(); - swi2c_write(SWI2C_RMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); - if (!swi2c_wait_ack()) return 0; - uint8_t byte = swi2c_read(); - swi2c_stop(); - if (pbyte) *pbyte = byte; - return 1; + swi2c_start(); + swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); + if (!swi2c_wait_ack()) { + swi2c_stop(); + return 0; + } + swi2c_write(addr & 0xff); + if (!swi2c_wait_ack()) return 0; + swi2c_stop(); + swi2c_start(); + swi2c_write(SWI2C_RMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); + if (!swi2c_wait_ack()) return 0; + uint8_t byte = swi2c_read(); + swi2c_stop(); + if (pbyte) *pbyte = byte; + return 1; } uint8_t swi2c_writeByte_A8(uint8_t dev_addr, uint8_t addr, uint8_t* pbyte) { - swi2c_start(); - swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); - if (!swi2c_wait_ack()) { swi2c_stop(); return 0; } - swi2c_write(addr & 0xff); - if (!swi2c_wait_ack()) return 0; - swi2c_write(*pbyte); - if (!swi2c_wait_ack()) return 0; - swi2c_stop(); - return 1; + swi2c_start(); + swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); + if (!swi2c_wait_ack()) { + swi2c_stop(); + return 0; + } + swi2c_write(addr & 0xff); + if (!swi2c_wait_ack()) return 0; + swi2c_write(*pbyte); + if (!swi2c_wait_ack()) return 0; + swi2c_stop(); + return 1; } #endif //SWI2C_A8 @@ -154,36 +166,42 @@ uint8_t swi2c_writeByte_A8(uint8_t dev_addr, uint8_t addr, uint8_t* pbyte) uint8_t swi2c_readByte_A16(uint8_t dev_addr, unsigned short addr, uint8_t* pbyte) { - swi2c_start(); - swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); - if (!swi2c_wait_ack()) { swi2c_stop(); return 0; } - swi2c_write(addr >> 8); - if (!swi2c_wait_ack()) return 0; - swi2c_write(addr & 0xff); - if (!swi2c_wait_ack()) return 0; - swi2c_stop(); - swi2c_start(); - swi2c_write(SWI2C_RMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); - if (!swi2c_wait_ack()) return 0; - uint8_t byte = swi2c_read(); - swi2c_stop(); - if (pbyte) *pbyte = byte; - return 1; + swi2c_start(); + swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); + if (!swi2c_wait_ack()) { + swi2c_stop(); + return 0; + } + swi2c_write(addr >> 8); + if (!swi2c_wait_ack()) return 0; + swi2c_write(addr & 0xff); + if (!swi2c_wait_ack()) return 0; + swi2c_stop(); + swi2c_start(); + swi2c_write(SWI2C_RMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); + if (!swi2c_wait_ack()) return 0; + uint8_t byte = swi2c_read(); + swi2c_stop(); + if (pbyte) *pbyte = byte; + return 1; } uint8_t swi2c_writeByte_A16(uint8_t dev_addr, unsigned short addr, uint8_t* pbyte) { - swi2c_start(); - swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); - if (!swi2c_wait_ack()) { swi2c_stop(); return 0; } - swi2c_write(addr >> 8); - if (!swi2c_wait_ack()) return 0; - swi2c_write(addr & 0xff); - if (!swi2c_wait_ack()) return 0; - swi2c_write(*pbyte); - if (!swi2c_wait_ack()) return 0; - swi2c_stop(); - return 1; + swi2c_start(); + swi2c_write(SWI2C_WMSK | ((dev_addr & SWI2C_DMSK) << SWI2C_ASHF)); + if (!swi2c_wait_ack()) { + swi2c_stop(); + return 0; + } + swi2c_write(addr >> 8); + if (!swi2c_wait_ack()) return 0; + swi2c_write(addr & 0xff); + if (!swi2c_wait_ack()) return 0; + swi2c_write(*pbyte); + if (!swi2c_wait_ack()) return 0; + swi2c_stop(); + return 1; } #endif //SWI2C_A16 diff --git a/Firmware/swspi.cpp b/Firmware/swspi.cpp index efab8f73be..a5372b785a 100755 --- a/Firmware/swspi.cpp +++ b/Firmware/swspi.cpp @@ -27,67 +27,70 @@ unsigned char swspi_cfg = 0; void swspi_init(unsigned char miso, unsigned char mosi, unsigned char sck, unsigned char cfg) { - swspi_miso = miso; - swspi_mosi = mosi; - swspi_sck = sck; - swspi_cfg = cfg; - GPIO_INP(swspi_miso); - GPIO_OUT(swspi_mosi); - GPIO_OUT(swspi_sck); - GPIO_CLR(swspi_mosi); - SWSPI_SCK_DN; + swspi_miso = miso; + swspi_mosi = mosi; + swspi_sck = sck; + swspi_cfg = cfg; + GPIO_INP(swspi_miso); + GPIO_OUT(swspi_mosi); + GPIO_OUT(swspi_sck); + GPIO_CLR(swspi_mosi); + SWSPI_SCK_DN; } void swspi_tx(unsigned char tx) { - int delay = 1 << (swspi_cfg & SWSPI_DEL)); - if (swspi_miso == swspi_mosi) GPIO_OUT(swspi_mosi); - unsigned char i = 0; for (; i < 8; i++) - { - if (tx & 0x80) GPIO_SET(swspi_mosi); - else GPIO_CLR(swspi_mosi); - DELAY(delay); - SWSPI_SCK_UP; - DELAY(delay); - SWSPI_SCK_DN; - tx <<= 1; - } + int delay = 1 << (swspi_cfg & SWSPI_DEL)); + if (swspi_miso == swspi_mosi) GPIO_OUT(swspi_mosi); + unsigned char i = 0; + for (; i < 8; i++) +{ + if (tx & 0x80) GPIO_SET(swspi_mosi); + else GPIO_CLR(swspi_mosi); + DELAY(delay); + SWSPI_SCK_UP; + DELAY(delay); + SWSPI_SCK_DN; + tx <<= 1; + } } unsigned char swspi_rx() { - int delay = 1 << (swspi_cfg & SWSPI_DEL)); - if (swspi_miso == swspi_mosi) GPIO_OUT(swspi_mosi); - unsigned char rx = 0; - unsigned char i = 0; for (; i < 8; i++) - { - rx <<= 1; - DELAY(delay); - SWSPI_SCK_UP; - DELAY(delay); - rx |= GPIO_GET(swspi_miso)?1:0; - SWSPI_SCK_DN; - } - return rx; + int delay = 1 << (swspi_cfg & SWSPI_DEL)); + if (swspi_miso == swspi_mosi) GPIO_OUT(swspi_mosi); + unsigned char rx = 0; + unsigned char i = 0; + for (; i < 8; i++) +{ + rx <<= 1; + DELAY(delay); + SWSPI_SCK_UP; + DELAY(delay); + rx |= GPIO_GET(swspi_miso)?1:0; + SWSPI_SCK_DN; + } + return rx; } unsigned char swspi_txrx(unsigned char tx) { - int delay = 1 << (swspi_cfg & SWSPI_DEL)); - unsigned char rx = 0; - unsigned char i = 0; for (; i < 8; i++) - { - rx <<= 1; - if (tx & 0x80) GPIO_SET(swspi_mosi); - else GPIO_CLR(swspi_mosi); - DELAY(delay); - SWSPI_SCK_UP; - DELAY(delay); - rx |= GPIO_GET(swspi_miso)?1:0; - SWSPI_SCK_DN; - tx <<= 1; - } - return rx; + int delay = 1 << (swspi_cfg & SWSPI_DEL)); + unsigned char rx = 0; + unsigned char i = 0; + for (; i < 8; i++) +{ + rx <<= 1; + if (tx & 0x80) GPIO_SET(swspi_mosi); + else GPIO_CLR(swspi_mosi); + DELAY(delay); + SWSPI_SCK_UP; + DELAY(delay); + rx |= GPIO_GET(swspi_miso)?1:0; + SWSPI_SCK_DN; + tx <<= 1; + } + return rx; } #endif //__SWSPI diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index cae3fada7f..4f45ce4884 100755 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -1,19 +1,19 @@ /* temperature.c - temperature control Part of Marlin - + 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 */ @@ -71,29 +71,29 @@ int current_voltage_raw_bed = 0; int current_temperature_bed_raw = 0; float current_temperature_bed = 0.0; #ifdef TEMP_SENSOR_1_AS_REDUNDANT - int redundant_temperature_raw = 0; - float redundant_temperature = 0.0; +int redundant_temperature_raw = 0; +float redundant_temperature = 0.0; #endif - + #ifdef PIDTEMP - float _Kp, _Ki, _Kd; - int pid_cycle, pid_number_of_cycles; - bool pid_tuning_finished = false; - #ifdef PID_ADD_EXTRUSION_RATE - float Kc=DEFAULT_Kc; - #endif +float _Kp, _Ki, _Kd; +int pid_cycle, pid_number_of_cycles; +bool pid_tuning_finished = false; +#ifdef PID_ADD_EXTRUSION_RATE +float Kc=DEFAULT_Kc; +#endif #endif //PIDTEMP - + #ifdef FAN_SOFT_PWM - unsigned char fanSpeedSoftPwm; +unsigned char fanSpeedSoftPwm; #endif unsigned char soft_pwm_bed; #ifdef BABYSTEPPING - volatile int babystepsTodo[3]={0,0,0}; +volatile int babystepsTodo[3]= {0,0,0}; #endif //=========================================================================== @@ -102,59 +102,59 @@ unsigned char soft_pwm_bed; static volatile bool temp_meas_ready = false; #ifdef PIDTEMP - //static cannot be external: - static float temp_iState[EXTRUDERS] = { 0 }; - static float temp_dState[EXTRUDERS] = { 0 }; - static float pTerm[EXTRUDERS]; - static float iTerm[EXTRUDERS]; - static float dTerm[EXTRUDERS]; - //int output; - static float pid_error[EXTRUDERS]; - static float temp_iState_min[EXTRUDERS]; - static float temp_iState_max[EXTRUDERS]; - // static float pid_input[EXTRUDERS]; - // static float pid_output[EXTRUDERS]; - static bool pid_reset[EXTRUDERS]; +//static cannot be external: +static float temp_iState[EXTRUDERS] = { 0 }; +static float temp_dState[EXTRUDERS] = { 0 }; +static float pTerm[EXTRUDERS]; +static float iTerm[EXTRUDERS]; +static float dTerm[EXTRUDERS]; +//int output; +static float pid_error[EXTRUDERS]; +static float temp_iState_min[EXTRUDERS]; +static float temp_iState_max[EXTRUDERS]; +// static float pid_input[EXTRUDERS]; +// static float pid_output[EXTRUDERS]; +static bool pid_reset[EXTRUDERS]; #endif //PIDTEMP #ifdef PIDTEMPBED - //static cannot be external: - static float temp_iState_bed = { 0 }; - static float temp_dState_bed = { 0 }; - static float pTerm_bed; - static float iTerm_bed; - static float dTerm_bed; - //int output; - static float pid_error_bed; - static float temp_iState_min_bed; - static float temp_iState_max_bed; +//static cannot be external: +static float temp_iState_bed = { 0 }; +static float temp_dState_bed = { 0 }; +static float pTerm_bed; +static float iTerm_bed; +static float dTerm_bed; +//int output; +static float pid_error_bed; +static float temp_iState_min_bed; +static float temp_iState_max_bed; #else //PIDTEMPBED - static unsigned long previous_millis_bed_heater; +static unsigned long previous_millis_bed_heater; #endif //PIDTEMPBED - static unsigned char soft_pwm[EXTRUDERS]; +static unsigned char soft_pwm[EXTRUDERS]; #ifdef FAN_SOFT_PWM - static unsigned char soft_pwm_fan; +static unsigned char soft_pwm_fan; #endif #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - static unsigned long extruder_autofan_last_check; -#endif +static unsigned long extruder_autofan_last_check; +#endif #if EXTRUDERS > 3 - # error Unsupported number of extruders +# error Unsupported number of extruders #elif EXTRUDERS > 2 - # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2, v3 } +# define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2, v3 } #elif EXTRUDERS > 1 - # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2 } +# define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1, v2 } #else - # define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 } +# define ARRAY_BY_EXTRUDERS(v1, v2, v3) { v1 } #endif // Init min and max temp with extreme values to prevent false errors during startup -static int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_LO_TEMP , HEATER_1_RAW_LO_TEMP , HEATER_2_RAW_LO_TEMP ); -static int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_HI_TEMP , HEATER_1_RAW_HI_TEMP , HEATER_2_RAW_HI_TEMP ); +static int minttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_LO_TEMP, HEATER_1_RAW_LO_TEMP, HEATER_2_RAW_LO_TEMP ); +static int maxttemp_raw[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_RAW_HI_TEMP, HEATER_1_RAW_HI_TEMP, HEATER_2_RAW_HI_TEMP ); static int minttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 0, 0, 0 ); static int maxttemp[EXTRUDERS] = ARRAY_BY_EXTRUDERS( 16383, 16383, 16383 ); #ifdef BED_MINTEMP @@ -165,11 +165,11 @@ static int bed_maxttemp_raw = HEATER_BED_RAW_HI_TEMP; #endif #ifdef TEMP_SENSOR_1_AS_REDUNDANT - static void *heater_ttbl_map[2] = {(void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE }; - static uint8_t heater_ttbllen_map[2] = { HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN }; +static void *heater_ttbl_map[2] = {(void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE }; +static uint8_t heater_ttbllen_map[2] = { HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN }; #else - static void *heater_ttbl_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( (void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE, (void *)HEATER_2_TEMPTABLE ); - static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN ); +static void *heater_ttbl_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( (void *)HEATER_0_TEMPTABLE, (void *)HEATER_1_TEMPTABLE, (void *)HEATER_2_TEMPTABLE ); +static uint8_t heater_ttbllen_map[EXTRUDERS] = ARRAY_BY_EXTRUDERS( HEATER_0_TEMPTABLE_LEN, HEATER_1_TEMPTABLE_LEN, HEATER_2_TEMPTABLE_LEN ); #endif static float analog2temp(int raw, uint8_t e); @@ -179,9 +179,9 @@ static void updateTemperaturesFromRawValues(); enum TempRunawayStates { - TempRunaway_INACTIVE = 0, - TempRunaway_PREHEAT = 1, - TempRunaway_ACTIVE = 2, + TempRunaway_INACTIVE = 0, + TempRunaway_PREHEAT = 1, + TempRunaway_ACTIVE = 2, }; #ifdef WATCH_TEMP_PERIOD @@ -207,377 +207,386 @@ static void temp_runaway_check(int _heater_id, float _target_temperature, float static void temp_runaway_stop(bool isPreheat, bool isBed); #endif - void PID_autotune(float temp, int extruder, int ncycles) - { - pid_number_of_cycles = ncycles; - pid_tuning_finished = false; - float input = 0.0; - pid_cycle=0; - bool heating = true; - - unsigned long temp_millis = millis(); - unsigned long t1=temp_millis; - unsigned long t2=temp_millis; - long t_high = 0; - long t_low = 0; - - long bias, d; - float Ku, Tu; - float max = 0, min = 10000; - uint8_t safety_check_cycles = 0; - const uint8_t safety_check_cycles_count = (extruder < 0) ? 45 : 10; //10 cycles / 20s delay for extruder and 45 cycles / 90s for heatbed - float temp_ambient; +void PID_autotune(float temp, int extruder, int ncycles) +{ + pid_number_of_cycles = ncycles; + pid_tuning_finished = false; + float input = 0.0; + pid_cycle=0; + bool heating = true; + + unsigned long temp_millis = millis(); + unsigned long t1=temp_millis; + unsigned long t2=temp_millis; + long t_high = 0; + long t_low = 0; + + long bias, d; + float Ku, Tu; + float max = 0, min = 10000; + uint8_t safety_check_cycles = 0; + const uint8_t safety_check_cycles_count = (extruder < 0) ? 45 : 10; //10 cycles / 20s delay for extruder and 45 cycles / 90s for heatbed + float temp_ambient; #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - unsigned long extruder_autofan_last_check = millis(); -#endif - - if ((extruder >= EXTRUDERS) - #if (TEMP_BED_PIN <= -1) - ||(extruder < 0) - #endif - ){ - SERIAL_ECHOLN("PID Autotune failed. Bad extruder number."); - pid_tuning_finished = true; - pid_cycle = 0; - return; - } - - SERIAL_ECHOLN("PID Autotune start"); - - disable_heater(); // switch off all heaters. + unsigned long extruder_autofan_last_check = millis(); +#endif + + if ((extruder >= EXTRUDERS) +#if (TEMP_BED_PIN <= -1) + ||(extruder < 0) +#endif + ) { + SERIAL_ECHOLN("PID Autotune failed. Bad extruder number."); + pid_tuning_finished = true; + pid_cycle = 0; + return; + } + + SERIAL_ECHOLN("PID Autotune start"); + + disable_heater(); // switch off all heaters. - if (extruder<0) - { - soft_pwm_bed = (MAX_BED_POWER)/2; - bias = d = (MAX_BED_POWER)/2; - } - else - { - soft_pwm[extruder] = (PID_MAX)/2; - bias = d = (PID_MAX)/2; - } + if (extruder<0) + { + soft_pwm_bed = (MAX_BED_POWER)/2; + bias = d = (MAX_BED_POWER)/2; + } + else + { + soft_pwm[extruder] = (PID_MAX)/2; + bias = d = (PID_MAX)/2; + } - for(;;) { + for(;;) { #ifdef WATCHDOG - wdt_reset(); + wdt_reset(); #endif //WATCHDOG - if(temp_meas_ready == true) { // temp sample ready - updateTemperaturesFromRawValues(); + if(temp_meas_ready == true) { // temp sample ready + updateTemperaturesFromRawValues(); - input = (extruder<0)?current_temperature_bed:current_temperature[extruder]; + input = (extruder<0)?current_temperature_bed:current_temperature[extruder]; - max=max(max,input); - min=min(min,input); + max=max(max,input); + min=min(min,input); - #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ +#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - if(millis() - extruder_autofan_last_check > 2500) { - checkExtruderAutoFans(); - extruder_autofan_last_check = millis(); - } - #endif - - if(heating == true && input > temp) { - if(millis() - t2 > 5000) { - heating=false; - if (extruder<0) - soft_pwm_bed = (bias - d) >> 1; - else - soft_pwm[extruder] = (bias - d) >> 1; - t1=millis(); - t_high=t1 - t2; - max=temp; + if(millis() - extruder_autofan_last_check > 2500) { + checkExtruderAutoFans(); + extruder_autofan_last_check = millis(); + } +#endif + + if(heating == true && input > temp) { + if(millis() - t2 > 5000) { + heating=false; + if (extruder<0) + soft_pwm_bed = (bias - d) >> 1; + else + soft_pwm[extruder] = (bias - d) >> 1; + t1=millis(); + t_high=t1 - t2; + max=temp; + } + } + if(heating == false && input < temp) { + if(millis() - t1 > 5000) { + heating=true; + t2=millis(); + t_low=t2 - t1; + if(pid_cycle > 0) { + bias += (d*(t_high - t_low))/(t_low + t_high); + bias = constrain(bias, 20,(extruder<0?(MAX_BED_POWER):(PID_MAX))-20); + if(bias > (extruder<0?(MAX_BED_POWER):(PID_MAX))/2) d = (extruder<0?(MAX_BED_POWER):(PID_MAX)) - 1 - bias; + else d = bias; + + SERIAL_PROTOCOLPGM(" bias: "); + SERIAL_PROTOCOL(bias); + SERIAL_PROTOCOLPGM(" d: "); + SERIAL_PROTOCOL(d); + SERIAL_PROTOCOLPGM(" min: "); + SERIAL_PROTOCOL(min); + SERIAL_PROTOCOLPGM(" max: "); + SERIAL_PROTOCOLLN(max); + if(pid_cycle > 2) { + Ku = (4.0*d)/(3.14159*(max-min)/2.0); + Tu = ((float)(t_low + t_high)/1000.0); + SERIAL_PROTOCOLPGM(" Ku: "); + SERIAL_PROTOCOL(Ku); + SERIAL_PROTOCOLPGM(" Tu: "); + SERIAL_PROTOCOLLN(Tu); + _Kp = 0.6*Ku; + _Ki = 2*_Kp/Tu; + _Kd = _Kp*Tu/8; + SERIAL_PROTOCOLLNPGM(" Classic PID "); + SERIAL_PROTOCOLPGM(" Kp: "); + SERIAL_PROTOCOLLN(_Kp); + SERIAL_PROTOCOLPGM(" Ki: "); + SERIAL_PROTOCOLLN(_Ki); + SERIAL_PROTOCOLPGM(" Kd: "); + SERIAL_PROTOCOLLN(_Kd); + /* + _Kp = 0.33*Ku; + _Ki = _Kp/Tu; + _Kd = _Kp*Tu/3; + 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_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp); + SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki); + SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd); + */ + } + } + if (extruder<0) + soft_pwm_bed = (bias + d) >> 1; + else + soft_pwm[extruder] = (bias + d) >> 1; + pid_cycle++; + min=temp; + } + } + } + if(input > (temp + 20)) { + SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature too high"); + pid_tuning_finished = true; + pid_cycle = 0; + return; } - } - if(heating == false && input < temp) { - if(millis() - t1 > 5000) { - heating=true; - t2=millis(); - t_low=t2 - t1; - if(pid_cycle > 0) { - bias += (d*(t_high - t_low))/(t_low + t_high); - bias = constrain(bias, 20 ,(extruder<0?(MAX_BED_POWER):(PID_MAX))-20); - if(bias > (extruder<0?(MAX_BED_POWER):(PID_MAX))/2) d = (extruder<0?(MAX_BED_POWER):(PID_MAX)) - 1 - bias; - else d = bias; - - SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias); - SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d); - SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min); - SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max); - if(pid_cycle > 2) { - Ku = (4.0*d)/(3.14159*(max-min)/2.0); - Tu = ((float)(t_low + t_high)/1000.0); - SERIAL_PROTOCOLPGM(" Ku: "); SERIAL_PROTOCOL(Ku); - SERIAL_PROTOCOLPGM(" Tu: "); SERIAL_PROTOCOLLN(Tu); - _Kp = 0.6*Ku; - _Ki = 2*_Kp/Tu; - _Kd = _Kp*Tu/8; - SERIAL_PROTOCOLLNPGM(" Classic PID "); - SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp); - SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki); - SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd); - /* - _Kp = 0.33*Ku; - _Ki = _Kp/Tu; - _Kd = _Kp*Tu/3; - 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_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(_Kp); - SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(_Ki); - SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(_Kd); - */ + if(millis() - temp_millis > 2000) { + int p; + if (extruder<0) { + p=soft_pwm_bed; + SERIAL_PROTOCOLPGM("B:"); + } else { + p=soft_pwm[extruder]; + SERIAL_PROTOCOLPGM("T:"); + } + + SERIAL_PROTOCOL(input); + SERIAL_PROTOCOLPGM(" @:"); + SERIAL_PROTOCOLLN(p); + if (safety_check_cycles == 0) { //save ambient temp + temp_ambient = input; + //SERIAL_ECHOPGM("Ambient T: "); + //MYSERIAL.println(temp_ambient); + safety_check_cycles++; + } + else if (safety_check_cycles < safety_check_cycles_count) { //delay + safety_check_cycles++; + } + else if (safety_check_cycles == safety_check_cycles_count) { //check that temperature is rising + safety_check_cycles++; + //SERIAL_ECHOPGM("Time from beginning: "); + //MYSERIAL.print(safety_check_cycles_count * 2); + //SERIAL_ECHOPGM("s. Difference between current and ambient T: "); + //MYSERIAL.println(input - temp_ambient); + + if (abs(input - temp_ambient) < 5.0) { + temp_runaway_stop(false, (extruder<0)); + pid_tuning_finished = true; + return; + } } - } - if (extruder<0) - soft_pwm_bed = (bias + d) >> 1; - else - soft_pwm[extruder] = (bias + d) >> 1; - pid_cycle++; - min=temp; + temp_millis = millis(); } - } - } - if(input > (temp + 20)) { - SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature too high"); - pid_tuning_finished = true; - pid_cycle = 0; - return; - } - if(millis() - temp_millis > 2000) { - int p; - if (extruder<0){ - p=soft_pwm_bed; - SERIAL_PROTOCOLPGM("B:"); - }else{ - p=soft_pwm[extruder]; - SERIAL_PROTOCOLPGM("T:"); - } - - SERIAL_PROTOCOL(input); - SERIAL_PROTOCOLPGM(" @:"); - SERIAL_PROTOCOLLN(p); - if (safety_check_cycles == 0) { //save ambient temp - temp_ambient = input; - //SERIAL_ECHOPGM("Ambient T: "); - //MYSERIAL.println(temp_ambient); - safety_check_cycles++; - } - else if (safety_check_cycles < safety_check_cycles_count) { //delay - safety_check_cycles++; - } - else if (safety_check_cycles == safety_check_cycles_count){ //check that temperature is rising - safety_check_cycles++; - //SERIAL_ECHOPGM("Time from beginning: "); - //MYSERIAL.print(safety_check_cycles_count * 2); - //SERIAL_ECHOPGM("s. Difference between current and ambient T: "); - //MYSERIAL.println(input - temp_ambient); - - if (abs(input - temp_ambient) < 5.0) { - temp_runaway_stop(false, (extruder<0)); - pid_tuning_finished = true; - return; - } - } - temp_millis = millis(); - } - if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) { - SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout"); - pid_tuning_finished = true; - pid_cycle = 0; - return; - } - if(pid_cycle > ncycles) { - SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h"); - pid_tuning_finished = true; - pid_cycle = 0; - return; + if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) { + SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout"); + pid_tuning_finished = true; + pid_cycle = 0; + return; + } + if(pid_cycle > ncycles) { + SERIAL_PROTOCOLLNPGM("PID Autotune finished! Put the last Kp, Ki and Kd constants from above into Configuration.h"); + pid_tuning_finished = true; + pid_cycle = 0; + return; + } + lcd_update(0); } - lcd_update(0); - } } void updatePID() { #ifdef PIDTEMP - for(int e = 0; e < EXTRUDERS; e++) { - temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki; - } + for(int e = 0; e < EXTRUDERS; e++) { + temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / cs.Ki; + } #endif #ifdef PIDTEMPBED - temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / cs.bedKi; + temp_iState_max_bed = PID_INTEGRAL_DRIVE_MAX / cs.bedKi; #endif } - + int getHeaterPower(int heater) { - if (heater<0) - return soft_pwm_bed; - return soft_pwm[heater]; + if (heater<0) + return soft_pwm_bed; + return soft_pwm[heater]; } #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - #if defined(FAN_PIN) && FAN_PIN > -1 - #if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #if EXTRUDER_1_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_1_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #if EXTRUDER_2_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_2_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #endif +#if defined(FAN_PIN) && FAN_PIN > -1 +#if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN +#error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN" +#endif +#if EXTRUDER_1_AUTO_FAN_PIN == FAN_PIN +#error "You cannot set EXTRUDER_1_AUTO_FAN_PIN equal to FAN_PIN" +#endif +#if EXTRUDER_2_AUTO_FAN_PIN == FAN_PIN +#error "You cannot set EXTRUDER_2_AUTO_FAN_PIN equal to FAN_PIN" +#endif +#endif void setExtruderAutoFanState(int pin, bool state) { - unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0; - // this idiom allows both digital and PWM fan outputs (see M42 handling). - pinMode(pin, OUTPUT); - digitalWrite(pin, newFanSpeed); - analogWrite(pin, newFanSpeed); + unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0; + // this idiom allows both digital and PWM fan outputs (see M42 handling). + pinMode(pin, OUTPUT); + digitalWrite(pin, newFanSpeed); + analogWrite(pin, newFanSpeed); } #if (defined(FANCHECK) && (((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1))))) void countFanSpeed() { - //SERIAL_ECHOPGM("edge counter 1:"); MYSERIAL.println(fan_edge_counter[1]); - fan_speed[0] = (fan_edge_counter[0] * (float(250) / (millis() - extruder_autofan_last_check))); - fan_speed[1] = (fan_edge_counter[1] * (float(250) / (millis() - extruder_autofan_last_check))); - /*SERIAL_ECHOPGM("time interval: "); MYSERIAL.println(millis() - extruder_autofan_last_check); - SERIAL_ECHOPGM("extruder fan speed:"); MYSERIAL.print(fan_speed[0]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[0]); - SERIAL_ECHOPGM("print fan speed:"); MYSERIAL.print(fan_speed[1]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[1]); - SERIAL_ECHOLNPGM(" ");*/ - fan_edge_counter[0] = 0; - fan_edge_counter[1] = 0; + //SERIAL_ECHOPGM("edge counter 1:"); MYSERIAL.println(fan_edge_counter[1]); + fan_speed[0] = (fan_edge_counter[0] * (float(250) / (millis() - extruder_autofan_last_check))); + fan_speed[1] = (fan_edge_counter[1] * (float(250) / (millis() - extruder_autofan_last_check))); + /*SERIAL_ECHOPGM("time interval: "); MYSERIAL.println(millis() - extruder_autofan_last_check); + SERIAL_ECHOPGM("extruder fan speed:"); MYSERIAL.print(fan_speed[0]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[0]); + SERIAL_ECHOPGM("print fan speed:"); MYSERIAL.print(fan_speed[1]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[1]); + SERIAL_ECHOLNPGM(" ");*/ + fan_edge_counter[0] = 0; + fan_edge_counter[1] = 0; } extern bool fans_check_enabled; void checkFanSpeed() { - fans_check_enabled = (eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED) > 0); - static unsigned char fan_speed_errors[2] = { 0,0 }; + fans_check_enabled = (eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED) > 0); + static unsigned char fan_speed_errors[2] = { 0,0 }; #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 >-1)) - if ((fan_speed[0] == 0) && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)) fan_speed_errors[0]++; - else fan_speed_errors[0] = 0; + if ((fan_speed[0] == 0) && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)) fan_speed_errors[0]++; + else fan_speed_errors[0] = 0; #endif #if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1)) - if ((fan_speed[1] == 0) && ((blocks_queued() ? block_buffer[block_buffer_tail].fan_speed : fanSpeed) > MIN_PRINT_FAN_SPEED)) fan_speed_errors[1]++; - else fan_speed_errors[1] = 0; -#endif - - if ((fan_speed_errors[0] > 5) && fans_check_enabled) { - fan_speed_errors[0] = 0; - fanSpeedError(0); //extruder fan - } - if ((fan_speed_errors[1] > 15) && fans_check_enabled) { - fan_speed_errors[1] = 0; - fanSpeedError(1); //print fan - } + if ((fan_speed[1] == 0) && ((blocks_queued() ? block_buffer[block_buffer_tail].fan_speed : fanSpeed) > MIN_PRINT_FAN_SPEED)) fan_speed_errors[1]++; + else fan_speed_errors[1] = 0; +#endif + + if ((fan_speed_errors[0] > 5) && fans_check_enabled) { + fan_speed_errors[0] = 0; + fanSpeedError(0); //extruder fan + } + if ((fan_speed_errors[1] > 15) && fans_check_enabled) { + fan_speed_errors[1] = 0; + fanSpeedError(1); //print fan + } } void fanSpeedError(unsigned char _fan) { - if (get_message_level() != 0 && isPrintPaused) return; - //to ensure that target temp. is not set to zero in case taht we are resuming print - if (card.sdprinting) { - if (heating_status != 0) { - lcd_print_stop(); - } - else { - lcd_pause_print(); - } - } - else { - setTargetHotend0(0); - SERIAL_ECHOLNPGM("// action:pause"); //for octoprint - } - switch (_fan) { - case 0: - SERIAL_ECHOLNPGM("Extruder fan speed is lower then expected"); - if (get_message_level() == 0) { -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) - WRITE(BEEPER, HIGH); - delayMicroseconds(200); - WRITE(BEEPER, LOW); - delayMicroseconds(100); - LCD_ALERTMESSAGEPGM("Err: EXTR. FAN ERROR"); - } - break; - case 1: - SERIAL_ECHOLNPGM("Print fan speed is lower then expected"); - if (get_message_level() == 0) { -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) - WRITE(BEEPER, HIGH); - delayMicroseconds(200); - WRITE(BEEPER, LOW); - delayMicroseconds(100); - LCD_ALERTMESSAGEPGM("Err: PRINT FAN ERROR"); - } - break; - } + if (get_message_level() != 0 && isPrintPaused) return; + //to ensure that target temp. is not set to zero in case taht we are resuming print + if (card.sdprinting) { + if (heating_status != 0) { + lcd_print_stop(); + } + else { + lcd_pause_print(); + } + } + else { + setTargetHotend0(0); + SERIAL_ECHOLNPGM("// action:pause"); //for octoprint + } + switch (_fan) { + case 0: + SERIAL_ECHOLNPGM("Extruder fan speed is lower then expected"); + if (get_message_level() == 0) { + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) + WRITE(BEEPER, HIGH); + delayMicroseconds(200); + WRITE(BEEPER, LOW); + delayMicroseconds(100); + LCD_ALERTMESSAGEPGM("Err: EXTR. FAN ERROR"); + } + break; + case 1: + SERIAL_ECHOLNPGM("Print fan speed is lower then expected"); + if (get_message_level() == 0) { + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) + WRITE(BEEPER, HIGH); + delayMicroseconds(200); + WRITE(BEEPER, LOW); + delayMicroseconds(100); + LCD_ALERTMESSAGEPGM("Err: PRINT FAN ERROR"); + } + break; + } } #endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1) void checkExtruderAutoFans() { - uint8_t fanState = 0; - - // which fan pins need to be turned on? - #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 - if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE) - fanState |= 1; - #endif - #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 - if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) - { - if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) + uint8_t fanState = 0; + + // which fan pins need to be turned on? +#if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 + if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE) fanState |= 1; - else - fanState |= 2; +#endif +#if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 + if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) + { + if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) + fanState |= 1; + else + fanState |= 2; } - #endif - #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 - if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) +#endif +#if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 + if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) { - if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) - fanState |= 2; - else - fanState |= 4; - } - #endif - - // update extruder auto fan states - #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 + if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) + fanState |= 1; + else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) + fanState |= 2; + else + fanState |= 4; + } +#endif + + // update extruder auto fan states +#if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, (fanState & 1) != 0); - #endif - #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 - if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0); - #endif - #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 - if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN - && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0); - #endif +#endif +#if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 + if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) + setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0); +#endif +#if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 + if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN + && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN) + setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0); +#endif } #endif // any extruder auto fan pins set @@ -588,234 +597,234 @@ void manage_heater() wdt_reset(); #endif //WATCHDOG - float pid_input; - float pid_output; + float pid_input; + float pid_output; - if(temp_meas_ready != true) //better readability - return; + if(temp_meas_ready != true) //better readability + return; - updateTemperaturesFromRawValues(); + updateTemperaturesFromRawValues(); #ifdef TEMP_RUNAWAY_BED_HYSTERESIS - temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true); + temp_runaway_check(0, target_temperature_bed, current_temperature_bed, (int)soft_pwm_bed, true); #endif - for(int e = 0; e < EXTRUDERS; e++) - { + for(int e = 0; e < EXTRUDERS; e++) + { #ifdef TEMP_RUNAWAY_EXTRUDER_HYSTERESIS - temp_runaway_check(e+1, target_temperature[e], current_temperature[e], (int)soft_pwm[e], false); + temp_runaway_check(e+1, target_temperature[e], current_temperature[e], (int)soft_pwm[e], false); #endif - #ifdef PIDTEMP - pid_input = current_temperature[e]; +#ifdef PIDTEMP + pid_input = current_temperature[e]; - #ifndef PID_OPENLOOP +#ifndef PID_OPENLOOP pid_error[e] = target_temperature[e] - pid_input; if(pid_error[e] > PID_FUNCTIONAL_RANGE) { - pid_output = BANG_MAX; - pid_reset[e] = true; + pid_output = BANG_MAX; + pid_reset[e] = true; } else if(pid_error[e] < -PID_FUNCTIONAL_RANGE || target_temperature[e] == 0) { - pid_output = 0; - pid_reset[e] = true; + pid_output = 0; + pid_reset[e] = true; } else { - if(pid_reset[e] == true) { - temp_iState[e] = 0.0; - pid_reset[e] = false; - } - pTerm[e] = cs.Kp * pid_error[e]; - temp_iState[e] += pid_error[e]; - temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]); - iTerm[e] = cs.Ki * temp_iState[e]; - - //K1 defined in Configuration.h in the PID settings - #define K2 (1.0-K1) - dTerm[e] = (cs.Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); - pid_output = pTerm[e] + iTerm[e] - dTerm[e]; - if (pid_output > PID_MAX) { - if (pid_error[e] > 0 ) temp_iState[e] -= pid_error[e]; // conditional un-integration - pid_output=PID_MAX; - } else if (pid_output < 0){ - if (pid_error[e] < 0 ) temp_iState[e] -= pid_error[e]; // conditional un-integration - pid_output=0; - } + if(pid_reset[e] == true) { + temp_iState[e] = 0.0; + pid_reset[e] = false; + } + pTerm[e] = cs.Kp * pid_error[e]; + temp_iState[e] += pid_error[e]; + temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]); + iTerm[e] = cs.Ki * temp_iState[e]; + + //K1 defined in Configuration.h in the PID settings +#define K2 (1.0-K1) + dTerm[e] = (cs.Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]); + pid_output = pTerm[e] + iTerm[e] - dTerm[e]; + if (pid_output > PID_MAX) { + if (pid_error[e] > 0 ) temp_iState[e] -= pid_error[e]; // conditional un-integration + pid_output=PID_MAX; + } else if (pid_output < 0) { + if (pid_error[e] < 0 ) temp_iState[e] -= pid_error[e]; // conditional un-integration + pid_output=0; + } } temp_dState[e] = pid_input; - #else - pid_output = constrain(target_temperature[e], 0, PID_MAX); - #endif //PID_OPENLOOP - #ifdef PID_DEBUG - SERIAL_ECHO_START; - SERIAL_ECHO(" PID_DEBUG "); - SERIAL_ECHO(e); - SERIAL_ECHO(": Input "); - SERIAL_ECHO(pid_input); - SERIAL_ECHO(" Output "); - SERIAL_ECHO(pid_output); - SERIAL_ECHO(" pTerm "); - SERIAL_ECHO(pTerm[e]); - SERIAL_ECHO(" iTerm "); - SERIAL_ECHO(iTerm[e]); - SERIAL_ECHO(" dTerm "); - SERIAL_ECHOLN(dTerm[e]); - #endif //PID_DEBUG - #else /* PID off */ - pid_output = 0; - if(current_temperature[e] < target_temperature[e]) { - pid_output = PID_MAX; - } - #endif +#else + pid_output = constrain(target_temperature[e], 0, PID_MAX); +#endif //PID_OPENLOOP +#ifdef PID_DEBUG + SERIAL_ECHO_START; + SERIAL_ECHO(" PID_DEBUG "); + SERIAL_ECHO(e); + SERIAL_ECHO(": Input "); + SERIAL_ECHO(pid_input); + SERIAL_ECHO(" Output "); + SERIAL_ECHO(pid_output); + SERIAL_ECHO(" pTerm "); + SERIAL_ECHO(pTerm[e]); + SERIAL_ECHO(" iTerm "); + SERIAL_ECHO(iTerm[e]); + SERIAL_ECHO(" dTerm "); + SERIAL_ECHOLN(dTerm[e]); +#endif //PID_DEBUG +#else /* PID off */ + pid_output = 0; + if(current_temperature[e] < target_temperature[e]) { + pid_output = PID_MAX; + } +#endif - // Check if temperature is within the correct range + // Check if temperature is within the correct range #ifdef AMBIENT_THERMISTOR - if(((current_temperature_ambient < MINTEMP_MINAMBIENT) || (current_temperature[e] > minttemp[e])) && (current_temperature[e] < maxttemp[e])) + if(((current_temperature_ambient < MINTEMP_MINAMBIENT) || (current_temperature[e] > minttemp[e])) && (current_temperature[e] < maxttemp[e])) #else //AMBIENT_THERMISTOR - if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) + if((current_temperature[e] > minttemp[e]) && (current_temperature[e] < maxttemp[e])) #endif //AMBIENT_THERMISTOR - { - soft_pwm[e] = (int)pid_output >> 1; - } - else - { - soft_pwm[e] = 0; - } + { + soft_pwm[e] = (int)pid_output >> 1; + } + else + { + soft_pwm[e] = 0; + } - #ifdef WATCH_TEMP_PERIOD - if(watchmillis[e] && millis() - watchmillis[e] > WATCH_TEMP_PERIOD) - { - if(degHotend(e) < watch_start_temp[e] + WATCH_TEMP_INCREASE) +#ifdef WATCH_TEMP_PERIOD + if(watchmillis[e] && millis() - watchmillis[e] > WATCH_TEMP_PERIOD) { - setTargetHotend(0, e); - LCD_MESSAGEPGM("Heating failed"); - SERIAL_ECHO_START; - SERIAL_ECHOLN("Heating failed"); - }else{ - watchmillis[e] = 0; + if(degHotend(e) < watch_start_temp[e] + WATCH_TEMP_INCREASE) + { + setTargetHotend(0, e); + LCD_MESSAGEPGM("Heating failed"); + SERIAL_ECHO_START; + SERIAL_ECHOLN("Heating failed"); + } else { + watchmillis[e] = 0; + } } - } - #endif - #ifdef TEMP_SENSOR_1_AS_REDUNDANT - if(fabs(current_temperature[0] - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF) { - disable_heater(); - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLNPGM("Extruder switched off. Temperature difference between temp sensors is too high !"); - LCD_ALERTMESSAGEPGM("Err: REDUNDANT TEMP ERROR"); +#endif +#ifdef TEMP_SENSOR_1_AS_REDUNDANT + if(fabs(current_temperature[0] - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF) { + disable_heater(); + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM("Extruder switched off. Temperature difference between temp sensors is too high !"); + LCD_ALERTMESSAGEPGM("Err: REDUNDANT TEMP ERROR"); + } +#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); +#endif } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - #endif - } - #endif - } // End extruder for loop +#endif + } // End extruder for loop #ifndef DEBUG_DISABLE_FANCHECK - #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ +#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - if(millis() - extruder_autofan_last_check > 1000) // only need to check fan state very infrequently - { + if(millis() - extruder_autofan_last_check > 1000) // only need to check fan state very infrequently + { #if (defined(FANCHECK) && ((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1)))) - countFanSpeed(); - checkFanSpeed(); + countFanSpeed(); + checkFanSpeed(); #endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1) - checkExtruderAutoFans(); - extruder_autofan_last_check = millis(); - } - #endif + checkExtruderAutoFans(); + extruder_autofan_last_check = millis(); + } +#endif #endif //DEBUG_DISABLE_FANCHECK - - #ifndef PIDTEMPBED - if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) - return; - previous_millis_bed_heater = millis(); - #endif - #if TEMP_SENSOR_BED != 0 +#ifndef PIDTEMPBED + if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL) + return; + previous_millis_bed_heater = millis(); +#endif + +#if TEMP_SENSOR_BED != 0 - #ifdef PIDTEMPBED +#ifdef PIDTEMPBED pid_input = current_temperature_bed; - #ifndef PID_OPENLOOP - pid_error_bed = target_temperature_bed - pid_input; - pTerm_bed = cs.bedKp * pid_error_bed; - temp_iState_bed += pid_error_bed; - temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed); - iTerm_bed = cs.bedKi * temp_iState_bed; - - //K1 defined in Configuration.h in the PID settings - #define K2 (1.0-K1) - dTerm_bed= (cs.bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed); - temp_dState_bed = pid_input; - - pid_output = pTerm_bed + iTerm_bed - dTerm_bed; - if (pid_output > MAX_BED_POWER) { - if (pid_error_bed > 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration - pid_output=MAX_BED_POWER; - } else if (pid_output < 0){ - if (pid_error_bed < 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration - pid_output=0; - } - - #else - pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER); - #endif //PID_OPENLOOP +#ifndef PID_OPENLOOP + pid_error_bed = target_temperature_bed - pid_input; + pTerm_bed = cs.bedKp * pid_error_bed; + temp_iState_bed += pid_error_bed; + temp_iState_bed = constrain(temp_iState_bed, temp_iState_min_bed, temp_iState_max_bed); + iTerm_bed = cs.bedKi * temp_iState_bed; + + //K1 defined in Configuration.h in the PID settings +#define K2 (1.0-K1) + dTerm_bed= (cs.bedKd * (pid_input - temp_dState_bed))*K2 + (K1 * dTerm_bed); + temp_dState_bed = pid_input; + + pid_output = pTerm_bed + iTerm_bed - dTerm_bed; + if (pid_output > MAX_BED_POWER) { + if (pid_error_bed > 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration + pid_output=MAX_BED_POWER; + } else if (pid_output < 0) { + if (pid_error_bed < 0 ) temp_iState_bed -= pid_error_bed; // conditional un-integration + pid_output=0; + } + +#else + pid_output = constrain(target_temperature_bed, 0, MAX_BED_POWER); +#endif //PID_OPENLOOP #ifdef AMBIENT_THERMISTOR - if(((current_temperature_bed > BED_MINTEMP) || (current_temperature_ambient < MINTEMP_MINAMBIENT)) && (current_temperature_bed < BED_MAXTEMP)) + if(((current_temperature_bed > BED_MINTEMP) || (current_temperature_ambient < MINTEMP_MINAMBIENT)) && (current_temperature_bed < BED_MAXTEMP)) #else //AMBIENT_THERMISTOR - if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) + if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) #endif //AMBIENT_THERMISTOR - { - soft_pwm_bed = (int)pid_output >> 1; - } - else { - soft_pwm_bed = 0; - } - - #elif !defined(BED_LIMIT_SWITCHING) - // Check if temperature is within the correct range - if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) - { + { + soft_pwm_bed = (int)pid_output >> 1; + } + else { + soft_pwm_bed = 0; + } + +#elif !defined(BED_LIMIT_SWITCHING) + // Check if temperature is within the correct range + if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) + { if(current_temperature_bed >= target_temperature_bed) { - soft_pwm_bed = 0; + soft_pwm_bed = 0; } - else + else { - soft_pwm_bed = MAX_BED_POWER>>1; + soft_pwm_bed = MAX_BED_POWER>>1; } - } - else - { + } + else + { soft_pwm_bed = 0; WRITE(HEATER_BED_PIN,LOW); - } - #else //#ifdef BED_LIMIT_SWITCHING - // Check if temperature is within the correct band - if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) - { + } +#else //#ifdef BED_LIMIT_SWITCHING + // Check if temperature is within the correct band + if((current_temperature_bed > BED_MINTEMP) && (current_temperature_bed < BED_MAXTEMP)) + { if(current_temperature_bed > target_temperature_bed + BED_HYSTERESIS) { - soft_pwm_bed = 0; + soft_pwm_bed = 0; } else if(current_temperature_bed <= target_temperature_bed - BED_HYSTERESIS) { - soft_pwm_bed = MAX_BED_POWER>>1; + soft_pwm_bed = MAX_BED_POWER>>1; } - } - else - { + } + else + { soft_pwm_bed = 0; WRITE(HEATER_BED_PIN,LOW); - } - #endif - #endif - + } +#endif +#endif + #ifdef HOST_KEEPALIVE_FEATURE - host_keepalive(); + host_keepalive(); #endif } @@ -824,103 +833,103 @@ void manage_heater() // For hot end temperature measurement. static float analog2temp(int raw, uint8_t e) { #ifdef TEMP_SENSOR_1_AS_REDUNDANT - if(e > EXTRUDERS) + if(e > EXTRUDERS) #else - if(e >= EXTRUDERS) -#endif - { - SERIAL_ERROR_START; - SERIAL_ERROR((int)e); - SERIAL_ERRORLNPGM(" - Invalid extruder number !"); - kill(PSTR(""), 6); - return 0.0; - } - #ifdef HEATER_0_USES_MAX6675 + if(e >= EXTRUDERS) +#endif + { + SERIAL_ERROR_START; + SERIAL_ERROR((int)e); + SERIAL_ERRORLNPGM(" - Invalid extruder number !"); + kill(PSTR(""), 6); + return 0.0; + } +#ifdef HEATER_0_USES_MAX6675 if (e == 0) { - return 0.25 * raw; + return 0.25 * raw; } - #endif - - if(heater_ttbl_map[e] != NULL) - { - float celsius = 0; - uint8_t i; - short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]); +#endif - for (i=1; i raw) - { - celsius = PGM_RD_W((*tt)[i-1][1]) + - (raw - PGM_RD_W((*tt)[i-1][0])) * - (float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) / - (float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0])); - break; - } - } + float celsius = 0; + uint8_t i; + short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]); - // Overflow: Set to last value in the table - if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]); + for (i=1; i raw) + { + celsius = PGM_RD_W((*tt)[i-1][1]) + + (raw - PGM_RD_W((*tt)[i-1][0])) * + (float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) / + (float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0])); + break; + } + } - return celsius; - } - return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET; + // Overflow: Set to last value in the table + if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]); + + return celsius; + } + return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET; } // Derived from RepRap FiveD extruder::getTemperature() // For bed temperature measurement. static float analog2tempBed(int raw) { - #ifdef BED_USES_THERMISTOR +#ifdef BED_USES_THERMISTOR float celsius = 0; byte i; for (i=1; i raw) - { - celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]) + - (raw - PGM_RD_W(BEDTEMPTABLE[i-1][0])) * - (float)(PGM_RD_W(BEDTEMPTABLE[i][1]) - PGM_RD_W(BEDTEMPTABLE[i-1][1])) / - (float)(PGM_RD_W(BEDTEMPTABLE[i][0]) - PGM_RD_W(BEDTEMPTABLE[i-1][0])); - break; - } + if (PGM_RD_W(BEDTEMPTABLE[i][0]) > raw) + { + celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]) + + (raw - PGM_RD_W(BEDTEMPTABLE[i-1][0])) * + (float)(PGM_RD_W(BEDTEMPTABLE[i][1]) - PGM_RD_W(BEDTEMPTABLE[i-1][1])) / + (float)(PGM_RD_W(BEDTEMPTABLE[i][0]) - PGM_RD_W(BEDTEMPTABLE[i-1][0])); + break; + } } // Overflow: Set to last value in the table if (i == BEDTEMPTABLE_LEN) celsius = PGM_RD_W(BEDTEMPTABLE[i-1][1]); - // temperature offset adjustment + // temperature offset adjustment #ifdef BED_OFFSET - float _offset = BED_OFFSET; - float _offset_center = BED_OFFSET_CENTER; - float _offset_start = BED_OFFSET_START; - float _first_koef = (_offset / 2) / (_offset_center - _offset_start); - float _second_koef = (_offset / 2) / (100 - _offset_center); + float _offset = BED_OFFSET; + float _offset_center = BED_OFFSET_CENTER; + float _offset_start = BED_OFFSET_START; + float _first_koef = (_offset / 2) / (_offset_center - _offset_start); + float _second_koef = (_offset / 2) / (100 - _offset_center); - if (celsius >= _offset_start && celsius <= _offset_center) - { - celsius = celsius + (_first_koef * (celsius - _offset_start)); - } - else if (celsius > _offset_center && celsius <= 100) - { - celsius = celsius + (_first_koef * (_offset_center - _offset_start)) + ( _second_koef * ( celsius - ( 100 - _offset_center ) )) ; - } - else if (celsius > 100) - { - celsius = celsius + _offset; - } + if (celsius >= _offset_start && celsius <= _offset_center) + { + celsius = celsius + (_first_koef * (celsius - _offset_start)); + } + else if (celsius > _offset_center && celsius <= 100) + { + celsius = celsius + (_first_koef * (_offset_center - _offset_start)) + ( _second_koef * ( celsius - ( 100 - _offset_center ) )) ; + } + else if (celsius > 100) + { + celsius = celsius + _offset; + } #endif return celsius; - #elif defined BED_USES_AD595 +#elif defined BED_USES_AD595 return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET; - #else +#else return 0; - #endif +#endif } #ifdef AMBIENT_THERMISTOR @@ -931,14 +940,14 @@ static float analog2tempAmbient(int raw) for (i=1; i raw) - { - celsius = PGM_RD_W(AMBIENTTEMPTABLE[i-1][1]) + - (raw - PGM_RD_W(AMBIENTTEMPTABLE[i-1][0])) * - (float)(PGM_RD_W(AMBIENTTEMPTABLE[i][1]) - PGM_RD_W(AMBIENTTEMPTABLE[i-1][1])) / - (float)(PGM_RD_W(AMBIENTTEMPTABLE[i][0]) - PGM_RD_W(AMBIENTTEMPTABLE[i-1][0])); - break; - } + if (PGM_RD_W(AMBIENTTEMPTABLE[i][0]) > raw) + { + celsius = PGM_RD_W(AMBIENTTEMPTABLE[i-1][1]) + + (raw - PGM_RD_W(AMBIENTTEMPTABLE[i-1][0])) * + (float)(PGM_RD_W(AMBIENTTEMPTABLE[i][1]) - PGM_RD_W(AMBIENTTEMPTABLE[i-1][1])) / + (float)(PGM_RD_W(AMBIENTTEMPTABLE[i][0]) - PGM_RD_W(AMBIENTTEMPTABLE[i-1][0])); + break; + } } // Overflow: Set to last value in the table if (i == AMBIENTTEMPTABLE_LEN) celsius = PGM_RD_W(AMBIENTTEMPTABLE[i-1][1]); @@ -950,28 +959,28 @@ static float analog2tempAmbient(int raw) and this function is called from normal context as it is too slow to run in interrupts and will block the stepper routine otherwise */ static void updateTemperaturesFromRawValues() { - for(uint8_t e=0;e -1) +#if defined(HEATER_0_PIN) && (HEATER_0_PIN > -1) SET_OUTPUT(HEATER_0_PIN); - #endif - #if defined(HEATER_1_PIN) && (HEATER_1_PIN > -1) +#endif +#if defined(HEATER_1_PIN) && (HEATER_1_PIN > -1) SET_OUTPUT(HEATER_1_PIN); - #endif - #if defined(HEATER_2_PIN) && (HEATER_2_PIN > -1) +#endif +#if defined(HEATER_2_PIN) && (HEATER_2_PIN > -1) SET_OUTPUT(HEATER_2_PIN); - #endif - #if defined(HEATER_BED_PIN) && (HEATER_BED_PIN > -1) +#endif +#if defined(HEATER_BED_PIN) && (HEATER_BED_PIN > -1) SET_OUTPUT(HEATER_BED_PIN); - #endif - #if defined(FAN_PIN) && (FAN_PIN > -1) +#endif +#if defined(FAN_PIN) && (FAN_PIN > -1) SET_OUTPUT(FAN_PIN); - #ifdef FAST_PWM_FAN +#ifdef FAST_PWM_FAN setPwmFrequency(FAN_PIN, 1); // No prescaling. Pwm frequency = F_CPU/256/8 - #endif - #ifdef FAN_SOFT_PWM +#endif +#ifdef FAN_SOFT_PWM soft_pwm_fan = fanSpeedSoftPwm / 2; - #endif - #endif - - #ifdef HEATER_0_USES_MAX6675 - #ifndef SDSUPPORT - SET_OUTPUT(SCK_PIN); - WRITE(SCK_PIN,0); - - SET_OUTPUT(MOSI_PIN); - WRITE(MOSI_PIN,1); - - SET_INPUT(MISO_PIN); - WRITE(MISO_PIN,1); - #endif +#endif +#endif + +#ifdef HEATER_0_USES_MAX6675 +#ifndef SDSUPPORT + SET_OUTPUT(SCK_PIN); + WRITE(SCK_PIN,0); + + SET_OUTPUT(MOSI_PIN); + WRITE(MOSI_PIN,1); + + SET_INPUT(MISO_PIN); + WRITE(MISO_PIN,1); +#endif /* Using pinMode and digitalWrite, as that was the only way I could get it to compile */ - + //Have to toggle SD card CS pin to low first, to enable firmware to talk with SD card - pinMode(SS_PIN, OUTPUT); - digitalWrite(SS_PIN,0); - pinMode(MAX6675_SS, OUTPUT); - digitalWrite(MAX6675_SS,1); - #endif - - adc_init(); - - // Use timer0 for temperature measurement - // Interleave temperature interrupt with millies interrupt - OCR0B = 128; - TIMSK0 |= (1< HEATER_0_MAXTEMP) { + maxttemp[0] = HEATER_0_MAXTEMP; + while(analog2temp(maxttemp_raw[0], 0) > HEATER_0_MAXTEMP) { #if HEATER_0_RAW_LO_TEMP < HEATER_0_RAW_HI_TEMP - maxttemp_raw[0] -= OVERSAMPLENR; + maxttemp_raw[0] -= OVERSAMPLENR; #else - maxttemp_raw[0] += OVERSAMPLENR; + maxttemp_raw[0] += OVERSAMPLENR; #endif - } + } #endif //MAXTEMP #if (EXTRUDERS > 1) && defined(HEATER_1_MINTEMP) - minttemp[1] = HEATER_1_MINTEMP; - while(analog2temp(minttemp_raw[1], 1) < HEATER_1_MINTEMP) { + minttemp[1] = HEATER_1_MINTEMP; + while(analog2temp(minttemp_raw[1], 1) < HEATER_1_MINTEMP) { #if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP - minttemp_raw[1] += OVERSAMPLENR; + minttemp_raw[1] += OVERSAMPLENR; #else - minttemp_raw[1] -= OVERSAMPLENR; + minttemp_raw[1] -= OVERSAMPLENR; #endif - } + } #endif // MINTEMP 1 #if (EXTRUDERS > 1) && defined(HEATER_1_MAXTEMP) - maxttemp[1] = HEATER_1_MAXTEMP; - while(analog2temp(maxttemp_raw[1], 1) > HEATER_1_MAXTEMP) { + maxttemp[1] = HEATER_1_MAXTEMP; + while(analog2temp(maxttemp_raw[1], 1) > HEATER_1_MAXTEMP) { #if HEATER_1_RAW_LO_TEMP < HEATER_1_RAW_HI_TEMP - maxttemp_raw[1] -= OVERSAMPLENR; + maxttemp_raw[1] -= OVERSAMPLENR; #else - maxttemp_raw[1] += OVERSAMPLENR; + maxttemp_raw[1] += OVERSAMPLENR; #endif - } + } #endif //MAXTEMP 1 #if (EXTRUDERS > 2) && defined(HEATER_2_MINTEMP) - minttemp[2] = HEATER_2_MINTEMP; - while(analog2temp(minttemp_raw[2], 2) < HEATER_2_MINTEMP) { + minttemp[2] = HEATER_2_MINTEMP; + while(analog2temp(minttemp_raw[2], 2) < HEATER_2_MINTEMP) { #if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP - minttemp_raw[2] += OVERSAMPLENR; + minttemp_raw[2] += OVERSAMPLENR; #else - minttemp_raw[2] -= OVERSAMPLENR; + minttemp_raw[2] -= OVERSAMPLENR; #endif - } + } #endif //MINTEMP 2 #if (EXTRUDERS > 2) && defined(HEATER_2_MAXTEMP) - maxttemp[2] = HEATER_2_MAXTEMP; - while(analog2temp(maxttemp_raw[2], 2) > HEATER_2_MAXTEMP) { + maxttemp[2] = HEATER_2_MAXTEMP; + while(analog2temp(maxttemp_raw[2], 2) > HEATER_2_MAXTEMP) { #if HEATER_2_RAW_LO_TEMP < HEATER_2_RAW_HI_TEMP - maxttemp_raw[2] -= OVERSAMPLENR; + maxttemp_raw[2] -= OVERSAMPLENR; #else - maxttemp_raw[2] += OVERSAMPLENR; + maxttemp_raw[2] += OVERSAMPLENR; #endif - } + } #endif //MAXTEMP 2 #ifdef BED_MINTEMP - /* No bed MINTEMP error implemented?!? */ - while(analog2tempBed(bed_minttemp_raw) < BED_MINTEMP) { + /* No bed MINTEMP error implemented?!? */ + while(analog2tempBed(bed_minttemp_raw) < BED_MINTEMP) { #if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP - bed_minttemp_raw += OVERSAMPLENR; + bed_minttemp_raw += OVERSAMPLENR; #else - bed_minttemp_raw -= OVERSAMPLENR; + bed_minttemp_raw -= OVERSAMPLENR; #endif - } - + } + #endif //BED_MINTEMP #ifdef BED_MAXTEMP - while(analog2tempBed(bed_maxttemp_raw) > BED_MAXTEMP) { + while(analog2tempBed(bed_maxttemp_raw) > BED_MAXTEMP) { #if HEATER_BED_RAW_LO_TEMP < HEATER_BED_RAW_HI_TEMP - bed_maxttemp_raw -= OVERSAMPLENR; + bed_maxttemp_raw -= OVERSAMPLENR; #else - bed_maxttemp_raw += OVERSAMPLENR; + bed_maxttemp_raw += OVERSAMPLENR; #endif - } + } #endif //BED_MAXTEMP } -void setWatch() -{ +void setWatch() +{ #ifdef WATCH_TEMP_PERIOD - for (int e = 0; e < EXTRUDERS; e++) - { - if(degHotend(e) < degTargetHotend(e) - (WATCH_TEMP_INCREASE * 2)) + for (int e = 0; e < EXTRUDERS; e++) { - watch_start_temp[e] = degHotend(e); - watchmillis[e] = millis(); - } - } -#endif + if(degHotend(e) < degTargetHotend(e) - (WATCH_TEMP_INCREASE * 2)) + { + watch_start_temp[e] = degHotend(e); + watchmillis[e] = millis(); + } + } +#endif } #if (defined (TEMP_RUNAWAY_BED_HYSTERESIS) && TEMP_RUNAWAY_BED_TIMEOUT > 0) || (defined (TEMP_RUNAWAY_EXTRUDER_HYSTERESIS) && TEMP_RUNAWAY_EXTRUDER_TIMEOUT > 0) void temp_runaway_check(int _heater_id, float _target_temperature, float _current_temperature, float _output, bool _isbed) { - float __hysteresis = 0; - int __timeout = 0; - bool temp_runaway_check_active = false; - static float __preheat_start[2] = { 0,0}; //currently just bed and one extruder - static int __preheat_counter[2] = { 0,0}; - static int __preheat_errors[2] = { 0,0}; - + float __hysteresis = 0; + int __timeout = 0; + bool temp_runaway_check_active = false; + static float __preheat_start[2] = { 0,0}; //currently just bed and one extruder + static int __preheat_counter[2] = { 0,0}; + static int __preheat_errors[2] = { 0,0}; - if (millis() - temp_runaway_timer[_heater_id] > 2000) - { + + if (millis() - temp_runaway_timer[_heater_id] > 2000) + { #ifdef TEMP_RUNAWAY_BED_TIMEOUT - if (_isbed) - { - __hysteresis = TEMP_RUNAWAY_BED_HYSTERESIS; - __timeout = TEMP_RUNAWAY_BED_TIMEOUT; - } + if (_isbed) + { + __hysteresis = TEMP_RUNAWAY_BED_HYSTERESIS; + __timeout = TEMP_RUNAWAY_BED_TIMEOUT; + } #endif #ifdef TEMP_RUNAWAY_EXTRUDER_TIMEOUT - if (!_isbed) - { - __hysteresis = TEMP_RUNAWAY_EXTRUDER_HYSTERESIS; - __timeout = TEMP_RUNAWAY_EXTRUDER_TIMEOUT; - } -#endif - - temp_runaway_timer[_heater_id] = millis(); - if (_output == 0) - { - temp_runaway_check_active = false; - temp_runaway_error_counter[_heater_id] = 0; - } - - if (temp_runaway_target[_heater_id] != _target_temperature) - { - if (_target_temperature > 0) - { - temp_runaway_status[_heater_id] = TempRunaway_PREHEAT; - temp_runaway_target[_heater_id] = _target_temperature; - __preheat_start[_heater_id] = _current_temperature; - __preheat_counter[_heater_id] = 0; - } - else - { - temp_runaway_status[_heater_id] = TempRunaway_INACTIVE; - temp_runaway_target[_heater_id] = _target_temperature; - } - } - - if ((_current_temperature < _target_temperature) && (temp_runaway_status[_heater_id] == TempRunaway_PREHEAT)) - { - __preheat_counter[_heater_id]++; - if (__preheat_counter[_heater_id] > ((_isbed) ? 16 : 8)) // periodicaly check if current temperature changes - { - /*SERIAL_ECHOPGM("Heater:"); - MYSERIAL.print(_heater_id); - SERIAL_ECHOPGM(" T:"); - MYSERIAL.print(_current_temperature); - SERIAL_ECHOPGM(" Tstart:"); - MYSERIAL.print(__preheat_start[_heater_id]);*/ - - if (_current_temperature - __preheat_start[_heater_id] < 2) { - __preheat_errors[_heater_id]++; - /*SERIAL_ECHOPGM(" Preheat errors:"); - MYSERIAL.println(__preheat_errors[_heater_id]);*/ - } - else { - //SERIAL_ECHOLNPGM(""); - __preheat_errors[_heater_id] = 0; - } - - if (__preheat_errors[_heater_id] > ((_isbed) ? 2 : 5)) - { - if (farm_mode) { prusa_statistics(0); } - temp_runaway_stop(true, _isbed); - if (farm_mode) { prusa_statistics(91); } - } - __preheat_start[_heater_id] = _current_temperature; - __preheat_counter[_heater_id] = 0; - } - } - - if (_current_temperature >= _target_temperature && temp_runaway_status[_heater_id] == TempRunaway_PREHEAT) - { - temp_runaway_status[_heater_id] = TempRunaway_ACTIVE; - temp_runaway_check_active = false; - } - - if (_output > 0) - { - temp_runaway_check_active = true; - } - - - if (temp_runaway_check_active) - { - // we are in range - if ((_current_temperature > (_target_temperature - __hysteresis)) && (_current_temperature < (_target_temperature + __hysteresis))) - { - temp_runaway_check_active = false; - temp_runaway_error_counter[_heater_id] = 0; - } - else - { - if (temp_runaway_status[_heater_id] > TempRunaway_PREHEAT) - { - temp_runaway_error_counter[_heater_id]++; - if (temp_runaway_error_counter[_heater_id] * 2 > __timeout) - { - if (farm_mode) { prusa_statistics(0); } - temp_runaway_stop(false, _isbed); - if (farm_mode) { prusa_statistics(90); } - } - } - } - } - - } + if (!_isbed) + { + __hysteresis = TEMP_RUNAWAY_EXTRUDER_HYSTERESIS; + __timeout = TEMP_RUNAWAY_EXTRUDER_TIMEOUT; + } +#endif + + temp_runaway_timer[_heater_id] = millis(); + if (_output == 0) + { + temp_runaway_check_active = false; + temp_runaway_error_counter[_heater_id] = 0; + } + + if (temp_runaway_target[_heater_id] != _target_temperature) + { + if (_target_temperature > 0) + { + temp_runaway_status[_heater_id] = TempRunaway_PREHEAT; + temp_runaway_target[_heater_id] = _target_temperature; + __preheat_start[_heater_id] = _current_temperature; + __preheat_counter[_heater_id] = 0; + } + else + { + temp_runaway_status[_heater_id] = TempRunaway_INACTIVE; + temp_runaway_target[_heater_id] = _target_temperature; + } + } + + if ((_current_temperature < _target_temperature) && (temp_runaway_status[_heater_id] == TempRunaway_PREHEAT)) + { + __preheat_counter[_heater_id]++; + if (__preheat_counter[_heater_id] > ((_isbed) ? 16 : 8)) // periodicaly check if current temperature changes + { + /*SERIAL_ECHOPGM("Heater:"); + MYSERIAL.print(_heater_id); + SERIAL_ECHOPGM(" T:"); + MYSERIAL.print(_current_temperature); + SERIAL_ECHOPGM(" Tstart:"); + MYSERIAL.print(__preheat_start[_heater_id]);*/ + + if (_current_temperature - __preheat_start[_heater_id] < 2) { + __preheat_errors[_heater_id]++; + /*SERIAL_ECHOPGM(" Preheat errors:"); + MYSERIAL.println(__preheat_errors[_heater_id]);*/ + } + else { + //SERIAL_ECHOLNPGM(""); + __preheat_errors[_heater_id] = 0; + } + + if (__preheat_errors[_heater_id] > ((_isbed) ? 2 : 5)) + { + if (farm_mode) { + prusa_statistics(0); + } + temp_runaway_stop(true, _isbed); + if (farm_mode) { + prusa_statistics(91); + } + } + __preheat_start[_heater_id] = _current_temperature; + __preheat_counter[_heater_id] = 0; + } + } + + if (_current_temperature >= _target_temperature && temp_runaway_status[_heater_id] == TempRunaway_PREHEAT) + { + temp_runaway_status[_heater_id] = TempRunaway_ACTIVE; + temp_runaway_check_active = false; + } + + if (_output > 0) + { + temp_runaway_check_active = true; + } + + + if (temp_runaway_check_active) + { + // we are in range + if ((_current_temperature > (_target_temperature - __hysteresis)) && (_current_temperature < (_target_temperature + __hysteresis))) + { + temp_runaway_check_active = false; + temp_runaway_error_counter[_heater_id] = 0; + } + else + { + if (temp_runaway_status[_heater_id] > TempRunaway_PREHEAT) + { + temp_runaway_error_counter[_heater_id]++; + if (temp_runaway_error_counter[_heater_id] * 2 > __timeout) + { + if (farm_mode) { + prusa_statistics(0); + } + temp_runaway_stop(false, _isbed); + if (farm_mode) { + prusa_statistics(90); + } + } + } + } + } + + } } void temp_runaway_stop(bool isPreheat, bool isBed) { - cancel_heatup = true; - quickStop(); - if (card.sdprinting) - { - card.sdprinting = false; - card.closefile(); - } - // Clean the input command queue - // This is necessary, because in command queue there can be commands which would later set heater or bed temperature. - cmdqueue_reset(); - - disable_heater(); - disable_x(); - disable_y(); - disable_e0(); - disable_e1(); - disable_e2(); - manage_heater(); - lcd_update(0); -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) - WRITE(BEEPER, HIGH); - delayMicroseconds(500); - WRITE(BEEPER, LOW); - delayMicroseconds(100); - - if (isPreheat) - { - Stop(); - isBed ? LCD_ALERTMESSAGEPGM("BED PREHEAT ERROR") : LCD_ALERTMESSAGEPGM("PREHEAT ERROR"); - SERIAL_ERROR_START; - isBed ? SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HEATBED)") : SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HOTEND)"); - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - SET_OUTPUT(FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); - analogWrite(FAN_PIN, 255); - fanSpeed = 255; - delayMicroseconds(2000); - } - else - { - isBed ? LCD_ALERTMESSAGEPGM("BED THERMAL RUNAWAY") : LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY"); - SERIAL_ERROR_START; - isBed ? SERIAL_ERRORLNPGM(" HEATBED THERMAL RUNAWAY") : SERIAL_ERRORLNPGM(" HOTEND THERMAL RUNAWAY"); - } + cancel_heatup = true; + quickStop(); + if (card.sdprinting) + { + card.sdprinting = false; + card.closefile(); + } + // Clean the input command queue + // This is necessary, because in command queue there can be commands which would later set heater or bed temperature. + cmdqueue_reset(); + + disable_heater(); + disable_x(); + disable_y(); + disable_e0(); + disable_e1(); + disable_e2(); + manage_heater(); + lcd_update(0); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) + WRITE(BEEPER, HIGH); + delayMicroseconds(500); + WRITE(BEEPER, LOW); + delayMicroseconds(100); + + if (isPreheat) + { + Stop(); + isBed ? LCD_ALERTMESSAGEPGM("BED PREHEAT ERROR") : LCD_ALERTMESSAGEPGM("PREHEAT ERROR"); + SERIAL_ERROR_START; + isBed ? SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HEATBED)") : SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HOTEND)"); + SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); + SET_OUTPUT(FAN_PIN); + WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); + analogWrite(FAN_PIN, 255); + fanSpeed = 255; + delayMicroseconds(2000); + } + else + { + isBed ? LCD_ALERTMESSAGEPGM("BED THERMAL RUNAWAY") : LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY"); + SERIAL_ERROR_START; + isBed ? SERIAL_ERRORLNPGM(" HEATBED THERMAL RUNAWAY") : SERIAL_ERRORLNPGM(" HOTEND THERMAL RUNAWAY"); + } } #endif void disable_heater() { - setAllTargetHotends(0); - setTargetBed(0); - #if defined(TEMP_0_PIN) && TEMP_0_PIN > -1 - target_temperature[0]=0; - soft_pwm[0]=0; - #if defined(HEATER_0_PIN) && HEATER_0_PIN > -1 - WRITE(HEATER_0_PIN,LOW); - #endif - #endif - - #if defined(TEMP_1_PIN) && TEMP_1_PIN > -1 && EXTRUDERS > 1 + setAllTargetHotends(0); + setTargetBed(0); +#if defined(TEMP_0_PIN) && TEMP_0_PIN > -1 + target_temperature[0]=0; + soft_pwm[0]=0; +#if defined(HEATER_0_PIN) && HEATER_0_PIN > -1 + WRITE(HEATER_0_PIN,LOW); +#endif +#endif + +#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 - WRITE(HEATER_1_PIN,LOW); - #endif - #endif - - #if defined(TEMP_2_PIN) && TEMP_2_PIN > -1 && EXTRUDERS > 2 +#if defined(HEATER_1_PIN) && HEATER_1_PIN > -1 + WRITE(HEATER_1_PIN,LOW); +#endif +#endif + +#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 - WRITE(HEATER_2_PIN,LOW); - #endif - #endif +#if defined(HEATER_2_PIN) && HEATER_2_PIN > -1 + WRITE(HEATER_2_PIN,LOW); +#endif +#endif - #if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 +#if defined(TEMP_BED_PIN) && TEMP_BED_PIN > -1 target_temperature_bed=0; soft_pwm_bed=0; - #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - WRITE(HEATER_BED_PIN,LOW); - #endif - #endif +#if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 + WRITE(HEATER_BED_PIN,LOW); +#endif +#endif } void max_temp_error(uint8_t e) { - disable_heater(); - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLN((int)e); - SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !"); - LCD_ALERTMESSAGEPGM("Err: MAXTEMP"); - } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - - - - #endif + disable_heater(); + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLN((int)e); + SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !"); + LCD_ALERTMESSAGEPGM("Err: MAXTEMP"); + } +#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); + + + +#endif SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); SET_OUTPUT(FAN_PIN); SET_OUTPUT(BEEPER); WRITE(FAN_PIN, 1); WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) - WRITE(BEEPER, 1); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) + WRITE(BEEPER, 1); // fanSpeed will consumed by the check_axes_activity() routine. fanSpeed=255; - if (farm_mode) { prusa_statistics(93); } + if (farm_mode) { + prusa_statistics(93); + } } void min_temp_error(uint8_t e) { #ifdef DEBUG_DISABLE_MINTEMP - return; + return; #endif //if (current_temperature_ambient < MINTEMP_MINAMBIENT) return; - disable_heater(); - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLN((int)e); - SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !"); - LCD_ALERTMESSAGEPGM("Err: MINTEMP"); - } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - #endif - if (farm_mode) { prusa_statistics(92); } + disable_heater(); + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLN((int)e); + SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !"); + LCD_ALERTMESSAGEPGM("Err: MINTEMP"); + } +#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); +#endif + if (farm_mode) { + prusa_statistics(92); + } } void bed_max_temp_error(void) { #if HEATER_BED_PIN > -1 - WRITE(HEATER_BED_PIN, 0); + WRITE(HEATER_BED_PIN, 0); +#endif + if(IsStopped() == false) { + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !"); + LCD_ALERTMESSAGEPGM("Err: MAXTEMP BED"); + } +#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE + Stop(); #endif - if(IsStopped() == false) { - SERIAL_ERROR_START; - SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !"); - LCD_ALERTMESSAGEPGM("Err: MAXTEMP BED"); - } - #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE - Stop(); - #endif } void bed_min_temp_error(void) { #ifdef DEBUG_DISABLE_MINTEMP - return; + return; #endif //if (current_temperature_ambient < MINTEMP_MINAMBIENT) return; #if HEATER_BED_PIN > -1 @@ -1452,52 +1473,52 @@ int max6675_temp = 2000; int read_max6675() { - if (millis() - max6675_previous_millis < MAX6675_HEAT_INTERVAL) - return max6675_temp; - - max6675_previous_millis = millis(); - max6675_temp = 0; - - #ifdef PRR + if (millis() - max6675_previous_millis < MAX6675_HEAT_INTERVAL) + return max6675_temp; + + max6675_previous_millis = millis(); + max6675_temp = 0; + +#ifdef PRR PRR &= ~(1<> 3; - } - - return max6675_temp; +#endif + + SPCR = (1<> 3; + } + + return max6675_temp; } #endif @@ -1505,22 +1526,22 @@ int read_max6675() extern "C" { -void adc_ready(void) //callback from adc when sampling finished -{ - current_temperature_raw[0] = adc_values[ADC_PIN_IDX(TEMP_0_PIN)]; //heater - current_temperature_raw_pinda = adc_values[ADC_PIN_IDX(TEMP_PINDA_PIN)]; - current_temperature_bed_raw = adc_values[ADC_PIN_IDX(TEMP_BED_PIN)]; + void adc_ready(void) //callback from adc when sampling finished + { + current_temperature_raw[0] = adc_values[ADC_PIN_IDX(TEMP_0_PIN)]; //heater + current_temperature_raw_pinda = adc_values[ADC_PIN_IDX(TEMP_PINDA_PIN)]; + current_temperature_bed_raw = adc_values[ADC_PIN_IDX(TEMP_BED_PIN)]; #ifdef VOLT_PWR_PIN - current_voltage_raw_pwr = adc_values[ADC_PIN_IDX(VOLT_PWR_PIN)]; + current_voltage_raw_pwr = adc_values[ADC_PIN_IDX(VOLT_PWR_PIN)]; #endif #ifdef AMBIENT_THERMISTOR - current_temperature_raw_ambient = adc_values[ADC_PIN_IDX(TEMP_AMBIENT_PIN)]; + current_temperature_raw_ambient = adc_values[ADC_PIN_IDX(TEMP_AMBIENT_PIN)]; #endif //AMBIENT_THERMISTOR #ifdef VOLT_BED_PIN - current_voltage_raw_bed = adc_values[ADC_PIN_IDX(VOLT_BED_PIN)]; // 6->9 + current_voltage_raw_bed = adc_values[ADC_PIN_IDX(VOLT_BED_PIN)]; // 6->9 #endif - temp_meas_ready = true; -} + temp_meas_ready = true; + } } // extern "C" @@ -1528,358 +1549,362 @@ void adc_ready(void) //callback from adc when sampling finished // Timer 0 is shared with millies ISR(TIMER0_COMPB_vect) { - static bool _lock = false; - if (_lock) return; - _lock = true; - asm("sei"); - - if (!temp_meas_ready) adc_cycle(); - else - { - check_max_temp(); - check_min_temp(); - } - lcd_buttons_update(); - - static unsigned char pwm_count = (1 << SOFT_PWM_SCALE); - static unsigned char soft_pwm_0; + static bool _lock = false; + if (_lock) return; + _lock = true; + asm("sei"); + + if (!temp_meas_ready) adc_cycle(); + else + { + check_max_temp(); + check_min_temp(); + } + lcd_buttons_update(); + + static unsigned char pwm_count = (1 << SOFT_PWM_SCALE); + static unsigned char soft_pwm_0; #ifdef SLOW_PWM_HEATERS - static unsigned char slow_pwm_count = 0; - static unsigned char state_heater_0 = 0; - static unsigned char state_timer_heater_0 = 0; -#endif + static unsigned char slow_pwm_count = 0; + static unsigned char state_heater_0 = 0; + static unsigned char state_timer_heater_0 = 0; +#endif #if (EXTRUDERS > 1) || defined(HEATERS_PARALLEL) - static unsigned char soft_pwm_1; + static unsigned char soft_pwm_1; #ifdef SLOW_PWM_HEATERS - static unsigned char state_heater_1 = 0; - static unsigned char state_timer_heater_1 = 0; -#endif + static unsigned char state_heater_1 = 0; + static unsigned char state_timer_heater_1 = 0; +#endif #endif #if EXTRUDERS > 2 - static unsigned char soft_pwm_2; + static unsigned char soft_pwm_2; #ifdef SLOW_PWM_HEATERS - static unsigned char state_heater_2 = 0; - static unsigned char state_timer_heater_2 = 0; -#endif + static unsigned char state_heater_2 = 0; + static unsigned char state_timer_heater_2 = 0; +#endif #endif #if HEATER_BED_PIN > -1 - static unsigned char soft_pwm_b; + static unsigned char soft_pwm_b; #ifdef SLOW_PWM_HEATERS - static unsigned char state_heater_b = 0; - static unsigned char state_timer_heater_b = 0; -#endif + static unsigned char state_heater_b = 0; + static unsigned char state_timer_heater_b = 0; #endif - +#endif + #if defined(FILWIDTH_PIN) &&(FILWIDTH_PIN > -1) - static unsigned long raw_filwidth_value = 0; //added for filament width sensor + static unsigned long raw_filwidth_value = 0; //added for filament width sensor #endif - + #ifndef SLOW_PWM_HEATERS - /* - * standard PWM modulation - */ - if (pwm_count == 0) - { - soft_pwm_0 = soft_pwm[0]; - if(soft_pwm_0 > 0) - { - WRITE(HEATER_0_PIN,1); + /* + * standard PWM modulation + */ + if (pwm_count == 0) + { + soft_pwm_0 = soft_pwm[0]; + if(soft_pwm_0 > 0) + { + WRITE(HEATER_0_PIN,1); #ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN,1); + WRITE(HEATER_1_PIN,1); #endif - } else WRITE(HEATER_0_PIN,0); + } 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); else WRITE(HEATER_1_PIN,0); + soft_pwm_1 = soft_pwm[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); else WRITE(HEATER_2_PIN,0); + soft_pwm_2 = soft_pwm[2]; + 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); else WRITE(HEATER_BED_PIN,0); + soft_pwm_b = soft_pwm_bed; + 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); else WRITE(FAN_PIN,0); + soft_pwm_fan = fanSpeedSoftPwm / 2; + if(soft_pwm_fan > 0) WRITE(FAN_PIN,1); + else WRITE(FAN_PIN,0); #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); + 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); - pwm_count &= 0x7f; + + pwm_count += (1 << SOFT_PWM_SCALE); + pwm_count &= 0x7f; #else //ifndef SLOW_PWM_HEATERS - /* - * SLOW PWM HEATERS - * - * for heaters drived by relay - */ + /* + * SLOW PWM HEATERS + * + * for heaters drived by relay + */ #ifndef MIN_STATE_TIME #define MIN_STATE_TIME 16 // MIN_STATE_TIME * 65.5 = time in milliseconds #endif - if (slow_pwm_count == 0) { - // EXTRUDER 0 - soft_pwm_0 = soft_pwm[0]; - if (soft_pwm_0 > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_0 == 0) { - // if change state set timer - if (state_heater_0 == 0) { - state_timer_heater_0 = MIN_STATE_TIME; - } - state_heater_0 = 1; - WRITE(HEATER_0_PIN, 1); + if (slow_pwm_count == 0) { + // EXTRUDER 0 + soft_pwm_0 = soft_pwm[0]; + if (soft_pwm_0 > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_0 == 0) { + // if change state set timer + if (state_heater_0 == 0) { + state_timer_heater_0 = MIN_STATE_TIME; + } + state_heater_0 = 1; + WRITE(HEATER_0_PIN, 1); #ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN, 1); -#endif - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_0 == 0) { - // if change state set timer - if (state_heater_0 == 1) { - state_timer_heater_0 = MIN_STATE_TIME; - } - state_heater_0 = 0; - WRITE(HEATER_0_PIN, 0); + WRITE(HEATER_1_PIN, 1); +#endif + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_0 == 0) { + // if change state set timer + if (state_heater_0 == 1) { + state_timer_heater_0 = MIN_STATE_TIME; + } + state_heater_0 = 0; + WRITE(HEATER_0_PIN, 0); #ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN, 0); + WRITE(HEATER_1_PIN, 0); #endif - } - } - + } + } + #if EXTRUDERS > 1 - // EXTRUDER 1 - soft_pwm_1 = soft_pwm[1]; - if (soft_pwm_1 > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_1 == 0) { - // if change state set timer - if (state_heater_1 == 0) { - state_timer_heater_1 = MIN_STATE_TIME; - } - state_heater_1 = 1; - WRITE(HEATER_1_PIN, 1); - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_1 == 0) { - // if change state set timer - if (state_heater_1 == 1) { - state_timer_heater_1 = MIN_STATE_TIME; - } - state_heater_1 = 0; - WRITE(HEATER_1_PIN, 0); - } - } -#endif - + // EXTRUDER 1 + soft_pwm_1 = soft_pwm[1]; + if (soft_pwm_1 > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_1 == 0) { + // if change state set timer + if (state_heater_1 == 0) { + state_timer_heater_1 = MIN_STATE_TIME; + } + state_heater_1 = 1; + WRITE(HEATER_1_PIN, 1); + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_1 == 0) { + // if change state set timer + if (state_heater_1 == 1) { + state_timer_heater_1 = MIN_STATE_TIME; + } + state_heater_1 = 0; + WRITE(HEATER_1_PIN, 0); + } + } +#endif + #if EXTRUDERS > 2 - // EXTRUDER 2 - soft_pwm_2 = soft_pwm[2]; - if (soft_pwm_2 > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_2 == 0) { - // if change state set timer - if (state_heater_2 == 0) { - state_timer_heater_2 = MIN_STATE_TIME; - } - state_heater_2 = 1; - WRITE(HEATER_2_PIN, 1); - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_2 == 0) { - // if change state set timer - if (state_heater_2 == 1) { - state_timer_heater_2 = MIN_STATE_TIME; - } - state_heater_2 = 0; - WRITE(HEATER_2_PIN, 0); - } - } -#endif - + // EXTRUDER 2 + soft_pwm_2 = soft_pwm[2]; + if (soft_pwm_2 > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_2 == 0) { + // if change state set timer + if (state_heater_2 == 0) { + state_timer_heater_2 = MIN_STATE_TIME; + } + state_heater_2 = 1; + WRITE(HEATER_2_PIN, 1); + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_2 == 0) { + // if change state set timer + if (state_heater_2 == 1) { + state_timer_heater_2 = MIN_STATE_TIME; + } + state_heater_2 = 0; + WRITE(HEATER_2_PIN, 0); + } + } +#endif + #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - // BED - soft_pwm_b = soft_pwm_bed; - if (soft_pwm_b > 0) { - // turn ON heather only if the minimum time is up - if (state_timer_heater_b == 0) { - // if change state set timer - if (state_heater_b == 0) { - state_timer_heater_b = MIN_STATE_TIME; - } - state_heater_b = 1; - WRITE(HEATER_BED_PIN, 1); - } - } else { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_b == 0) { - // if change state set timer - if (state_heater_b == 1) { - state_timer_heater_b = MIN_STATE_TIME; - } - state_heater_b = 0; - WRITE(HEATER_BED_PIN, 0); - } - } -#endif - } // if (slow_pwm_count == 0) - - // EXTRUDER 0 - if (soft_pwm_0 < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_0 == 0) { - // if change state set timer - if (state_heater_0 == 1) { - state_timer_heater_0 = MIN_STATE_TIME; - } - state_heater_0 = 0; - WRITE(HEATER_0_PIN, 0); + // BED + soft_pwm_b = soft_pwm_bed; + if (soft_pwm_b > 0) { + // turn ON heather only if the minimum time is up + if (state_timer_heater_b == 0) { + // if change state set timer + if (state_heater_b == 0) { + state_timer_heater_b = MIN_STATE_TIME; + } + state_heater_b = 1; + WRITE(HEATER_BED_PIN, 1); + } + } else { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_b == 0) { + // if change state set timer + if (state_heater_b == 1) { + state_timer_heater_b = MIN_STATE_TIME; + } + state_heater_b = 0; + WRITE(HEATER_BED_PIN, 0); + } + } +#endif + } // if (slow_pwm_count == 0) + + // EXTRUDER 0 + if (soft_pwm_0 < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_0 == 0) { + // if change state set timer + if (state_heater_0 == 1) { + state_timer_heater_0 = MIN_STATE_TIME; + } + state_heater_0 = 0; + WRITE(HEATER_0_PIN, 0); #ifdef HEATERS_PARALLEL - WRITE(HEATER_1_PIN, 0); + WRITE(HEATER_1_PIN, 0); #endif + } } - } - + #if EXTRUDERS > 1 - // EXTRUDER 1 - if (soft_pwm_1 < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_1 == 0) { - // if change state set timer - if (state_heater_1 == 1) { - state_timer_heater_1 = MIN_STATE_TIME; - } - state_heater_1 = 0; - WRITE(HEATER_1_PIN, 0); - } - } -#endif - + // EXTRUDER 1 + if (soft_pwm_1 < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_1 == 0) { + // if change state set timer + if (state_heater_1 == 1) { + state_timer_heater_1 = MIN_STATE_TIME; + } + state_heater_1 = 0; + WRITE(HEATER_1_PIN, 0); + } + } +#endif + #if EXTRUDERS > 2 - // EXTRUDER 2 - if (soft_pwm_2 < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_2 == 0) { - // if change state set timer - if (state_heater_2 == 1) { - state_timer_heater_2 = MIN_STATE_TIME; - } - state_heater_2 = 0; - WRITE(HEATER_2_PIN, 0); - } - } -#endif - + // EXTRUDER 2 + if (soft_pwm_2 < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_2 == 0) { + // if change state set timer + if (state_heater_2 == 1) { + state_timer_heater_2 = MIN_STATE_TIME; + } + state_heater_2 = 0; + WRITE(HEATER_2_PIN, 0); + } + } +#endif + #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - // BED - if (soft_pwm_b < slow_pwm_count) { - // turn OFF heather only if the minimum time is up - if (state_timer_heater_b == 0) { - // if change state set timer - if (state_heater_b == 1) { - state_timer_heater_b = MIN_STATE_TIME; - } - state_heater_b = 0; - WRITE(HEATER_BED_PIN, 0); - } - } -#endif - + // BED + if (soft_pwm_b < slow_pwm_count) { + // turn OFF heather only if the minimum time is up + if (state_timer_heater_b == 0) { + // if change state set timer + if (state_heater_b == 1) { + state_timer_heater_b = MIN_STATE_TIME; + } + state_heater_b = 0; + WRITE(HEATER_BED_PIN, 0); + } + } +#endif + #ifdef FAN_SOFT_PWM - if (pwm_count == 0){ - soft_pwm_fan = fanSpeedSoftPwm / 2; - if (soft_pwm_fan > 0) WRITE(FAN_PIN,1); else WRITE(FAN_PIN,0); - } - if (soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0); -#endif - - pwm_count += (1 << SOFT_PWM_SCALE); - pwm_count &= 0x7f; - - // increment slow_pwm_count only every 64 pwm_count circa 65.5ms - if ((pwm_count % 64) == 0) { - slow_pwm_count++; - slow_pwm_count &= 0x7f; - - // Extruder 0 - if (state_timer_heater_0 > 0) { - state_timer_heater_0--; - } - + if (pwm_count == 0) { + soft_pwm_fan = fanSpeedSoftPwm / 2; + if (soft_pwm_fan > 0) WRITE(FAN_PIN,1); + else WRITE(FAN_PIN,0); + } + if (soft_pwm_fan < pwm_count) WRITE(FAN_PIN,0); +#endif + + pwm_count += (1 << SOFT_PWM_SCALE); + pwm_count &= 0x7f; + + // increment slow_pwm_count only every 64 pwm_count circa 65.5ms + if ((pwm_count % 64) == 0) { + slow_pwm_count++; + slow_pwm_count &= 0x7f; + + // Extruder 0 + if (state_timer_heater_0 > 0) { + state_timer_heater_0--; + } + #if EXTRUDERS > 1 - // Extruder 1 - if (state_timer_heater_1 > 0) - state_timer_heater_1--; + // Extruder 1 + if (state_timer_heater_1 > 0) + state_timer_heater_1--; #endif - + #if EXTRUDERS > 2 - // Extruder 2 - if (state_timer_heater_2 > 0) - state_timer_heater_2--; + // Extruder 2 + if (state_timer_heater_2 > 0) + state_timer_heater_2--; #endif - + #if defined(HEATER_BED_PIN) && HEATER_BED_PIN > -1 - // Bed - if (state_timer_heater_b > 0) - state_timer_heater_b--; + // Bed + if (state_timer_heater_b > 0) + state_timer_heater_b--; #endif - } //if ((pwm_count % 64) == 0) { - + } //if ((pwm_count % 64) == 0) { + #endif //ifndef SLOW_PWM_HEATERS - + #ifdef BABYSTEPPING - for(uint8_t axis=0;axis<3;axis++) - { - int curTodo=babystepsTodo[axis]; //get rid of volatile for performance - - if(curTodo>0) - { - asm("cli"); - babystep(axis,/*fwd*/true); - babystepsTodo[axis]--; //less to do next time - asm("sei"); - } - else - if(curTodo<0) + for(uint8_t axis=0; axis<3; axis++) { - asm("cli"); - babystep(axis,/*fwd*/false); - babystepsTodo[axis]++; //less to do next time - asm("sei"); + int curTodo=babystepsTodo[axis]; //get rid of volatile for performance + + if(curTodo>0) + { + asm("cli"); + babystep(axis,/*fwd*/true); + babystepsTodo[axis]--; //less to do next time + asm("sei"); + } + else if(curTodo<0) + { + asm("cli"); + babystep(axis,/*fwd*/false); + babystepsTodo[axis]++; //less to do next time + asm("sei"); + } } - } #endif //BABYSTEPPING #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1)) - check_fans(); + check_fans(); #endif //(defined(TACH_0)) - _lock = false; + _lock = false; } void check_max_temp() @@ -1899,8 +1924,8 @@ void check_max_temp() #else if (current_temperature_bed_raw >= bed_maxttemp_raw) { #endif - target_temperature_bed = 0; - bed_max_temp_error(); + target_temperature_bed = 0; + bed_max_temp_error(); } #endif @@ -1910,59 +1935,59 @@ void check_min_temp_heater0() { //heater #if HEATER_0_RAW_LO_TEMP > HEATER_0_RAW_HI_TEMP - if (current_temperature_raw[0] >= minttemp_raw[0]) { + if (current_temperature_raw[0] >= minttemp_raw[0]) { #else - if (current_temperature_raw[0] <= minttemp_raw[0]) { + if (current_temperature_raw[0] <= minttemp_raw[0]) { #endif - min_temp_error(0); - } + min_temp_error(0); + } } void check_min_temp_bed() { #if HEATER_BED_RAW_LO_TEMP > HEATER_BED_RAW_HI_TEMP - if (current_temperature_bed_raw >= bed_minttemp_raw) { + if (current_temperature_bed_raw >= bed_minttemp_raw) { #else - if (current_temperature_bed_raw <= bed_minttemp_raw) { + if (current_temperature_bed_raw <= bed_minttemp_raw) { #endif - bed_min_temp_error(); - } + bed_min_temp_error(); + } } void check_min_temp() { #ifdef AMBIENT_THERMISTOR - static uint8_t heat_cycles = 0; - if (current_temperature_raw_ambient > OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW) - { - if (READ(HEATER_0_PIN) == HIGH) - { + static uint8_t heat_cycles = 0; + if (current_temperature_raw_ambient > OVERSAMPLENR*MINTEMP_MINAMBIENT_RAW) + { + if (READ(HEATER_0_PIN) == HIGH) + { // if ((heat_cycles % 10) == 0) // printf_P(PSTR("X%d\n"), heat_cycles); - if (heat_cycles > 50) //reaction time 5-10s - check_min_temp_heater0(); - else - heat_cycles++; - } - else - heat_cycles = 0; - return; - } + if (heat_cycles > 50) //reaction time 5-10s + check_min_temp_heater0(); + else + heat_cycles++; + } + else + heat_cycles = 0; + return; + } #endif //AMBIENT_THERMISTOR - check_min_temp_heater0(); - check_min_temp_bed(); + check_min_temp_heater0(); + check_min_temp_bed(); } - + #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1)) void check_fans() { - if (READ(TACH_0) != fan_state[0]) { - fan_edge_counter[0] ++; - fan_state[0] = !fan_state[0]; - } - //if (READ(TACH_1) != fan_state[1]) { - // fan_edge_counter[1] ++; - // fan_state[1] = !fan_state[1]; - //} + if (READ(TACH_0) != fan_state[0]) { + fan_edge_counter[0] ++; + fan_state[0] = !fan_state[0]; + } + //if (READ(TACH_1) != fan_state[1]) { + // fan_edge_counter[1] ++; + // fan_state[1] = !fan_state[1]; + //} } #endif //TACH_0 @@ -1972,12 +1997,12 @@ void check_fans() { float scalePID_i(float i) { - return i*PID_dT; + return i*PID_dT; } float unscalePID_i(float i) { - return i/PID_dT; + return i/PID_dT; } float scalePID_d(float d) @@ -1987,7 +2012,7 @@ float scalePID_d(float d) float unscalePID_d(float d) { - return d*PID_dT; + return d*PID_dT; } #endif //PIDTEMP diff --git a/Firmware/temperature.h b/Firmware/temperature.h index 9a3cee8348..9910bdf793 100755 --- a/Firmware/temperature.h +++ b/Firmware/temperature.h @@ -19,12 +19,12 @@ */ #ifndef temperature_h -#define temperature_h +#define temperature_h #include "Marlin.h" #include "planner.h" #ifdef PID_ADD_EXTRUSION_RATE - #include "stepper.h" +#include "stepper.h" #endif #define ENABLE_TEMPERATURE_INTERRUPT() TIMSK0 |= (1< -1 - extern unsigned char soft_pwm_bed; +extern unsigned char soft_pwm_bed; #endif #ifdef PIDTEMP - extern int pid_cycle, pid_number_of_cycles; - extern float Kc,_Kp,_Ki,_Kd; - extern bool pid_tuning_finished; - float scalePID_i(float i); - float scalePID_d(float d); - float unscalePID_i(float i); - float unscalePID_d(float d); +extern int pid_cycle, pid_number_of_cycles; +extern float Kc,_Kp,_Ki,_Kd; +extern bool pid_tuning_finished; +float scalePID_i(float i); +float scalePID_d(float d); +float unscalePID_i(float i); +float unscalePID_d(float d); #endif - - + + #ifdef BABYSTEPPING - extern volatile int babystepsTodo[3]; +extern volatile int babystepsTodo[3]; #endif inline void babystepsTodoZadd(int n) @@ -109,34 +109,34 @@ inline void babystepsTodoZsubtract(int n) //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]; }; #ifdef SHOW_TEMP_ADC_VALUES - FORCE_INLINE float rawHotendTemp(uint8_t extruder) { +FORCE_INLINE float rawHotendTemp(uint8_t extruder) { return current_temperature_raw[extruder]; - }; +}; - FORCE_INLINE float rawBedTemp() { +FORCE_INLINE float rawBedTemp() { return current_temperature_bed_raw; - }; +}; #endif FORCE_INLINE float degBed() { - return current_temperature_bed; + return current_temperature_bed; }; -FORCE_INLINE float degTargetHotend(uint8_t extruder) { - return target_temperature[extruder]; +FORCE_INLINE float degTargetHotend(uint8_t extruder) { + return target_temperature[extruder]; }; -FORCE_INLINE float degTargetBed() { - return target_temperature_bed; +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 setTargetHotend(const float &celsius, uint8_t extruder) { + target_temperature[extruder] = celsius; }; static inline void setTargetHotendSafe(const float &celsius, uint8_t extruder) @@ -146,27 +146,27 @@ static inline void setTargetHotendSafe(const float &celsius, uint8_t extruder) static inline void setAllTargetHotends(const float &celsius) { - for(int i=0;i current_temperature[extruder]; +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; + return target_temperature_bed > current_temperature_bed; }; -FORCE_INLINE bool isCoolingHotend(uint8_t extruder) { - return target_temperature[extruder] < current_temperature[extruder]; +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; + return target_temperature_bed < current_temperature_bed; }; #define degHotend0() degHotend(0) @@ -202,15 +202,15 @@ void setWatch(); void updatePID(); -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); diff --git a/Firmware/thermistortables.h b/Firmware/thermistortables.h index dc934ccfd0..e171796ae1 100755 --- a/Firmware/thermistortables.h +++ b/Firmware/thermistortables.h @@ -9,67 +9,67 @@ #if (THERMISTORHEATER_0 == 1) || (THERMISTORHEATER_1 == 1) || (THERMISTORHEATER_2 == 1) || (THERMISTORBED == 1) //100k bed thermistor const short temptable_1[][2] PROGMEM = { -{ 23*OVERSAMPLENR , 300 }, -{ 25*OVERSAMPLENR , 295 }, -{ 27*OVERSAMPLENR , 290 }, -{ 28*OVERSAMPLENR , 285 }, -{ 31*OVERSAMPLENR , 280 }, -{ 33*OVERSAMPLENR , 275 }, -{ 35*OVERSAMPLENR , 270 }, -{ 38*OVERSAMPLENR , 265 }, -{ 41*OVERSAMPLENR , 260 }, -{ 44*OVERSAMPLENR , 255 }, -{ 48*OVERSAMPLENR , 250 }, -{ 52*OVERSAMPLENR , 245 }, -{ 56*OVERSAMPLENR , 240 }, -{ 61*OVERSAMPLENR , 235 }, -{ 66*OVERSAMPLENR , 230 }, -{ 71*OVERSAMPLENR , 225 }, -{ 78*OVERSAMPLENR , 220 }, -{ 84*OVERSAMPLENR , 215 }, -{ 92*OVERSAMPLENR , 210 }, -{ 100*OVERSAMPLENR , 205 }, -{ 109*OVERSAMPLENR , 200 }, -{ 120*OVERSAMPLENR , 195 }, -{ 131*OVERSAMPLENR , 190 }, -{ 143*OVERSAMPLENR , 185 }, -{ 156*OVERSAMPLENR , 180 }, -{ 171*OVERSAMPLENR , 175 }, -{ 187*OVERSAMPLENR , 170 }, -{ 205*OVERSAMPLENR , 165 }, -{ 224*OVERSAMPLENR , 160 }, -{ 245*OVERSAMPLENR , 155 }, -{ 268*OVERSAMPLENR , 150 }, -{ 293*OVERSAMPLENR , 145 }, -{ 320*OVERSAMPLENR , 140 }, -{ 348*OVERSAMPLENR , 135 }, -{ 379*OVERSAMPLENR , 130 }, -{ 411*OVERSAMPLENR , 125 }, -{ 445*OVERSAMPLENR , 120 }, -{ 480*OVERSAMPLENR , 115 }, -{ 516*OVERSAMPLENR , 110 }, -{ 553*OVERSAMPLENR , 105 }, -{ 591*OVERSAMPLENR , 100 }, -{ 628*OVERSAMPLENR , 95 }, -{ 665*OVERSAMPLENR , 90 }, -{ 702*OVERSAMPLENR , 85 }, -{ 737*OVERSAMPLENR , 80 }, -{ 770*OVERSAMPLENR , 75 }, -{ 801*OVERSAMPLENR , 70 }, -{ 830*OVERSAMPLENR , 65 }, -{ 857*OVERSAMPLENR , 60 }, -{ 881*OVERSAMPLENR , 55 }, -{ 903*OVERSAMPLENR , 50 }, -{ 922*OVERSAMPLENR , 45 }, -{ 939*OVERSAMPLENR , 40 }, -{ 954*OVERSAMPLENR , 35 }, -{ 966*OVERSAMPLENR , 30 }, -{ 977*OVERSAMPLENR , 25 }, -{ 985*OVERSAMPLENR , 20 }, -{ 993*OVERSAMPLENR , 15 }, -{ 999*OVERSAMPLENR , 10 }, -{ 1004*OVERSAMPLENR , 5 }, -{ 1008*OVERSAMPLENR , 0 } //safety + { 23*OVERSAMPLENR, 300 }, + { 25*OVERSAMPLENR, 295 }, + { 27*OVERSAMPLENR, 290 }, + { 28*OVERSAMPLENR, 285 }, + { 31*OVERSAMPLENR, 280 }, + { 33*OVERSAMPLENR, 275 }, + { 35*OVERSAMPLENR, 270 }, + { 38*OVERSAMPLENR, 265 }, + { 41*OVERSAMPLENR, 260 }, + { 44*OVERSAMPLENR, 255 }, + { 48*OVERSAMPLENR, 250 }, + { 52*OVERSAMPLENR, 245 }, + { 56*OVERSAMPLENR, 240 }, + { 61*OVERSAMPLENR, 235 }, + { 66*OVERSAMPLENR, 230 }, + { 71*OVERSAMPLENR, 225 }, + { 78*OVERSAMPLENR, 220 }, + { 84*OVERSAMPLENR, 215 }, + { 92*OVERSAMPLENR, 210 }, + { 100*OVERSAMPLENR, 205 }, + { 109*OVERSAMPLENR, 200 }, + { 120*OVERSAMPLENR, 195 }, + { 131*OVERSAMPLENR, 190 }, + { 143*OVERSAMPLENR, 185 }, + { 156*OVERSAMPLENR, 180 }, + { 171*OVERSAMPLENR, 175 }, + { 187*OVERSAMPLENR, 170 }, + { 205*OVERSAMPLENR, 165 }, + { 224*OVERSAMPLENR, 160 }, + { 245*OVERSAMPLENR, 155 }, + { 268*OVERSAMPLENR, 150 }, + { 293*OVERSAMPLENR, 145 }, + { 320*OVERSAMPLENR, 140 }, + { 348*OVERSAMPLENR, 135 }, + { 379*OVERSAMPLENR, 130 }, + { 411*OVERSAMPLENR, 125 }, + { 445*OVERSAMPLENR, 120 }, + { 480*OVERSAMPLENR, 115 }, + { 516*OVERSAMPLENR, 110 }, + { 553*OVERSAMPLENR, 105 }, + { 591*OVERSAMPLENR, 100 }, + { 628*OVERSAMPLENR, 95 }, + { 665*OVERSAMPLENR, 90 }, + { 702*OVERSAMPLENR, 85 }, + { 737*OVERSAMPLENR, 80 }, + { 770*OVERSAMPLENR, 75 }, + { 801*OVERSAMPLENR, 70 }, + { 830*OVERSAMPLENR, 65 }, + { 857*OVERSAMPLENR, 60 }, + { 881*OVERSAMPLENR, 55 }, + { 903*OVERSAMPLENR, 50 }, + { 922*OVERSAMPLENR, 45 }, + { 939*OVERSAMPLENR, 40 }, + { 954*OVERSAMPLENR, 35 }, + { 966*OVERSAMPLENR, 30 }, + { 977*OVERSAMPLENR, 25 }, + { 985*OVERSAMPLENR, 20 }, + { 993*OVERSAMPLENR, 15 }, + { 999*OVERSAMPLENR, 10 }, + { 1004*OVERSAMPLENR, 5 }, + { 1008*OVERSAMPLENR, 0 } //safety }; #endif #if (THERMISTORHEATER_0 == 2) || (THERMISTORHEATER_1 == 2) || (THERMISTORHEATER_2 == 2) || (THERMISTORBED == 2) //200k bed thermistor @@ -77,96 +77,96 @@ const short temptable_2[][2] PROGMEM = { //200k ATC Semitec 204GT-2 //Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf // Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance - {1*OVERSAMPLENR, 848}, - {30*OVERSAMPLENR, 300}, //top rating 300C - {34*OVERSAMPLENR, 290}, - {39*OVERSAMPLENR, 280}, - {46*OVERSAMPLENR, 270}, - {53*OVERSAMPLENR, 260}, - {63*OVERSAMPLENR, 250}, - {74*OVERSAMPLENR, 240}, - {87*OVERSAMPLENR, 230}, - {104*OVERSAMPLENR, 220}, - {124*OVERSAMPLENR, 210}, - {148*OVERSAMPLENR, 200}, - {176*OVERSAMPLENR, 190}, - {211*OVERSAMPLENR, 180}, - {252*OVERSAMPLENR, 170}, - {301*OVERSAMPLENR, 160}, - {357*OVERSAMPLENR, 150}, - {420*OVERSAMPLENR, 140}, - {489*OVERSAMPLENR, 130}, - {562*OVERSAMPLENR, 120}, - {636*OVERSAMPLENR, 110}, - {708*OVERSAMPLENR, 100}, - {775*OVERSAMPLENR, 90}, - {835*OVERSAMPLENR, 80}, - {884*OVERSAMPLENR, 70}, - {924*OVERSAMPLENR, 60}, - {955*OVERSAMPLENR, 50}, - {977*OVERSAMPLENR, 40}, - {993*OVERSAMPLENR, 30}, - {1004*OVERSAMPLENR, 20}, - {1012*OVERSAMPLENR, 10}, - {1016*OVERSAMPLENR, 0}, + {1*OVERSAMPLENR, 848}, + {30*OVERSAMPLENR, 300}, //top rating 300C + {34*OVERSAMPLENR, 290}, + {39*OVERSAMPLENR, 280}, + {46*OVERSAMPLENR, 270}, + {53*OVERSAMPLENR, 260}, + {63*OVERSAMPLENR, 250}, + {74*OVERSAMPLENR, 240}, + {87*OVERSAMPLENR, 230}, + {104*OVERSAMPLENR, 220}, + {124*OVERSAMPLENR, 210}, + {148*OVERSAMPLENR, 200}, + {176*OVERSAMPLENR, 190}, + {211*OVERSAMPLENR, 180}, + {252*OVERSAMPLENR, 170}, + {301*OVERSAMPLENR, 160}, + {357*OVERSAMPLENR, 150}, + {420*OVERSAMPLENR, 140}, + {489*OVERSAMPLENR, 130}, + {562*OVERSAMPLENR, 120}, + {636*OVERSAMPLENR, 110}, + {708*OVERSAMPLENR, 100}, + {775*OVERSAMPLENR, 90}, + {835*OVERSAMPLENR, 80}, + {884*OVERSAMPLENR, 70}, + {924*OVERSAMPLENR, 60}, + {955*OVERSAMPLENR, 50}, + {977*OVERSAMPLENR, 40}, + {993*OVERSAMPLENR, 30}, + {1004*OVERSAMPLENR, 20}, + {1012*OVERSAMPLENR, 10}, + {1016*OVERSAMPLENR, 0}, }; #endif #if (THERMISTORHEATER_0 == 3) || (THERMISTORHEATER_1 == 3) || (THERMISTORHEATER_2 == 3) || (THERMISTORBED == 3) //mendel-parts const short temptable_3[][2] PROGMEM = { - {1*OVERSAMPLENR,864}, - {21*OVERSAMPLENR,300}, - {25*OVERSAMPLENR,290}, - {29*OVERSAMPLENR,280}, - {33*OVERSAMPLENR,270}, - {39*OVERSAMPLENR,260}, - {46*OVERSAMPLENR,250}, - {54*OVERSAMPLENR,240}, - {64*OVERSAMPLENR,230}, - {75*OVERSAMPLENR,220}, - {90*OVERSAMPLENR,210}, - {107*OVERSAMPLENR,200}, - {128*OVERSAMPLENR,190}, - {154*OVERSAMPLENR,180}, - {184*OVERSAMPLENR,170}, - {221*OVERSAMPLENR,160}, - {265*OVERSAMPLENR,150}, - {316*OVERSAMPLENR,140}, - {375*OVERSAMPLENR,130}, - {441*OVERSAMPLENR,120}, - {513*OVERSAMPLENR,110}, - {588*OVERSAMPLENR,100}, - {734*OVERSAMPLENR,80}, - {856*OVERSAMPLENR,60}, - {938*OVERSAMPLENR,40}, - {986*OVERSAMPLENR,20}, - {1008*OVERSAMPLENR,0}, - {1018*OVERSAMPLENR,-20} - }; + {1*OVERSAMPLENR,864}, + {21*OVERSAMPLENR,300}, + {25*OVERSAMPLENR,290}, + {29*OVERSAMPLENR,280}, + {33*OVERSAMPLENR,270}, + {39*OVERSAMPLENR,260}, + {46*OVERSAMPLENR,250}, + {54*OVERSAMPLENR,240}, + {64*OVERSAMPLENR,230}, + {75*OVERSAMPLENR,220}, + {90*OVERSAMPLENR,210}, + {107*OVERSAMPLENR,200}, + {128*OVERSAMPLENR,190}, + {154*OVERSAMPLENR,180}, + {184*OVERSAMPLENR,170}, + {221*OVERSAMPLENR,160}, + {265*OVERSAMPLENR,150}, + {316*OVERSAMPLENR,140}, + {375*OVERSAMPLENR,130}, + {441*OVERSAMPLENR,120}, + {513*OVERSAMPLENR,110}, + {588*OVERSAMPLENR,100}, + {734*OVERSAMPLENR,80}, + {856*OVERSAMPLENR,60}, + {938*OVERSAMPLENR,40}, + {986*OVERSAMPLENR,20}, + {1008*OVERSAMPLENR,0}, + {1018*OVERSAMPLENR,-20} +}; #endif #if (THERMISTORHEATER_0 == 4) || (THERMISTORHEATER_1 == 4) || (THERMISTORHEATER_2 == 4) || (THERMISTORBED == 4) //10k thermistor const short temptable_4[][2] PROGMEM = { - {1*OVERSAMPLENR, 430}, - {54*OVERSAMPLENR, 137}, - {107*OVERSAMPLENR, 107}, - {160*OVERSAMPLENR, 91}, - {213*OVERSAMPLENR, 80}, - {266*OVERSAMPLENR, 71}, - {319*OVERSAMPLENR, 64}, - {372*OVERSAMPLENR, 57}, - {425*OVERSAMPLENR, 51}, - {478*OVERSAMPLENR, 46}, - {531*OVERSAMPLENR, 41}, - {584*OVERSAMPLENR, 35}, - {637*OVERSAMPLENR, 30}, - {690*OVERSAMPLENR, 25}, - {743*OVERSAMPLENR, 20}, - {796*OVERSAMPLENR, 14}, - {849*OVERSAMPLENR, 7}, - {902*OVERSAMPLENR, 0}, - {955*OVERSAMPLENR, -11}, - {1008*OVERSAMPLENR, -35} + {1*OVERSAMPLENR, 430}, + {54*OVERSAMPLENR, 137}, + {107*OVERSAMPLENR, 107}, + {160*OVERSAMPLENR, 91}, + {213*OVERSAMPLENR, 80}, + {266*OVERSAMPLENR, 71}, + {319*OVERSAMPLENR, 64}, + {372*OVERSAMPLENR, 57}, + {425*OVERSAMPLENR, 51}, + {478*OVERSAMPLENR, 46}, + {531*OVERSAMPLENR, 41}, + {584*OVERSAMPLENR, 35}, + {637*OVERSAMPLENR, 30}, + {690*OVERSAMPLENR, 25}, + {743*OVERSAMPLENR, 20}, + {796*OVERSAMPLENR, 14}, + {849*OVERSAMPLENR, 7}, + {902*OVERSAMPLENR, 0}, + {955*OVERSAMPLENR, -11}, + {1008*OVERSAMPLENR, -35} }; #endif @@ -175,144 +175,144 @@ const short temptable_5[][2] PROGMEM = { // ATC Semitec 104GT-2 (Used in ParCan) // Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf // Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance - {1*OVERSAMPLENR, 713}, - {17*OVERSAMPLENR, 300}, //top rating 300C - {20*OVERSAMPLENR, 290}, - {23*OVERSAMPLENR, 280}, - {27*OVERSAMPLENR, 270}, - {31*OVERSAMPLENR, 260}, - {37*OVERSAMPLENR, 250}, - {43*OVERSAMPLENR, 240}, - {51*OVERSAMPLENR, 230}, - {61*OVERSAMPLENR, 220}, - {73*OVERSAMPLENR, 210}, - {87*OVERSAMPLENR, 200}, - {106*OVERSAMPLENR, 190}, - {128*OVERSAMPLENR, 180}, - {155*OVERSAMPLENR, 170}, - {189*OVERSAMPLENR, 160}, - {230*OVERSAMPLENR, 150}, - {278*OVERSAMPLENR, 140}, - {336*OVERSAMPLENR, 130}, - {402*OVERSAMPLENR, 120}, - {476*OVERSAMPLENR, 110}, - {554*OVERSAMPLENR, 100}, - {635*OVERSAMPLENR, 90}, - {713*OVERSAMPLENR, 80}, - {784*OVERSAMPLENR, 70}, - {846*OVERSAMPLENR, 60}, - {897*OVERSAMPLENR, 50}, - {937*OVERSAMPLENR, 40}, - {966*OVERSAMPLENR, 30}, - {986*OVERSAMPLENR, 20}, - {1000*OVERSAMPLENR, 10}, - {1010*OVERSAMPLENR, 0} + {1*OVERSAMPLENR, 713}, + {17*OVERSAMPLENR, 300}, //top rating 300C + {20*OVERSAMPLENR, 290}, + {23*OVERSAMPLENR, 280}, + {27*OVERSAMPLENR, 270}, + {31*OVERSAMPLENR, 260}, + {37*OVERSAMPLENR, 250}, + {43*OVERSAMPLENR, 240}, + {51*OVERSAMPLENR, 230}, + {61*OVERSAMPLENR, 220}, + {73*OVERSAMPLENR, 210}, + {87*OVERSAMPLENR, 200}, + {106*OVERSAMPLENR, 190}, + {128*OVERSAMPLENR, 180}, + {155*OVERSAMPLENR, 170}, + {189*OVERSAMPLENR, 160}, + {230*OVERSAMPLENR, 150}, + {278*OVERSAMPLENR, 140}, + {336*OVERSAMPLENR, 130}, + {402*OVERSAMPLENR, 120}, + {476*OVERSAMPLENR, 110}, + {554*OVERSAMPLENR, 100}, + {635*OVERSAMPLENR, 90}, + {713*OVERSAMPLENR, 80}, + {784*OVERSAMPLENR, 70}, + {846*OVERSAMPLENR, 60}, + {897*OVERSAMPLENR, 50}, + {937*OVERSAMPLENR, 40}, + {966*OVERSAMPLENR, 30}, + {986*OVERSAMPLENR, 20}, + {1000*OVERSAMPLENR, 10}, + {1010*OVERSAMPLENR, 0} }; #endif #if (THERMISTORHEATER_0 == 6) || (THERMISTORHEATER_1 == 6) || (THERMISTORHEATER_2 == 6) || (THERMISTORBED == 6) // 100k Epcos thermistor const short temptable_6[][2] PROGMEM = { - {1*OVERSAMPLENR, 350}, - {28*OVERSAMPLENR, 250}, //top rating 250C - {31*OVERSAMPLENR, 245}, - {35*OVERSAMPLENR, 240}, - {39*OVERSAMPLENR, 235}, - {42*OVERSAMPLENR, 230}, - {44*OVERSAMPLENR, 225}, - {49*OVERSAMPLENR, 220}, - {53*OVERSAMPLENR, 215}, - {62*OVERSAMPLENR, 210}, - {71*OVERSAMPLENR, 205}, //fitted graphically - {78*OVERSAMPLENR, 200}, //fitted graphically - {94*OVERSAMPLENR, 190}, - {102*OVERSAMPLENR, 185}, - {116*OVERSAMPLENR, 170}, - {143*OVERSAMPLENR, 160}, - {183*OVERSAMPLENR, 150}, - {223*OVERSAMPLENR, 140}, - {270*OVERSAMPLENR, 130}, - {318*OVERSAMPLENR, 120}, - {383*OVERSAMPLENR, 110}, - {413*OVERSAMPLENR, 105}, - {439*OVERSAMPLENR, 100}, - {484*OVERSAMPLENR, 95}, - {513*OVERSAMPLENR, 90}, - {607*OVERSAMPLENR, 80}, - {664*OVERSAMPLENR, 70}, - {781*OVERSAMPLENR, 60}, - {810*OVERSAMPLENR, 55}, - {849*OVERSAMPLENR, 50}, - {914*OVERSAMPLENR, 45}, - {914*OVERSAMPLENR, 40}, - {935*OVERSAMPLENR, 35}, - {954*OVERSAMPLENR, 30}, - {970*OVERSAMPLENR, 25}, - {978*OVERSAMPLENR, 22}, - {1008*OVERSAMPLENR, 3}, - {1023*OVERSAMPLENR, 0} //to allow internal 0 degrees C + {1*OVERSAMPLENR, 350}, + {28*OVERSAMPLENR, 250}, //top rating 250C + {31*OVERSAMPLENR, 245}, + {35*OVERSAMPLENR, 240}, + {39*OVERSAMPLENR, 235}, + {42*OVERSAMPLENR, 230}, + {44*OVERSAMPLENR, 225}, + {49*OVERSAMPLENR, 220}, + {53*OVERSAMPLENR, 215}, + {62*OVERSAMPLENR, 210}, + {71*OVERSAMPLENR, 205}, //fitted graphically + {78*OVERSAMPLENR, 200}, //fitted graphically + {94*OVERSAMPLENR, 190}, + {102*OVERSAMPLENR, 185}, + {116*OVERSAMPLENR, 170}, + {143*OVERSAMPLENR, 160}, + {183*OVERSAMPLENR, 150}, + {223*OVERSAMPLENR, 140}, + {270*OVERSAMPLENR, 130}, + {318*OVERSAMPLENR, 120}, + {383*OVERSAMPLENR, 110}, + {413*OVERSAMPLENR, 105}, + {439*OVERSAMPLENR, 100}, + {484*OVERSAMPLENR, 95}, + {513*OVERSAMPLENR, 90}, + {607*OVERSAMPLENR, 80}, + {664*OVERSAMPLENR, 70}, + {781*OVERSAMPLENR, 60}, + {810*OVERSAMPLENR, 55}, + {849*OVERSAMPLENR, 50}, + {914*OVERSAMPLENR, 45}, + {914*OVERSAMPLENR, 40}, + {935*OVERSAMPLENR, 35}, + {954*OVERSAMPLENR, 30}, + {970*OVERSAMPLENR, 25}, + {978*OVERSAMPLENR, 22}, + {1008*OVERSAMPLENR, 3}, + {1023*OVERSAMPLENR, 0} //to allow internal 0 degrees C }; #endif #if (THERMISTORHEATER_0 == 7) || (THERMISTORHEATER_1 == 7) || (THERMISTORHEATER_2 == 7) || (THERMISTORBED == 7) // 100k Honeywell 135-104LAG-J01 const short temptable_7[][2] PROGMEM = { - {1*OVERSAMPLENR, 941}, - {19*OVERSAMPLENR, 362}, - {37*OVERSAMPLENR, 299}, //top rating 300C - {55*OVERSAMPLENR, 266}, - {73*OVERSAMPLENR, 245}, - {91*OVERSAMPLENR, 229}, - {109*OVERSAMPLENR, 216}, - {127*OVERSAMPLENR, 206}, - {145*OVERSAMPLENR, 197}, - {163*OVERSAMPLENR, 190}, - {181*OVERSAMPLENR, 183}, - {199*OVERSAMPLENR, 177}, - {217*OVERSAMPLENR, 171}, - {235*OVERSAMPLENR, 166}, - {253*OVERSAMPLENR, 162}, - {271*OVERSAMPLENR, 157}, - {289*OVERSAMPLENR, 153}, - {307*OVERSAMPLENR, 149}, - {325*OVERSAMPLENR, 146}, - {343*OVERSAMPLENR, 142}, - {361*OVERSAMPLENR, 139}, - {379*OVERSAMPLENR, 135}, - {397*OVERSAMPLENR, 132}, - {415*OVERSAMPLENR, 129}, - {433*OVERSAMPLENR, 126}, - {451*OVERSAMPLENR, 123}, - {469*OVERSAMPLENR, 121}, - {487*OVERSAMPLENR, 118}, - {505*OVERSAMPLENR, 115}, - {523*OVERSAMPLENR, 112}, - {541*OVERSAMPLENR, 110}, - {559*OVERSAMPLENR, 107}, - {577*OVERSAMPLENR, 105}, - {595*OVERSAMPLENR, 102}, - {613*OVERSAMPLENR, 99}, - {631*OVERSAMPLENR, 97}, - {649*OVERSAMPLENR, 94}, - {667*OVERSAMPLENR, 92}, - {685*OVERSAMPLENR, 89}, - {703*OVERSAMPLENR, 86}, - {721*OVERSAMPLENR, 84}, - {739*OVERSAMPLENR, 81}, - {757*OVERSAMPLENR, 78}, - {775*OVERSAMPLENR, 75}, - {793*OVERSAMPLENR, 72}, - {811*OVERSAMPLENR, 69}, - {829*OVERSAMPLENR, 66}, - {847*OVERSAMPLENR, 62}, - {865*OVERSAMPLENR, 59}, - {883*OVERSAMPLENR, 55}, - {901*OVERSAMPLENR, 51}, - {919*OVERSAMPLENR, 46}, - {937*OVERSAMPLENR, 41}, - {955*OVERSAMPLENR, 35}, - {973*OVERSAMPLENR, 27}, - {991*OVERSAMPLENR, 17}, - {1009*OVERSAMPLENR, 1}, - {1023*OVERSAMPLENR, 0} //to allow internal 0 degrees C + {1*OVERSAMPLENR, 941}, + {19*OVERSAMPLENR, 362}, + {37*OVERSAMPLENR, 299}, //top rating 300C + {55*OVERSAMPLENR, 266}, + {73*OVERSAMPLENR, 245}, + {91*OVERSAMPLENR, 229}, + {109*OVERSAMPLENR, 216}, + {127*OVERSAMPLENR, 206}, + {145*OVERSAMPLENR, 197}, + {163*OVERSAMPLENR, 190}, + {181*OVERSAMPLENR, 183}, + {199*OVERSAMPLENR, 177}, + {217*OVERSAMPLENR, 171}, + {235*OVERSAMPLENR, 166}, + {253*OVERSAMPLENR, 162}, + {271*OVERSAMPLENR, 157}, + {289*OVERSAMPLENR, 153}, + {307*OVERSAMPLENR, 149}, + {325*OVERSAMPLENR, 146}, + {343*OVERSAMPLENR, 142}, + {361*OVERSAMPLENR, 139}, + {379*OVERSAMPLENR, 135}, + {397*OVERSAMPLENR, 132}, + {415*OVERSAMPLENR, 129}, + {433*OVERSAMPLENR, 126}, + {451*OVERSAMPLENR, 123}, + {469*OVERSAMPLENR, 121}, + {487*OVERSAMPLENR, 118}, + {505*OVERSAMPLENR, 115}, + {523*OVERSAMPLENR, 112}, + {541*OVERSAMPLENR, 110}, + {559*OVERSAMPLENR, 107}, + {577*OVERSAMPLENR, 105}, + {595*OVERSAMPLENR, 102}, + {613*OVERSAMPLENR, 99}, + {631*OVERSAMPLENR, 97}, + {649*OVERSAMPLENR, 94}, + {667*OVERSAMPLENR, 92}, + {685*OVERSAMPLENR, 89}, + {703*OVERSAMPLENR, 86}, + {721*OVERSAMPLENR, 84}, + {739*OVERSAMPLENR, 81}, + {757*OVERSAMPLENR, 78}, + {775*OVERSAMPLENR, 75}, + {793*OVERSAMPLENR, 72}, + {811*OVERSAMPLENR, 69}, + {829*OVERSAMPLENR, 66}, + {847*OVERSAMPLENR, 62}, + {865*OVERSAMPLENR, 59}, + {883*OVERSAMPLENR, 55}, + {901*OVERSAMPLENR, 51}, + {919*OVERSAMPLENR, 46}, + {937*OVERSAMPLENR, 41}, + {955*OVERSAMPLENR, 35}, + {973*OVERSAMPLENR, 27}, + {991*OVERSAMPLENR, 17}, + {1009*OVERSAMPLENR, 1}, + {1023*OVERSAMPLENR, 0} //to allow internal 0 degrees C }; #endif @@ -323,302 +323,302 @@ const short temptable_7[][2] PROGMEM = { // 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}, + {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 = { - {1*OVERSAMPLENR, 704}, - {54*OVERSAMPLENR, 216}, - {107*OVERSAMPLENR, 175}, - {160*OVERSAMPLENR, 152}, - {213*OVERSAMPLENR, 137}, - {266*OVERSAMPLENR, 125}, - {319*OVERSAMPLENR, 115}, - {372*OVERSAMPLENR, 106}, - {425*OVERSAMPLENR, 99}, - {478*OVERSAMPLENR, 91}, - {531*OVERSAMPLENR, 85}, - {584*OVERSAMPLENR, 78}, - {637*OVERSAMPLENR, 71}, - {690*OVERSAMPLENR, 65}, - {743*OVERSAMPLENR, 58}, - {796*OVERSAMPLENR, 50}, - {849*OVERSAMPLENR, 42}, - {902*OVERSAMPLENR, 31}, - {955*OVERSAMPLENR, 17}, - {1008*OVERSAMPLENR, 0} + {1*OVERSAMPLENR, 704}, + {54*OVERSAMPLENR, 216}, + {107*OVERSAMPLENR, 175}, + {160*OVERSAMPLENR, 152}, + {213*OVERSAMPLENR, 137}, + {266*OVERSAMPLENR, 125}, + {319*OVERSAMPLENR, 115}, + {372*OVERSAMPLENR, 106}, + {425*OVERSAMPLENR, 99}, + {478*OVERSAMPLENR, 91}, + {531*OVERSAMPLENR, 85}, + {584*OVERSAMPLENR, 78}, + {637*OVERSAMPLENR, 71}, + {690*OVERSAMPLENR, 65}, + {743*OVERSAMPLENR, 58}, + {796*OVERSAMPLENR, 50}, + {849*OVERSAMPLENR, 42}, + {902*OVERSAMPLENR, 31}, + {955*OVERSAMPLENR, 17}, + {1008*OVERSAMPLENR, 0} }; #endif #if (THERMISTORHEATER_0 == 9) || (THERMISTORHEATER_1 == 9) || (THERMISTORHEATER_2 == 9) || (THERMISTORBED == 9) // 100k GE Sensing AL03006-58.2K-97-G1 (4.7k pullup) const short temptable_9[][2] PROGMEM = { - {1*OVERSAMPLENR, 936}, - {36*OVERSAMPLENR, 300}, - {71*OVERSAMPLENR, 246}, - {106*OVERSAMPLENR, 218}, - {141*OVERSAMPLENR, 199}, - {176*OVERSAMPLENR, 185}, - {211*OVERSAMPLENR, 173}, - {246*OVERSAMPLENR, 163}, - {281*OVERSAMPLENR, 155}, - {316*OVERSAMPLENR, 147}, - {351*OVERSAMPLENR, 140}, - {386*OVERSAMPLENR, 134}, - {421*OVERSAMPLENR, 128}, - {456*OVERSAMPLENR, 122}, - {491*OVERSAMPLENR, 117}, - {526*OVERSAMPLENR, 112}, - {561*OVERSAMPLENR, 107}, - {596*OVERSAMPLENR, 102}, - {631*OVERSAMPLENR, 97}, - {666*OVERSAMPLENR, 92}, - {701*OVERSAMPLENR, 87}, - {736*OVERSAMPLENR, 81}, - {771*OVERSAMPLENR, 76}, - {806*OVERSAMPLENR, 70}, - {841*OVERSAMPLENR, 63}, - {876*OVERSAMPLENR, 56}, - {911*OVERSAMPLENR, 48}, - {946*OVERSAMPLENR, 38}, - {981*OVERSAMPLENR, 23}, - {1005*OVERSAMPLENR, 5}, - {1016*OVERSAMPLENR, 0} + {1*OVERSAMPLENR, 936}, + {36*OVERSAMPLENR, 300}, + {71*OVERSAMPLENR, 246}, + {106*OVERSAMPLENR, 218}, + {141*OVERSAMPLENR, 199}, + {176*OVERSAMPLENR, 185}, + {211*OVERSAMPLENR, 173}, + {246*OVERSAMPLENR, 163}, + {281*OVERSAMPLENR, 155}, + {316*OVERSAMPLENR, 147}, + {351*OVERSAMPLENR, 140}, + {386*OVERSAMPLENR, 134}, + {421*OVERSAMPLENR, 128}, + {456*OVERSAMPLENR, 122}, + {491*OVERSAMPLENR, 117}, + {526*OVERSAMPLENR, 112}, + {561*OVERSAMPLENR, 107}, + {596*OVERSAMPLENR, 102}, + {631*OVERSAMPLENR, 97}, + {666*OVERSAMPLENR, 92}, + {701*OVERSAMPLENR, 87}, + {736*OVERSAMPLENR, 81}, + {771*OVERSAMPLENR, 76}, + {806*OVERSAMPLENR, 70}, + {841*OVERSAMPLENR, 63}, + {876*OVERSAMPLENR, 56}, + {911*OVERSAMPLENR, 48}, + {946*OVERSAMPLENR, 38}, + {981*OVERSAMPLENR, 23}, + {1005*OVERSAMPLENR, 5}, + {1016*OVERSAMPLENR, 0} }; #endif #if (THERMISTORHEATER_0 == 10) || (THERMISTORHEATER_1 == 10) || (THERMISTORHEATER_2 == 10) || (THERMISTORBED == 10) // 100k RS thermistor 198-961 (4.7k pullup) const short temptable_10[][2] PROGMEM = { - {1*OVERSAMPLENR, 929}, - {36*OVERSAMPLENR, 299}, - {71*OVERSAMPLENR, 246}, - {106*OVERSAMPLENR, 217}, - {141*OVERSAMPLENR, 198}, - {176*OVERSAMPLENR, 184}, - {211*OVERSAMPLENR, 173}, - {246*OVERSAMPLENR, 163}, - {281*OVERSAMPLENR, 154}, - {316*OVERSAMPLENR, 147}, - {351*OVERSAMPLENR, 140}, - {386*OVERSAMPLENR, 134}, - {421*OVERSAMPLENR, 128}, - {456*OVERSAMPLENR, 122}, - {491*OVERSAMPLENR, 117}, - {526*OVERSAMPLENR, 112}, - {561*OVERSAMPLENR, 107}, - {596*OVERSAMPLENR, 102}, - {631*OVERSAMPLENR, 97}, - {666*OVERSAMPLENR, 91}, - {701*OVERSAMPLENR, 86}, - {736*OVERSAMPLENR, 81}, - {771*OVERSAMPLENR, 76}, - {806*OVERSAMPLENR, 70}, - {841*OVERSAMPLENR, 63}, - {876*OVERSAMPLENR, 56}, - {911*OVERSAMPLENR, 48}, - {946*OVERSAMPLENR, 38}, - {981*OVERSAMPLENR, 23}, - {1005*OVERSAMPLENR, 5}, - {1016*OVERSAMPLENR, 0} + {1*OVERSAMPLENR, 929}, + {36*OVERSAMPLENR, 299}, + {71*OVERSAMPLENR, 246}, + {106*OVERSAMPLENR, 217}, + {141*OVERSAMPLENR, 198}, + {176*OVERSAMPLENR, 184}, + {211*OVERSAMPLENR, 173}, + {246*OVERSAMPLENR, 163}, + {281*OVERSAMPLENR, 154}, + {316*OVERSAMPLENR, 147}, + {351*OVERSAMPLENR, 140}, + {386*OVERSAMPLENR, 134}, + {421*OVERSAMPLENR, 128}, + {456*OVERSAMPLENR, 122}, + {491*OVERSAMPLENR, 117}, + {526*OVERSAMPLENR, 112}, + {561*OVERSAMPLENR, 107}, + {596*OVERSAMPLENR, 102}, + {631*OVERSAMPLENR, 97}, + {666*OVERSAMPLENR, 91}, + {701*OVERSAMPLENR, 86}, + {736*OVERSAMPLENR, 81}, + {771*OVERSAMPLENR, 76}, + {806*OVERSAMPLENR, 70}, + {841*OVERSAMPLENR, 63}, + {876*OVERSAMPLENR, 56}, + {911*OVERSAMPLENR, 48}, + {946*OVERSAMPLENR, 38}, + {981*OVERSAMPLENR, 23}, + {1005*OVERSAMPLENR, 5}, + {1016*OVERSAMPLENR, 0} }; #endif -#if (THERMISTORHEATER_0 == 11) || (THERMISTORHEATER_1 == 11) || (THERMISTORHEATER_2 == 11) || (THERMISTORBED == 11) +#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}, - {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} + {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 @@ -626,69 +626,69 @@ const short temptable_11[][2] PROGMEM = { // Hisens thermistor B25/50 =3950 +/-1% const short temptable_13[][2] PROGMEM = { - { 22.5*OVERSAMPLENR, 300 }, -{ 24.125*OVERSAMPLENR, 295 }, -{ 25.875*OVERSAMPLENR, 290 }, -{ 27.8125*OVERSAMPLENR, 285 }, -{ 29.9375*OVERSAMPLENR, 280 }, -{ 32.25*OVERSAMPLENR, 275 }, -{ 34.8125*OVERSAMPLENR, 270 }, -{ 37.625*OVERSAMPLENR, 265 }, -{ 40.6875*OVERSAMPLENR, 260 }, -{ 44.0625*OVERSAMPLENR, 255 }, -{ 47.75*OVERSAMPLENR, 250 }, -{ 51.8125*OVERSAMPLENR, 245 }, -{ 56.3125*OVERSAMPLENR, 240 }, -{ 61.25*OVERSAMPLENR, 235 }, -{ 66.75*OVERSAMPLENR, 230 }, -{ 72.8125*OVERSAMPLENR, 225 }, -{ 79.5*OVERSAMPLENR, 220 }, -{ 87*OVERSAMPLENR, 215 }, -{ 95.3125*OVERSAMPLENR, 210 }, -{ 104.1875*OVERSAMPLENR, 205 }, -{ 112.75*OVERSAMPLENR, 200 }, -{ 123.125*OVERSAMPLENR, 195 }, -{ 135.75*OVERSAMPLENR, 190 }, -{ 148.3125*OVERSAMPLENR, 185 }, -{ 163.8125*OVERSAMPLENR, 180 }, -{ 179*OVERSAMPLENR, 175 }, -{ 211.125*OVERSAMPLENR, 170 }, -{ 216.125*OVERSAMPLENR, 165 }, -{ 236.5625*OVERSAMPLENR, 160 }, -{ 258.5*OVERSAMPLENR, 155 }, -{ 279.875*OVERSAMPLENR, 150 }, -{ 305.375*OVERSAMPLENR, 145 }, -{ 333.25*OVERSAMPLENR, 140 }, -{ 362.5625*OVERSAMPLENR, 135 }, -{ 393.6875*OVERSAMPLENR, 130 }, -{ 425*OVERSAMPLENR, 125 }, -{ 460.625*OVERSAMPLENR, 120 }, -{ 495.1875*OVERSAMPLENR, 115 }, -{ 530.875*OVERSAMPLENR, 110 }, -{ 567.25*OVERSAMPLENR, 105 }, -{ 601.625*OVERSAMPLENR, 100 }, -{ 637.875*OVERSAMPLENR, 95 }, -{ 674.5625*OVERSAMPLENR, 90 }, -{ 710*OVERSAMPLENR, 85 }, -{ 744.125*OVERSAMPLENR, 80 }, -{ 775.9375*OVERSAMPLENR, 75 }, -{ 806.875*OVERSAMPLENR, 70 }, -{ 835.1875*OVERSAMPLENR, 65 }, -{ 861.125*OVERSAMPLENR, 60 }, -{ 884.375*OVERSAMPLENR, 55 }, -{ 904.5625*OVERSAMPLENR, 50 }, -{ 923.8125*OVERSAMPLENR, 45 }, -{ 940.375*OVERSAMPLENR, 40 }, -{ 954.625*OVERSAMPLENR, 35 }, -{ 966.875*OVERSAMPLENR, 30 }, -{ 977.0625*OVERSAMPLENR, 25 }, -{ 986*OVERSAMPLENR, 20 }, -{ 993.375*OVERSAMPLENR, 15 }, -{ 999.5*OVERSAMPLENR, 10 }, -{ 1004.5*OVERSAMPLENR, 5 }, -{ 1008.5*OVERSAMPLENR, 0 } + { 22.5*OVERSAMPLENR, 300 }, + { 24.125*OVERSAMPLENR, 295 }, + { 25.875*OVERSAMPLENR, 290 }, + { 27.8125*OVERSAMPLENR, 285 }, + { 29.9375*OVERSAMPLENR, 280 }, + { 32.25*OVERSAMPLENR, 275 }, + { 34.8125*OVERSAMPLENR, 270 }, + { 37.625*OVERSAMPLENR, 265 }, + { 40.6875*OVERSAMPLENR, 260 }, + { 44.0625*OVERSAMPLENR, 255 }, + { 47.75*OVERSAMPLENR, 250 }, + { 51.8125*OVERSAMPLENR, 245 }, + { 56.3125*OVERSAMPLENR, 240 }, + { 61.25*OVERSAMPLENR, 235 }, + { 66.75*OVERSAMPLENR, 230 }, + { 72.8125*OVERSAMPLENR, 225 }, + { 79.5*OVERSAMPLENR, 220 }, + { 87*OVERSAMPLENR, 215 }, + { 95.3125*OVERSAMPLENR, 210 }, + { 104.1875*OVERSAMPLENR, 205 }, + { 112.75*OVERSAMPLENR, 200 }, + { 123.125*OVERSAMPLENR, 195 }, + { 135.75*OVERSAMPLENR, 190 }, + { 148.3125*OVERSAMPLENR, 185 }, + { 163.8125*OVERSAMPLENR, 180 }, + { 179*OVERSAMPLENR, 175 }, + { 211.125*OVERSAMPLENR, 170 }, + { 216.125*OVERSAMPLENR, 165 }, + { 236.5625*OVERSAMPLENR, 160 }, + { 258.5*OVERSAMPLENR, 155 }, + { 279.875*OVERSAMPLENR, 150 }, + { 305.375*OVERSAMPLENR, 145 }, + { 333.25*OVERSAMPLENR, 140 }, + { 362.5625*OVERSAMPLENR, 135 }, + { 393.6875*OVERSAMPLENR, 130 }, + { 425*OVERSAMPLENR, 125 }, + { 460.625*OVERSAMPLENR, 120 }, + { 495.1875*OVERSAMPLENR, 115 }, + { 530.875*OVERSAMPLENR, 110 }, + { 567.25*OVERSAMPLENR, 105 }, + { 601.625*OVERSAMPLENR, 100 }, + { 637.875*OVERSAMPLENR, 95 }, + { 674.5625*OVERSAMPLENR, 90 }, + { 710*OVERSAMPLENR, 85 }, + { 744.125*OVERSAMPLENR, 80 }, + { 775.9375*OVERSAMPLENR, 75 }, + { 806.875*OVERSAMPLENR, 70 }, + { 835.1875*OVERSAMPLENR, 65 }, + { 861.125*OVERSAMPLENR, 60 }, + { 884.375*OVERSAMPLENR, 55 }, + { 904.5625*OVERSAMPLENR, 50 }, + { 923.8125*OVERSAMPLENR, 45 }, + { 940.375*OVERSAMPLENR, 40 }, + { 954.625*OVERSAMPLENR, 35 }, + { 966.875*OVERSAMPLENR, 30 }, + { 977.0625*OVERSAMPLENR, 25 }, + { 986*OVERSAMPLENR, 20 }, + { 993.375*OVERSAMPLENR, 15 }, + { 999.5*OVERSAMPLENR, 10 }, + { 1004.5*OVERSAMPLENR, 5 }, + { 1008.5*OVERSAMPLENR, 0 } - }; +}; #endif #if (THERMISTORHEATER_0 == 20) || (THERMISTORHEATER_1 == 20) || (THERMISTORHEATER_2 == 20) || (THERMISTORBED == 20) // PT100 with INA826 amp on Ultimaker v2.0 electronics @@ -711,55 +711,55 @@ This does not match the normal thermistor behaviour so we need to set the follow # 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 } + { 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 @@ -769,146 +769,146 @@ const short temptable_20[][2] PROGMEM = { // Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance // Advantage: Twice the resolution and better linearity from 150C to 200C const short temptable_51[][2] PROGMEM = { - {1*OVERSAMPLENR, 350}, - {190*OVERSAMPLENR, 250}, //top rating 250C - {203*OVERSAMPLENR, 245}, - {217*OVERSAMPLENR, 240}, - {232*OVERSAMPLENR, 235}, - {248*OVERSAMPLENR, 230}, - {265*OVERSAMPLENR, 225}, - {283*OVERSAMPLENR, 220}, - {302*OVERSAMPLENR, 215}, - {322*OVERSAMPLENR, 210}, - {344*OVERSAMPLENR, 205}, - {366*OVERSAMPLENR, 200}, - {390*OVERSAMPLENR, 195}, - {415*OVERSAMPLENR, 190}, - {440*OVERSAMPLENR, 185}, - {467*OVERSAMPLENR, 180}, - {494*OVERSAMPLENR, 175}, - {522*OVERSAMPLENR, 170}, - {551*OVERSAMPLENR, 165}, - {580*OVERSAMPLENR, 160}, - {609*OVERSAMPLENR, 155}, - {638*OVERSAMPLENR, 150}, - {666*OVERSAMPLENR, 145}, - {695*OVERSAMPLENR, 140}, - {722*OVERSAMPLENR, 135}, - {749*OVERSAMPLENR, 130}, - {775*OVERSAMPLENR, 125}, - {800*OVERSAMPLENR, 120}, - {823*OVERSAMPLENR, 115}, - {845*OVERSAMPLENR, 110}, - {865*OVERSAMPLENR, 105}, - {884*OVERSAMPLENR, 100}, - {901*OVERSAMPLENR, 95}, - {917*OVERSAMPLENR, 90}, - {932*OVERSAMPLENR, 85}, - {944*OVERSAMPLENR, 80}, - {956*OVERSAMPLENR, 75}, - {966*OVERSAMPLENR, 70}, - {975*OVERSAMPLENR, 65}, - {982*OVERSAMPLENR, 60}, - {989*OVERSAMPLENR, 55}, - {995*OVERSAMPLENR, 50}, - {1000*OVERSAMPLENR, 45}, - {1004*OVERSAMPLENR, 40}, - {1007*OVERSAMPLENR, 35}, - {1010*OVERSAMPLENR, 30}, - {1013*OVERSAMPLENR, 25}, - {1015*OVERSAMPLENR, 20}, - {1017*OVERSAMPLENR, 15}, - {1018*OVERSAMPLENR, 10}, - {1019*OVERSAMPLENR, 5}, - {1020*OVERSAMPLENR, 0}, - {1021*OVERSAMPLENR, -5} + {1*OVERSAMPLENR, 350}, + {190*OVERSAMPLENR, 250}, //top rating 250C + {203*OVERSAMPLENR, 245}, + {217*OVERSAMPLENR, 240}, + {232*OVERSAMPLENR, 235}, + {248*OVERSAMPLENR, 230}, + {265*OVERSAMPLENR, 225}, + {283*OVERSAMPLENR, 220}, + {302*OVERSAMPLENR, 215}, + {322*OVERSAMPLENR, 210}, + {344*OVERSAMPLENR, 205}, + {366*OVERSAMPLENR, 200}, + {390*OVERSAMPLENR, 195}, + {415*OVERSAMPLENR, 190}, + {440*OVERSAMPLENR, 185}, + {467*OVERSAMPLENR, 180}, + {494*OVERSAMPLENR, 175}, + {522*OVERSAMPLENR, 170}, + {551*OVERSAMPLENR, 165}, + {580*OVERSAMPLENR, 160}, + {609*OVERSAMPLENR, 155}, + {638*OVERSAMPLENR, 150}, + {666*OVERSAMPLENR, 145}, + {695*OVERSAMPLENR, 140}, + {722*OVERSAMPLENR, 135}, + {749*OVERSAMPLENR, 130}, + {775*OVERSAMPLENR, 125}, + {800*OVERSAMPLENR, 120}, + {823*OVERSAMPLENR, 115}, + {845*OVERSAMPLENR, 110}, + {865*OVERSAMPLENR, 105}, + {884*OVERSAMPLENR, 100}, + {901*OVERSAMPLENR, 95}, + {917*OVERSAMPLENR, 90}, + {932*OVERSAMPLENR, 85}, + {944*OVERSAMPLENR, 80}, + {956*OVERSAMPLENR, 75}, + {966*OVERSAMPLENR, 70}, + {975*OVERSAMPLENR, 65}, + {982*OVERSAMPLENR, 60}, + {989*OVERSAMPLENR, 55}, + {995*OVERSAMPLENR, 50}, + {1000*OVERSAMPLENR, 45}, + {1004*OVERSAMPLENR, 40}, + {1007*OVERSAMPLENR, 35}, + {1010*OVERSAMPLENR, 30}, + {1013*OVERSAMPLENR, 25}, + {1015*OVERSAMPLENR, 20}, + {1017*OVERSAMPLENR, 15}, + {1018*OVERSAMPLENR, 10}, + {1019*OVERSAMPLENR, 5}, + {1020*OVERSAMPLENR, 0}, + {1021*OVERSAMPLENR, -5} }; #endif -#if (THERMISTORHEATER_0 == 52) || (THERMISTORHEATER_1 == 52) || (THERMISTORHEATER_2 == 52) || (THERMISTORBED == 52) +#if (THERMISTORHEATER_0 == 52) || (THERMISTORHEATER_1 == 52) || (THERMISTORHEATER_2 == 52) || (THERMISTORBED == 52) // 200k ATC Semitec 204GT-2 (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!) // Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf // Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance // Advantage: More resolution and better linearity from 150C to 200C const short temptable_52[][2] PROGMEM = { - {1*OVERSAMPLENR, 500}, - {125*OVERSAMPLENR, 300}, //top rating 300C - {142*OVERSAMPLENR, 290}, - {162*OVERSAMPLENR, 280}, - {185*OVERSAMPLENR, 270}, - {211*OVERSAMPLENR, 260}, - {240*OVERSAMPLENR, 250}, - {274*OVERSAMPLENR, 240}, - {312*OVERSAMPLENR, 230}, - {355*OVERSAMPLENR, 220}, - {401*OVERSAMPLENR, 210}, - {452*OVERSAMPLENR, 200}, - {506*OVERSAMPLENR, 190}, - {563*OVERSAMPLENR, 180}, - {620*OVERSAMPLENR, 170}, - {677*OVERSAMPLENR, 160}, - {732*OVERSAMPLENR, 150}, - {783*OVERSAMPLENR, 140}, - {830*OVERSAMPLENR, 130}, - {871*OVERSAMPLENR, 120}, - {906*OVERSAMPLENR, 110}, - {935*OVERSAMPLENR, 100}, - {958*OVERSAMPLENR, 90}, - {976*OVERSAMPLENR, 80}, - {990*OVERSAMPLENR, 70}, - {1000*OVERSAMPLENR, 60}, - {1008*OVERSAMPLENR, 50}, - {1013*OVERSAMPLENR, 40}, - {1017*OVERSAMPLENR, 30}, - {1019*OVERSAMPLENR, 20}, - {1021*OVERSAMPLENR, 10}, - {1022*OVERSAMPLENR, 0} + {1*OVERSAMPLENR, 500}, + {125*OVERSAMPLENR, 300}, //top rating 300C + {142*OVERSAMPLENR, 290}, + {162*OVERSAMPLENR, 280}, + {185*OVERSAMPLENR, 270}, + {211*OVERSAMPLENR, 260}, + {240*OVERSAMPLENR, 250}, + {274*OVERSAMPLENR, 240}, + {312*OVERSAMPLENR, 230}, + {355*OVERSAMPLENR, 220}, + {401*OVERSAMPLENR, 210}, + {452*OVERSAMPLENR, 200}, + {506*OVERSAMPLENR, 190}, + {563*OVERSAMPLENR, 180}, + {620*OVERSAMPLENR, 170}, + {677*OVERSAMPLENR, 160}, + {732*OVERSAMPLENR, 150}, + {783*OVERSAMPLENR, 140}, + {830*OVERSAMPLENR, 130}, + {871*OVERSAMPLENR, 120}, + {906*OVERSAMPLENR, 110}, + {935*OVERSAMPLENR, 100}, + {958*OVERSAMPLENR, 90}, + {976*OVERSAMPLENR, 80}, + {990*OVERSAMPLENR, 70}, + {1000*OVERSAMPLENR, 60}, + {1008*OVERSAMPLENR, 50}, + {1013*OVERSAMPLENR, 40}, + {1017*OVERSAMPLENR, 30}, + {1019*OVERSAMPLENR, 20}, + {1021*OVERSAMPLENR, 10}, + {1022*OVERSAMPLENR, 0} }; #endif -#if (THERMISTORHEATER_0 == 55) || (THERMISTORHEATER_1 == 55) || (THERMISTORHEATER_2 == 55) || (THERMISTORBED == 55) +#if (THERMISTORHEATER_0 == 55) || (THERMISTORHEATER_1 == 55) || (THERMISTORHEATER_2 == 55) || (THERMISTORBED == 55) // 100k ATC Semitec 104GT-2 (Used on ParCan) (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!) // Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf // Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance // Advantage: More resolution and better linearity from 150C to 200C const short temptable_55[][2] PROGMEM = { - {1*OVERSAMPLENR, 500}, - {76*OVERSAMPLENR, 300}, - {87*OVERSAMPLENR, 290}, - {100*OVERSAMPLENR, 280}, - {114*OVERSAMPLENR, 270}, - {131*OVERSAMPLENR, 260}, - {152*OVERSAMPLENR, 250}, - {175*OVERSAMPLENR, 240}, - {202*OVERSAMPLENR, 230}, - {234*OVERSAMPLENR, 220}, - {271*OVERSAMPLENR, 210}, - {312*OVERSAMPLENR, 200}, - {359*OVERSAMPLENR, 190}, - {411*OVERSAMPLENR, 180}, - {467*OVERSAMPLENR, 170}, - {527*OVERSAMPLENR, 160}, - {590*OVERSAMPLENR, 150}, - {652*OVERSAMPLENR, 140}, - {713*OVERSAMPLENR, 130}, - {770*OVERSAMPLENR, 120}, - {822*OVERSAMPLENR, 110}, - {867*OVERSAMPLENR, 100}, - {905*OVERSAMPLENR, 90}, - {936*OVERSAMPLENR, 80}, - {961*OVERSAMPLENR, 70}, - {979*OVERSAMPLENR, 60}, - {993*OVERSAMPLENR, 50}, - {1003*OVERSAMPLENR, 40}, - {1010*OVERSAMPLENR, 30}, - {1015*OVERSAMPLENR, 20}, - {1018*OVERSAMPLENR, 10}, - {1020*OVERSAMPLENR, 0} + {1*OVERSAMPLENR, 500}, + {76*OVERSAMPLENR, 300}, + {87*OVERSAMPLENR, 290}, + {100*OVERSAMPLENR, 280}, + {114*OVERSAMPLENR, 270}, + {131*OVERSAMPLENR, 260}, + {152*OVERSAMPLENR, 250}, + {175*OVERSAMPLENR, 240}, + {202*OVERSAMPLENR, 230}, + {234*OVERSAMPLENR, 220}, + {271*OVERSAMPLENR, 210}, + {312*OVERSAMPLENR, 200}, + {359*OVERSAMPLENR, 190}, + {411*OVERSAMPLENR, 180}, + {467*OVERSAMPLENR, 170}, + {527*OVERSAMPLENR, 160}, + {590*OVERSAMPLENR, 150}, + {652*OVERSAMPLENR, 140}, + {713*OVERSAMPLENR, 130}, + {770*OVERSAMPLENR, 120}, + {822*OVERSAMPLENR, 110}, + {867*OVERSAMPLENR, 100}, + {905*OVERSAMPLENR, 90}, + {936*OVERSAMPLENR, 80}, + {961*OVERSAMPLENR, 70}, + {979*OVERSAMPLENR, 60}, + {993*OVERSAMPLENR, 50}, + {1003*OVERSAMPLENR, 40}, + {1010*OVERSAMPLENR, 30}, + {1015*OVERSAMPLENR, 20}, + {1018*OVERSAMPLENR, 10}, + {1020*OVERSAMPLENR, 0} }; #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 +// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=3950 // r0: 100000 // t0: 25 // r1: 0 (parallel with rTherm) @@ -917,118 +917,118 @@ const short temptable_55[][2] PROGMEM = { // 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}, - {71*OVERSAMPLENR, 247}, - {81*OVERSAMPLENR, 237}, - {91*OVERSAMPLENR, 229}, - {101*OVERSAMPLENR, 221}, - {131*OVERSAMPLENR, 204}, - {161*OVERSAMPLENR, 190}, - {191*OVERSAMPLENR, 179}, - {231*OVERSAMPLENR, 167}, - {271*OVERSAMPLENR, 157}, - {311*OVERSAMPLENR, 148}, - {351*OVERSAMPLENR, 140}, - {381*OVERSAMPLENR, 135}, - {411*OVERSAMPLENR, 130}, - {441*OVERSAMPLENR, 125}, - {451*OVERSAMPLENR, 123}, - {461*OVERSAMPLENR, 122}, - {471*OVERSAMPLENR, 120}, - {481*OVERSAMPLENR, 119}, - {491*OVERSAMPLENR, 117}, - {501*OVERSAMPLENR, 116}, - {511*OVERSAMPLENR, 114}, - {521*OVERSAMPLENR, 113}, - {531*OVERSAMPLENR, 111}, - {541*OVERSAMPLENR, 110}, - {551*OVERSAMPLENR, 108}, - {561*OVERSAMPLENR, 107}, - {571*OVERSAMPLENR, 105}, - {581*OVERSAMPLENR, 104}, - {591*OVERSAMPLENR, 102}, - {601*OVERSAMPLENR, 101}, - {611*OVERSAMPLENR, 100}, - {621*OVERSAMPLENR, 98}, - {631*OVERSAMPLENR, 97}, - {641*OVERSAMPLENR, 95}, - {651*OVERSAMPLENR, 94}, - {661*OVERSAMPLENR, 92}, - {671*OVERSAMPLENR, 91}, - {681*OVERSAMPLENR, 90}, - {691*OVERSAMPLENR, 88}, - {701*OVERSAMPLENR, 87}, - {711*OVERSAMPLENR, 85}, - {721*OVERSAMPLENR, 84}, - {731*OVERSAMPLENR, 82}, - {741*OVERSAMPLENR, 81}, - {751*OVERSAMPLENR, 79}, - {761*OVERSAMPLENR, 77}, - {771*OVERSAMPLENR, 76}, - {781*OVERSAMPLENR, 74}, - {791*OVERSAMPLENR, 72}, - {801*OVERSAMPLENR, 71}, - {811*OVERSAMPLENR, 69}, - {821*OVERSAMPLENR, 67}, - {831*OVERSAMPLENR, 65}, - {841*OVERSAMPLENR, 63}, - {851*OVERSAMPLENR, 62}, - {861*OVERSAMPLENR, 60}, - {871*OVERSAMPLENR, 57}, - {881*OVERSAMPLENR, 55}, - {891*OVERSAMPLENR, 53}, - {901*OVERSAMPLENR, 51}, - {911*OVERSAMPLENR, 48}, - {921*OVERSAMPLENR, 45}, - {931*OVERSAMPLENR, 42}, - {941*OVERSAMPLENR, 39}, - {951*OVERSAMPLENR, 36}, - {961*OVERSAMPLENR, 32}, - {981*OVERSAMPLENR, 23}, - {991*OVERSAMPLENR, 17}, - {1001*OVERSAMPLENR, 9}, - {1008*OVERSAMPLENR, 0}, + {51*OVERSAMPLENR, 272}, + {61*OVERSAMPLENR, 258}, + {71*OVERSAMPLENR, 247}, + {81*OVERSAMPLENR, 237}, + {91*OVERSAMPLENR, 229}, + {101*OVERSAMPLENR, 221}, + {131*OVERSAMPLENR, 204}, + {161*OVERSAMPLENR, 190}, + {191*OVERSAMPLENR, 179}, + {231*OVERSAMPLENR, 167}, + {271*OVERSAMPLENR, 157}, + {311*OVERSAMPLENR, 148}, + {351*OVERSAMPLENR, 140}, + {381*OVERSAMPLENR, 135}, + {411*OVERSAMPLENR, 130}, + {441*OVERSAMPLENR, 125}, + {451*OVERSAMPLENR, 123}, + {461*OVERSAMPLENR, 122}, + {471*OVERSAMPLENR, 120}, + {481*OVERSAMPLENR, 119}, + {491*OVERSAMPLENR, 117}, + {501*OVERSAMPLENR, 116}, + {511*OVERSAMPLENR, 114}, + {521*OVERSAMPLENR, 113}, + {531*OVERSAMPLENR, 111}, + {541*OVERSAMPLENR, 110}, + {551*OVERSAMPLENR, 108}, + {561*OVERSAMPLENR, 107}, + {571*OVERSAMPLENR, 105}, + {581*OVERSAMPLENR, 104}, + {591*OVERSAMPLENR, 102}, + {601*OVERSAMPLENR, 101}, + {611*OVERSAMPLENR, 100}, + {621*OVERSAMPLENR, 98}, + {631*OVERSAMPLENR, 97}, + {641*OVERSAMPLENR, 95}, + {651*OVERSAMPLENR, 94}, + {661*OVERSAMPLENR, 92}, + {671*OVERSAMPLENR, 91}, + {681*OVERSAMPLENR, 90}, + {691*OVERSAMPLENR, 88}, + {701*OVERSAMPLENR, 87}, + {711*OVERSAMPLENR, 85}, + {721*OVERSAMPLENR, 84}, + {731*OVERSAMPLENR, 82}, + {741*OVERSAMPLENR, 81}, + {751*OVERSAMPLENR, 79}, + {761*OVERSAMPLENR, 77}, + {771*OVERSAMPLENR, 76}, + {781*OVERSAMPLENR, 74}, + {791*OVERSAMPLENR, 72}, + {801*OVERSAMPLENR, 71}, + {811*OVERSAMPLENR, 69}, + {821*OVERSAMPLENR, 67}, + {831*OVERSAMPLENR, 65}, + {841*OVERSAMPLENR, 63}, + {851*OVERSAMPLENR, 62}, + {861*OVERSAMPLENR, 60}, + {871*OVERSAMPLENR, 57}, + {881*OVERSAMPLENR, 55}, + {891*OVERSAMPLENR, 53}, + {901*OVERSAMPLENR, 51}, + {911*OVERSAMPLENR, 48}, + {921*OVERSAMPLENR, 45}, + {931*OVERSAMPLENR, 42}, + {941*OVERSAMPLENR, 39}, + {951*OVERSAMPLENR, 36}, + {961*OVERSAMPLENR, 32}, + {981*OVERSAMPLENR, 23}, + {991*OVERSAMPLENR, 17}, + {1001*OVERSAMPLENR, 9}, + {1008*OVERSAMPLENR, 0}, }; #endif -#if (THERMISTORBED == 12) +#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}, + {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 -// +// // Rt=R0*(1+a*T+b*T*T) [for T>0] // a=3.9083E-3, b=-5.775E-7 @@ -1042,26 +1042,26 @@ const short temptable_12[][2] PROGMEM = { #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) +// 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) +// 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 // E3D Pt100 with 4k7 MiniRambo pullup, no Amp on the MiniRambo v1.3a @@ -1069,146 +1069,146 @@ const short temptable_147[][2] PROGMEM = { const short temptable_148[][2] PROGMEM = { // These values have been calculated and tested over many days. See https://docs.google.com/spreadsheets/d/1MJXa6feEe0mGVCT2TrBwLxVOMoLDkJlvfQ4JXhAdV_E // Values that are missing from the 5C gap are missing due to resolution limits. -{19.00000 * OVERSAMPLENR, 0}, -{19.25000 * OVERSAMPLENR, 5}, -{19.50000 * OVERSAMPLENR, 10}, -{19.87500 * OVERSAMPLENR, 15}, -{20.25000 * OVERSAMPLENR, 20}, -{21.00000 * OVERSAMPLENR, 25}, -{21.75000 * OVERSAMPLENR, 35}, -{22.00000 * OVERSAMPLENR, 40}, -{23.00000 * OVERSAMPLENR, 50}, // 55C is more commonly used. -{23.75000 * OVERSAMPLENR, 60}, -{24.00000 * OVERSAMPLENR, 65}, -{24.06250 * OVERSAMPLENR, 70}, -{25.00000 * OVERSAMPLENR, 75}, -{25.50000 * OVERSAMPLENR, 85}, -{26.00000 * OVERSAMPLENR, 90}, -{26.93750 * OVERSAMPLENR,100}, -{27.00000 * OVERSAMPLENR,105}, -{27.37500 * OVERSAMPLENR,110}, -{28.00000 * OVERSAMPLENR,115}, -{29.00000 * OVERSAMPLENR,125}, -{29.25000 * OVERSAMPLENR,135}, -{30.00000 * OVERSAMPLENR,140}, -{35.50000 * OVERSAMPLENR,150}, -{31.00000 * OVERSAMPLENR,155}, -{32.00000 * OVERSAMPLENR,165}, -{32.18750 * OVERSAMPLENR,175}, -{33.00000 * OVERSAMPLENR,180}, -{33.62500 * OVERSAMPLENR,190}, -{34.00000 * OVERSAMPLENR,195}, -{35.00000 * OVERSAMPLENR,205}, -{35.50000 * OVERSAMPLENR,215}, -{36.00000 * OVERSAMPLENR,220}, -{36.75000 * OVERSAMPLENR,230}, -{37.00000 * OVERSAMPLENR,235}, -{37.75000 * OVERSAMPLENR,245}, -{38.00000 * OVERSAMPLENR,250}, -{38.12500 * OVERSAMPLENR,255}, -{39.00000 * OVERSAMPLENR,260}, -{40.00000 * OVERSAMPLENR,275}, -{40.25000 * OVERSAMPLENR,285}, -{41.00000 * OVERSAMPLENR,290}, -{41.25000 * OVERSAMPLENR,300}, -{42.00000 * OVERSAMPLENR,305}, -{43.00000 * OVERSAMPLENR,315}, -{43.25000 * OVERSAMPLENR,325}, -{44.00000 * OVERSAMPLENR,330}, -{44.18750 * OVERSAMPLENR,340}, -{45.00000 * OVERSAMPLENR,345}, -{45.25000 * OVERSAMPLENR,355}, -{46.00000 * OVERSAMPLENR,360}, -{46.62500 * OVERSAMPLENR,370}, -{47.00000 * OVERSAMPLENR,375}, -{47.25000 * OVERSAMPLENR,385}, -{48.00000 * OVERSAMPLENR,390}, -{48.75000 * OVERSAMPLENR,400}, -{49.00000 * OVERSAMPLENR,405}, + {19.00000 * OVERSAMPLENR, 0}, + {19.25000 * OVERSAMPLENR, 5}, + {19.50000 * OVERSAMPLENR, 10}, + {19.87500 * OVERSAMPLENR, 15}, + {20.25000 * OVERSAMPLENR, 20}, + {21.00000 * OVERSAMPLENR, 25}, + {21.75000 * OVERSAMPLENR, 35}, + {22.00000 * OVERSAMPLENR, 40}, + {23.00000 * OVERSAMPLENR, 50}, // 55C is more commonly used. + {23.75000 * OVERSAMPLENR, 60}, + {24.00000 * OVERSAMPLENR, 65}, + {24.06250 * OVERSAMPLENR, 70}, + {25.00000 * OVERSAMPLENR, 75}, + {25.50000 * OVERSAMPLENR, 85}, + {26.00000 * OVERSAMPLENR, 90}, + {26.93750 * OVERSAMPLENR,100}, + {27.00000 * OVERSAMPLENR,105}, + {27.37500 * OVERSAMPLENR,110}, + {28.00000 * OVERSAMPLENR,115}, + {29.00000 * OVERSAMPLENR,125}, + {29.25000 * OVERSAMPLENR,135}, + {30.00000 * OVERSAMPLENR,140}, + {35.50000 * OVERSAMPLENR,150}, + {31.00000 * OVERSAMPLENR,155}, + {32.00000 * OVERSAMPLENR,165}, + {32.18750 * OVERSAMPLENR,175}, + {33.00000 * OVERSAMPLENR,180}, + {33.62500 * OVERSAMPLENR,190}, + {34.00000 * OVERSAMPLENR,195}, + {35.00000 * OVERSAMPLENR,205}, + {35.50000 * OVERSAMPLENR,215}, + {36.00000 * OVERSAMPLENR,220}, + {36.75000 * OVERSAMPLENR,230}, + {37.00000 * OVERSAMPLENR,235}, + {37.75000 * OVERSAMPLENR,245}, + {38.00000 * OVERSAMPLENR,250}, + {38.12500 * OVERSAMPLENR,255}, + {39.00000 * OVERSAMPLENR,260}, + {40.00000 * OVERSAMPLENR,275}, + {40.25000 * OVERSAMPLENR,285}, + {41.00000 * OVERSAMPLENR,290}, + {41.25000 * OVERSAMPLENR,300}, + {42.00000 * OVERSAMPLENR,305}, + {43.00000 * OVERSAMPLENR,315}, + {43.25000 * OVERSAMPLENR,325}, + {44.00000 * OVERSAMPLENR,330}, + {44.18750 * OVERSAMPLENR,340}, + {45.00000 * OVERSAMPLENR,345}, + {45.25000 * OVERSAMPLENR,355}, + {46.00000 * OVERSAMPLENR,360}, + {46.62500 * OVERSAMPLENR,370}, + {47.00000 * OVERSAMPLENR,375}, + {47.25000 * OVERSAMPLENR,385}, + {48.00000 * OVERSAMPLENR,390}, + {48.75000 * OVERSAMPLENR,400}, + {49.00000 * OVERSAMPLENR,405}, }; #endif #if (THERMISTORHEATER_0 == 247) || (THERMISTORHEATER_1 == 247) || (THERMISTORHEATER_2 == 247) || (THERMISTORBED == 247) // Pt100 with 4k7 MiniRambo pullup & PT100 Amplifier const short temptable_247[][2] PROGMEM = { // Calculated from Bob-the-Kuhn's PT100 calculator listed in https://github.com/MarlinFirmware/Marlin/issues/5543 // and the table provided by E3D at http://wiki.e3d-online.com/wiki/E3D_PT100_Amplifier_Documentation#Output_Characteristics. -{ 0 * OVERSAMPLENR, 0}, -{241 * OVERSAMPLENR, 1}, -{249 * OVERSAMPLENR, 10}, -{259 * OVERSAMPLENR, 20}, -{267 * OVERSAMPLENR, 30}, -{275 * OVERSAMPLENR, 40}, -{283 * OVERSAMPLENR, 50}, -{291 * OVERSAMPLENR, 60}, -{299 * OVERSAMPLENR, 70}, -{307 * OVERSAMPLENR, 80}, -{315 * OVERSAMPLENR, 90}, -{323 * OVERSAMPLENR, 100}, -{331 * OVERSAMPLENR, 110}, -{340 * OVERSAMPLENR, 120}, -{348 * OVERSAMPLENR, 130}, -{354 * OVERSAMPLENR, 140}, -{362 * OVERSAMPLENR, 150}, -{370 * OVERSAMPLENR, 160}, -{378 * OVERSAMPLENR, 170}, -{386 * OVERSAMPLENR, 180}, -{394 * OVERSAMPLENR, 190}, -{402 * OVERSAMPLENR, 200}, -{410 * OVERSAMPLENR, 210}, -{418 * OVERSAMPLENR, 220}, -{426 * OVERSAMPLENR, 230}, -{432 * OVERSAMPLENR, 240}, -{440 * OVERSAMPLENR, 250}, -{448 * OVERSAMPLENR, 260}, -{454 * OVERSAMPLENR, 270}, -{462 * OVERSAMPLENR, 280}, -{469 * OVERSAMPLENR, 290}, -{475 * OVERSAMPLENR, 300}, -{483 * OVERSAMPLENR, 310}, -{491 * OVERSAMPLENR, 320}, -{499 * OVERSAMPLENR, 330}, -{505 * OVERSAMPLENR, 340}, -{513 * OVERSAMPLENR, 350}, -{519 * OVERSAMPLENR, 360}, -{527 * OVERSAMPLENR, 370}, -{533 * OVERSAMPLENR, 380}, -{541 * OVERSAMPLENR, 390}, -{549 * OVERSAMPLENR, 400}, -{616 * OVERSAMPLENR, 500}, -{682 * OVERSAMPLENR, 600}, -{741 * OVERSAMPLENR, 700}, -{801 * OVERSAMPLENR, 800}, -{856 * OVERSAMPLENR, 900}, -{910 * OVERSAMPLENR, 1000}, -{960 * OVERSAMPLENR, 1100}, + { 0 * OVERSAMPLENR, 0}, + {241 * OVERSAMPLENR, 1}, + {249 * OVERSAMPLENR, 10}, + {259 * OVERSAMPLENR, 20}, + {267 * OVERSAMPLENR, 30}, + {275 * OVERSAMPLENR, 40}, + {283 * OVERSAMPLENR, 50}, + {291 * OVERSAMPLENR, 60}, + {299 * OVERSAMPLENR, 70}, + {307 * OVERSAMPLENR, 80}, + {315 * OVERSAMPLENR, 90}, + {323 * OVERSAMPLENR, 100}, + {331 * OVERSAMPLENR, 110}, + {340 * OVERSAMPLENR, 120}, + {348 * OVERSAMPLENR, 130}, + {354 * OVERSAMPLENR, 140}, + {362 * OVERSAMPLENR, 150}, + {370 * OVERSAMPLENR, 160}, + {378 * OVERSAMPLENR, 170}, + {386 * OVERSAMPLENR, 180}, + {394 * OVERSAMPLENR, 190}, + {402 * OVERSAMPLENR, 200}, + {410 * OVERSAMPLENR, 210}, + {418 * OVERSAMPLENR, 220}, + {426 * OVERSAMPLENR, 230}, + {432 * OVERSAMPLENR, 240}, + {440 * OVERSAMPLENR, 250}, + {448 * OVERSAMPLENR, 260}, + {454 * OVERSAMPLENR, 270}, + {462 * OVERSAMPLENR, 280}, + {469 * OVERSAMPLENR, 290}, + {475 * OVERSAMPLENR, 300}, + {483 * OVERSAMPLENR, 310}, + {491 * OVERSAMPLENR, 320}, + {499 * OVERSAMPLENR, 330}, + {505 * OVERSAMPLENR, 340}, + {513 * OVERSAMPLENR, 350}, + {519 * OVERSAMPLENR, 360}, + {527 * OVERSAMPLENR, 370}, + {533 * OVERSAMPLENR, 380}, + {541 * OVERSAMPLENR, 390}, + {549 * OVERSAMPLENR, 400}, + {616 * OVERSAMPLENR, 500}, + {682 * OVERSAMPLENR, 600}, + {741 * OVERSAMPLENR, 700}, + {801 * OVERSAMPLENR, 800}, + {856 * OVERSAMPLENR, 900}, + {910 * OVERSAMPLENR, 1000}, + {960 * OVERSAMPLENR, 1100}, }; #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) + 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) +// 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 @@ -1216,74 +1216,74 @@ const short temptable_1047[][2] PROGMEM = { const short temptable_2000[][2] PROGMEM = { // Source: https://product.tdk.com/info/en/catalog/datasheets/503021/tpd_ntc-thermistor_ntcg_en.pdf // Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance -/*{305*OVERSAMPLENR, 125}, -{338*OVERSAMPLENR, 120}, -{374*OVERSAMPLENR, 115}, -{412*OVERSAMPLENR, 110}, -{452*OVERSAMPLENR, 105}, -{494*OVERSAMPLENR, 100}, -{536*OVERSAMPLENR, 95}, -{580*OVERSAMPLENR, 90}, -{623*OVERSAMPLENR, 85}, -{665*OVERSAMPLENR, 80}, -{706*OVERSAMPLENR, 75}, -{744*OVERSAMPLENR, 70}, -{780*OVERSAMPLENR, 65}, -{813*OVERSAMPLENR, 60}, -{843*OVERSAMPLENR, 55}, -{869*OVERSAMPLENR, 50}, -{892*OVERSAMPLENR, 45}, -{912*OVERSAMPLENR, 40}, -{929*OVERSAMPLENR, 35}, -{943*OVERSAMPLENR, 30}, -{955*OVERSAMPLENR, 25}, -{965*OVERSAMPLENR, 20}, -{973*OVERSAMPLENR, 15}, -{979*OVERSAMPLENR, 10}, -{984*OVERSAMPLENR, 5}, -{988*OVERSAMPLENR, 0}, -{991*OVERSAMPLENR, -5}, -{993*OVERSAMPLENR, -10}, -{995*OVERSAMPLENR, -15}, -{996*OVERSAMPLENR, -20}, -{997*OVERSAMPLENR, -25}, -{998*OVERSAMPLENR, -30}, -{999*OVERSAMPLENR, -35}, -{999*OVERSAMPLENR, -40},*/ -{313*OVERSAMPLENR,125}, -{347*OVERSAMPLENR,120}, -{383*OVERSAMPLENR,115}, -{422*OVERSAMPLENR,110}, -{463*OVERSAMPLENR,105}, -{506*OVERSAMPLENR,100}, -{549*OVERSAMPLENR,95}, -{594*OVERSAMPLENR,90}, -{638*OVERSAMPLENR,85}, -{681*OVERSAMPLENR,80}, -{722*OVERSAMPLENR,75}, -{762*OVERSAMPLENR,70}, -{799*OVERSAMPLENR,65}, -{833*OVERSAMPLENR,60}, -{863*OVERSAMPLENR,55}, -{890*OVERSAMPLENR,50}, -{914*OVERSAMPLENR,45}, -{934*OVERSAMPLENR,40}, -{951*OVERSAMPLENR,35}, -{966*OVERSAMPLENR,30}, -{978*OVERSAMPLENR,25}, -{988*OVERSAMPLENR,20}, -{996*OVERSAMPLENR,15}, -{1002*OVERSAMPLENR,10}, -{1007*OVERSAMPLENR,5}, -{1012*OVERSAMPLENR,0}, -{1015*OVERSAMPLENR,-5}, -{1017*OVERSAMPLENR,-10}, -{1019*OVERSAMPLENR,-15}, -{1020*OVERSAMPLENR,-20}, -{1021*OVERSAMPLENR,-25}, -{1022*OVERSAMPLENR,-30}, -{1023*OVERSAMPLENR,-35}, -{1023*OVERSAMPLENR,-40}, + /*{305*OVERSAMPLENR, 125}, + {338*OVERSAMPLENR, 120}, + {374*OVERSAMPLENR, 115}, + {412*OVERSAMPLENR, 110}, + {452*OVERSAMPLENR, 105}, + {494*OVERSAMPLENR, 100}, + {536*OVERSAMPLENR, 95}, + {580*OVERSAMPLENR, 90}, + {623*OVERSAMPLENR, 85}, + {665*OVERSAMPLENR, 80}, + {706*OVERSAMPLENR, 75}, + {744*OVERSAMPLENR, 70}, + {780*OVERSAMPLENR, 65}, + {813*OVERSAMPLENR, 60}, + {843*OVERSAMPLENR, 55}, + {869*OVERSAMPLENR, 50}, + {892*OVERSAMPLENR, 45}, + {912*OVERSAMPLENR, 40}, + {929*OVERSAMPLENR, 35}, + {943*OVERSAMPLENR, 30}, + {955*OVERSAMPLENR, 25}, + {965*OVERSAMPLENR, 20}, + {973*OVERSAMPLENR, 15}, + {979*OVERSAMPLENR, 10}, + {984*OVERSAMPLENR, 5}, + {988*OVERSAMPLENR, 0}, + {991*OVERSAMPLENR, -5}, + {993*OVERSAMPLENR, -10}, + {995*OVERSAMPLENR, -15}, + {996*OVERSAMPLENR, -20}, + {997*OVERSAMPLENR, -25}, + {998*OVERSAMPLENR, -30}, + {999*OVERSAMPLENR, -35}, + {999*OVERSAMPLENR, -40},*/ + {313*OVERSAMPLENR,125}, + {347*OVERSAMPLENR,120}, + {383*OVERSAMPLENR,115}, + {422*OVERSAMPLENR,110}, + {463*OVERSAMPLENR,105}, + {506*OVERSAMPLENR,100}, + {549*OVERSAMPLENR,95}, + {594*OVERSAMPLENR,90}, + {638*OVERSAMPLENR,85}, + {681*OVERSAMPLENR,80}, + {722*OVERSAMPLENR,75}, + {762*OVERSAMPLENR,70}, + {799*OVERSAMPLENR,65}, + {833*OVERSAMPLENR,60}, + {863*OVERSAMPLENR,55}, + {890*OVERSAMPLENR,50}, + {914*OVERSAMPLENR,45}, + {934*OVERSAMPLENR,40}, + {951*OVERSAMPLENR,35}, + {966*OVERSAMPLENR,30}, + {978*OVERSAMPLENR,25}, + {988*OVERSAMPLENR,20}, + {996*OVERSAMPLENR,15}, + {1002*OVERSAMPLENR,10}, + {1007*OVERSAMPLENR,5}, + {1012*OVERSAMPLENR,0}, + {1015*OVERSAMPLENR,-5}, + {1017*OVERSAMPLENR,-10}, + {1019*OVERSAMPLENR,-15}, + {1020*OVERSAMPLENR,-20}, + {1021*OVERSAMPLENR,-25}, + {1022*OVERSAMPLENR,-30}, + {1023*OVERSAMPLENR,-35}, + {1023*OVERSAMPLENR,-40}, }; #endif diff --git a/Firmware/tmc2130.cpp b/Firmware/tmc2130.cpp index 8020559cf4..7b26cc2d07 100755 --- a/Firmware/tmc2130.cpp +++ b/Firmware/tmc2130.cpp @@ -55,10 +55,10 @@ uint8_t tmc2130_home_fsteps[2] = {48, 48}; uint8_t tmc2130_wave_fac[4] = {0, 0, 0, 0}; tmc2130_chopper_config_t tmc2130_chopper_config[4] = { - {TMC2130_TOFF_XYZ, 5, 1, 2, 0}, - {TMC2130_TOFF_XYZ, 5, 1, 2, 0}, - {TMC2130_TOFF_XYZ, 5, 1, 2, 0}, - {TMC2130_TOFF_E, 5, 1, 2, 0} + {TMC2130_TOFF_XYZ, 5, 1, 2, 0}, + {TMC2130_TOFF_XYZ, 5, 1, 2, 0}, + {TMC2130_TOFF_XYZ, 5, 1, 2, 0}, + {TMC2130_TOFF_E, 5, 1, 2, 0} }; bool tmc2130_sg_stop_on_crash = true; @@ -134,487 +134,506 @@ void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_ uint16_t __tcoolthrs(uint8_t axis) { - switch (axis) - { - case X_AXIS: return TMC2130_TCOOLTHRS_X; - case Y_AXIS: return TMC2130_TCOOLTHRS_Y; - case Z_AXIS: return TMC2130_TCOOLTHRS_Z; - } - return 0; + switch (axis) + { + case X_AXIS: + return TMC2130_TCOOLTHRS_X; + case Y_AXIS: + return TMC2130_TCOOLTHRS_Y; + case Z_AXIS: + return TMC2130_TCOOLTHRS_Z; + } + return 0; } void tmc2130_init() { // DBG(_n("tmc2130_init(), mode=%S\n"), tmc2130_mode?_n("STEALTH"):_n("NORMAL")); - WRITE(X_TMC2130_CS, HIGH); - WRITE(Y_TMC2130_CS, HIGH); - WRITE(Z_TMC2130_CS, HIGH); - WRITE(E0_TMC2130_CS, HIGH); - SET_OUTPUT(X_TMC2130_CS); - SET_OUTPUT(Y_TMC2130_CS); - SET_OUTPUT(Z_TMC2130_CS); - SET_OUTPUT(E0_TMC2130_CS); - SET_INPUT(X_TMC2130_DIAG); - SET_INPUT(Y_TMC2130_DIAG); - SET_INPUT(Z_TMC2130_DIAG); - SET_INPUT(E0_TMC2130_DIAG); - for (int axis = 0; axis < 2; axis++) // X Y axes - { - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); - tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000); - tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); - tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, (tmc2130_mode == TMC2130_MODE_SILENT)?0:__tcoolthrs(axis)); - tmc2130_wr(axis, TMC2130_REG_GCONF, (tmc2130_mode == TMC2130_MODE_SILENT)?TMC2130_GCONF_SILENT:TMC2130_GCONF_SGSENS); - tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); - tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS); - //tmc2130_wr_THIGH(axis, TMC2130_THIGH); - } - for (int axis = 2; axis < 3; axis++) // Z axis - { - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); - tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000); + WRITE(X_TMC2130_CS, HIGH); + WRITE(Y_TMC2130_CS, HIGH); + WRITE(Z_TMC2130_CS, HIGH); + WRITE(E0_TMC2130_CS, HIGH); + SET_OUTPUT(X_TMC2130_CS); + SET_OUTPUT(Y_TMC2130_CS); + SET_OUTPUT(Z_TMC2130_CS); + SET_OUTPUT(E0_TMC2130_CS); + SET_INPUT(X_TMC2130_DIAG); + SET_INPUT(Y_TMC2130_DIAG); + SET_INPUT(Z_TMC2130_DIAG); + SET_INPUT(E0_TMC2130_DIAG); + for (int axis = 0; axis < 2; axis++) // X Y axes + { + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000); + tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); + tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, (tmc2130_mode == TMC2130_MODE_SILENT)?0:__tcoolthrs(axis)); + tmc2130_wr(axis, TMC2130_REG_GCONF, (tmc2130_mode == TMC2130_MODE_SILENT)?TMC2130_GCONF_SILENT:TMC2130_GCONF_SGSENS); + tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); + tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS); + //tmc2130_wr_THIGH(axis, TMC2130_THIGH); + } + for (int axis = 2; axis < 3; axis++) // Z axis + { + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000); #ifndef TMC2130_STEALTH_Z - tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); + tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); #else //TMC2130_STEALTH_Z - tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); - tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, (tmc2130_mode == TMC2130_MODE_SILENT)?0:__tcoolthrs(axis)); - tmc2130_wr(axis, TMC2130_REG_GCONF, (tmc2130_mode == TMC2130_MODE_SILENT)?TMC2130_GCONF_SILENT:TMC2130_GCONF_SGSENS); - tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); - tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS); + tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); + tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, (tmc2130_mode == TMC2130_MODE_SILENT)?0:__tcoolthrs(axis)); + tmc2130_wr(axis, TMC2130_REG_GCONF, (tmc2130_mode == TMC2130_MODE_SILENT)?TMC2130_GCONF_SILENT:TMC2130_GCONF_SGSENS); + tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); + tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS); #endif //TMC2130_STEALTH_Z - } - for (int axis = 3; axis < 4; axis++) // E axis - { - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); - tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000); + } + for (int axis = 3; axis < 4; axis++) // E axis + { + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_wr(axis, TMC2130_REG_TPOWERDOWN, 0x00000000); #ifndef TMC2130_STEALTH_E - tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); + tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); #else //TMC2130_STEALTH_E - tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); - tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, 0); - tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SILENT); - tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); - tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS); + tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); + tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, 0); + tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SILENT); + tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); + tmc2130_wr_TPWMTHRS(axis, TMC2130_TPWMTHRS); #endif //TMC2130_STEALTH_E - } + } - tmc2130_sg_err[0] = 0; - tmc2130_sg_err[1] = 0; - tmc2130_sg_err[2] = 0; - tmc2130_sg_err[3] = 0; - tmc2130_sg_cnt[0] = 0; - tmc2130_sg_cnt[1] = 0; - tmc2130_sg_cnt[2] = 0; - tmc2130_sg_cnt[3] = 0; + tmc2130_sg_err[0] = 0; + tmc2130_sg_err[1] = 0; + tmc2130_sg_err[2] = 0; + tmc2130_sg_err[3] = 0; + tmc2130_sg_cnt[0] = 0; + tmc2130_sg_cnt[1] = 0; + tmc2130_sg_cnt[2] = 0; + tmc2130_sg_cnt[3] = 0; #ifdef TMC2130_LINEARITY_CORRECTION #ifdef TMC2130_LINEARITY_CORRECTION_XYZ - tmc2130_set_wave(X_AXIS, 247, tmc2130_wave_fac[X_AXIS]); - tmc2130_set_wave(Y_AXIS, 247, tmc2130_wave_fac[Y_AXIS]); - tmc2130_set_wave(Z_AXIS, 247, tmc2130_wave_fac[Z_AXIS]); + tmc2130_set_wave(X_AXIS, 247, tmc2130_wave_fac[X_AXIS]); + tmc2130_set_wave(Y_AXIS, 247, tmc2130_wave_fac[Y_AXIS]); + tmc2130_set_wave(Z_AXIS, 247, tmc2130_wave_fac[Z_AXIS]); #endif //TMC2130_LINEARITY_CORRECTION_XYZ - tmc2130_set_wave(E_AXIS, 247, tmc2130_wave_fac[E_AXIS]); + tmc2130_set_wave(E_AXIS, 247, tmc2130_wave_fac[E_AXIS]); #endif //TMC2130_LINEARITY_CORRECTION } uint8_t tmc2130_sample_diag() { - uint8_t mask = 0; - if (READ(X_TMC2130_DIAG)) mask |= X_AXIS_MASK; - if (READ(Y_TMC2130_DIAG)) mask |= Y_AXIS_MASK; + uint8_t mask = 0; + if (READ(X_TMC2130_DIAG)) mask |= X_AXIS_MASK; + if (READ(Y_TMC2130_DIAG)) mask |= Y_AXIS_MASK; // if (READ(Z_TMC2130_DIAG)) mask |= Z_AXIS_MASK; // if (READ(E0_TMC2130_DIAG)) mask |= E_AXIS_MASK; - return mask; + return mask; } extern bool is_usb_printing; void tmc2130_st_isr() { - if (tmc2130_mode == TMC2130_MODE_SILENT || tmc2130_sg_stop_on_crash == false) return; - uint8_t crash = 0; - uint8_t diag_mask = tmc2130_sample_diag(); + if (tmc2130_mode == TMC2130_MODE_SILENT || tmc2130_sg_stop_on_crash == false) return; + uint8_t crash = 0; + uint8_t diag_mask = tmc2130_sample_diag(); // for (uint8_t axis = X_AXIS; axis <= E_AXIS; axis++) - for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) - { - uint8_t mask = (X_AXIS_MASK << axis); - if (diag_mask & mask) tmc2130_sg_err[axis]++; - else - if (tmc2130_sg_err[axis] > 0) tmc2130_sg_err[axis]--; - if (tmc2130_sg_cnt[axis] < tmc2130_sg_err[axis]) - { - tmc2130_sg_cnt[axis] = tmc2130_sg_err[axis]; - tmc2130_sg_change = true; - uint8_t sg_thr = 64; + for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) + { + uint8_t mask = (X_AXIS_MASK << axis); + if (diag_mask & mask) tmc2130_sg_err[axis]++; + else if (tmc2130_sg_err[axis] > 0) tmc2130_sg_err[axis]--; + if (tmc2130_sg_cnt[axis] < tmc2130_sg_err[axis]) + { + tmc2130_sg_cnt[axis] = tmc2130_sg_err[axis]; + tmc2130_sg_change = true; + uint8_t sg_thr = 64; // if (axis == Y_AXIS) sg_thr = 64; - if (tmc2130_sg_err[axis] >= sg_thr) - { - tmc2130_sg_err[axis] = 0; - crash |= mask; - } - } - } - if (tmc2130_sg_homing_axes_mask == 0) - { - if (tmc2130_sg_stop_on_crash && crash) - { - tmc2130_sg_crash = crash; - tmc2130_sg_stop_on_crash = false; - crashdet_stop_and_save_print(); - } - } + if (tmc2130_sg_err[axis] >= sg_thr) + { + tmc2130_sg_err[axis] = 0; + crash |= mask; + } + } + } + if (tmc2130_sg_homing_axes_mask == 0) + { + if (tmc2130_sg_stop_on_crash && crash) + { + tmc2130_sg_crash = crash; + tmc2130_sg_stop_on_crash = false; + crashdet_stop_and_save_print(); + } + } } bool tmc2130_update_sg() { - if (tmc2130_sg_meassure <= E_AXIS) - { - uint32_t val32 = 0; - tmc2130_rd(tmc2130_sg_meassure, TMC2130_REG_DRV_STATUS, &val32); - tmc2130_sg_meassure_val += (val32 & 0x3ff); - tmc2130_sg_meassure_cnt++; - return true; - } - return false; + if (tmc2130_sg_meassure <= E_AXIS) + { + uint32_t val32 = 0; + tmc2130_rd(tmc2130_sg_meassure, TMC2130_REG_DRV_STATUS, &val32); + tmc2130_sg_meassure_val += (val32 & 0x3ff); + tmc2130_sg_meassure_cnt++; + return true; + } + return false; } void tmc2130_home_enter(uint8_t axes_mask) { - printf_P(PSTR("tmc2130_home_enter(axes_mask=0x%02x)\n"), axes_mask); + printf_P(PSTR("tmc2130_home_enter(axes_mask=0x%02x)\n"), axes_mask); #ifdef TMC2130_SG_HOMING - if (axes_mask & 0x03) //X or Y - tmc2130_wait_standstill_xy(1000); - for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) //X Y and Z axes - { - uint8_t mask = (X_AXIS_MASK << axis); - if (axes_mask & mask) - { - tmc2130_sg_homing_axes_mask |= mask; - //Configuration to spreadCycle - tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_NORMAL); - tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr_home[axis]) << 16)); + if (axes_mask & 0x03) //X or Y + tmc2130_wait_standstill_xy(1000); + for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) //X Y and Z axes + { + uint8_t mask = (X_AXIS_MASK << axis); + if (axes_mask & mask) + { + tmc2130_sg_homing_axes_mask |= mask; + //Configuration to spreadCycle + tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_NORMAL); + tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr_home[axis]) << 16)); // tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16) | ((uint32_t)1 << 24)); - tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, __tcoolthrs(axis)); - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r_home[axis]); - if (mask & (X_AXIS_MASK | Y_AXIS_MASK | Z_AXIS_MASK)) - tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); //stallguard output DIAG1, DIAG1 = pushpull - } - } + tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, __tcoolthrs(axis)); + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r_home[axis]); + if (mask & (X_AXIS_MASK | Y_AXIS_MASK | Z_AXIS_MASK)) + tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); //stallguard output DIAG1, DIAG1 = pushpull + } + } #endif //TMC2130_SG_HOMING } void tmc2130_home_exit() { - printf_P(PSTR("tmc2130_home_exit tmc2130_sg_homing_axes_mask=0x%02x\n"), tmc2130_sg_homing_axes_mask); + printf_P(PSTR("tmc2130_home_exit tmc2130_sg_homing_axes_mask=0x%02x\n"), tmc2130_sg_homing_axes_mask); #ifdef TMC2130_SG_HOMING - if (tmc2130_sg_homing_axes_mask & 0x03) //X or Y - tmc2130_wait_standstill_xy(1000); - if (tmc2130_sg_homing_axes_mask) - { - for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) //X Y and Z axes - { - uint8_t mask = (X_AXIS_MASK << axis); - if (tmc2130_sg_homing_axes_mask & mask & (X_AXIS_MASK | Y_AXIS_MASK | Z_AXIS_MASK)) - { + if (tmc2130_sg_homing_axes_mask & 0x03) //X or Y + tmc2130_wait_standstill_xy(1000); + if (tmc2130_sg_homing_axes_mask) + { + for (uint8_t axis = X_AXIS; axis <= Z_AXIS; axis++) //X Y and Z axes + { + uint8_t mask = (X_AXIS_MASK << axis); + if (tmc2130_sg_homing_axes_mask & mask & (X_AXIS_MASK | Y_AXIS_MASK | Z_AXIS_MASK)) + { #ifndef TMC2130_STEALTH_Z - if ((tmc2130_mode == TMC2130_MODE_SILENT) && (axis != Z_AXIS)) + if ((tmc2130_mode == TMC2130_MODE_SILENT) && (axis != Z_AXIS)) #else //TMC2130_STEALTH_Z - if (tmc2130_mode == TMC2130_MODE_SILENT) + if (tmc2130_mode == TMC2130_MODE_SILENT) #endif //TMC2130_STEALTH_Z - { - tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SILENT); // Configuration back to stealthChop - tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, 0); + { + tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SILENT); // Configuration back to stealthChop + tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, 0); // tmc2130_wr_PWMCONF(i, tmc2130_pwm_ampl[i], tmc2130_pwm_grad[i], tmc2130_pwm_freq[i], tmc2130_pwm_auto[i], 0, 0); - } - else - { + } + else + { // tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_NORMAL); - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); // tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16) | ((uint32_t)1 << 24)); - tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); - tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, __tcoolthrs(axis)); - tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); - } - } - } - tmc2130_sg_homing_axes_mask = 0x00; - } - tmc2130_sg_crash = false; + tmc2130_wr(axis, TMC2130_REG_COOLCONF, (((uint32_t)tmc2130_sg_thr[axis]) << 16)); + tmc2130_wr(axis, TMC2130_REG_TCOOLTHRS, __tcoolthrs(axis)); + tmc2130_wr(axis, TMC2130_REG_GCONF, TMC2130_GCONF_SGSENS); + } + } + } + tmc2130_sg_homing_axes_mask = 0x00; + } + tmc2130_sg_crash = false; #endif } void tmc2130_sg_meassure_start(uint8_t axis) { - tmc2130_sg_meassure = axis; - tmc2130_sg_meassure_cnt = 0; - tmc2130_sg_meassure_val = 0; + tmc2130_sg_meassure = axis; + tmc2130_sg_meassure_cnt = 0; + tmc2130_sg_meassure_val = 0; } uint16_t tmc2130_sg_meassure_stop() { - tmc2130_sg_meassure = 0xff; - return tmc2130_sg_meassure_val / tmc2130_sg_meassure_cnt; + tmc2130_sg_meassure = 0xff; + return tmc2130_sg_meassure_val / tmc2130_sg_meassure_cnt; } bool tmc2130_wait_standstill_xy(int timeout) { // DBG(_n("tmc2130_wait_standstill_xy(timeout=%d)\n"), timeout); - bool standstill = false; - while (!standstill && (timeout > 0)) - { - uint32_t drv_status_x = 0; - uint32_t drv_status_y = 0; - tmc2130_rd(X_AXIS, TMC2130_REG_DRV_STATUS, &drv_status_x); - tmc2130_rd(Y_AXIS, TMC2130_REG_DRV_STATUS, &drv_status_y); + bool standstill = false; + while (!standstill && (timeout > 0)) + { + uint32_t drv_status_x = 0; + uint32_t drv_status_y = 0; + tmc2130_rd(X_AXIS, TMC2130_REG_DRV_STATUS, &drv_status_x); + tmc2130_rd(Y_AXIS, TMC2130_REG_DRV_STATUS, &drv_status_y); // DBG(_n("\tdrv_status_x=0x%08x drv_status_x=0x%08x\n"), drv_status_x, drv_status_y); - standstill = (drv_status_x & 0x80000000) && (drv_status_y & 0x80000000); - tmc2130_check_overtemp(); - timeout--; - } - return standstill; + standstill = (drv_status_x & 0x80000000) && (drv_status_y & 0x80000000); + tmc2130_check_overtemp(); + timeout--; + } + return standstill; } void tmc2130_check_overtemp() { - static uint32_t checktime = 0; - if (millis() - checktime > 1000 ) - { - for (int i = 0; i < 4; i++) - { - uint32_t drv_status = 0; - skip_debug_msg = true; - tmc2130_rd(i, TMC2130_REG_DRV_STATUS, &drv_status); - if (drv_status & ((uint32_t)1 << 26)) - { // BIT 26 - over temp prewarning ~120C (+-20C) - SERIAL_ERRORRPGM(MSG_TMC_OVERTEMP); - SERIAL_ECHOLN(i); - for (int j = 0; j < 4; j++) - tmc2130_wr(j, TMC2130_REG_CHOPCONF, 0x00010000); - kill(MSG_TMC_OVERTEMP); - } - - } - checktime = millis(); - tmc2130_sg_change = true; - } + static uint32_t checktime = 0; + if (millis() - checktime > 1000 ) + { + for (int i = 0; i < 4; i++) + { + uint32_t drv_status = 0; + skip_debug_msg = true; + tmc2130_rd(i, TMC2130_REG_DRV_STATUS, &drv_status); + if (drv_status & ((uint32_t)1 << 26)) + { // BIT 26 - over temp prewarning ~120C (+-20C) + SERIAL_ERRORRPGM(MSG_TMC_OVERTEMP); + SERIAL_ECHOLN(i); + for (int j = 0; j < 4; j++) + tmc2130_wr(j, TMC2130_REG_CHOPCONF, 0x00010000); + kill(MSG_TMC_OVERTEMP); + } + + } + checktime = millis(); + tmc2130_sg_change = true; + } #ifdef DEBUG_CRASHDET_COUNTERS - if (tmc2130_sg_change) - { - for (int i = 0; i < 4; i++) - { - tmc2130_sg_change = false; - lcd_set_cursor(0 + i*4, 3); - lcd_print(itostr3(tmc2130_sg_cnt[i])); - lcd_print(' '); - } - } + if (tmc2130_sg_change) + { + for (int i = 0; i < 4; i++) + { + tmc2130_sg_change = false; + lcd_set_cursor(0 + i*4, 3); + lcd_print(itostr3(tmc2130_sg_cnt[i])); + lcd_print(' '); + } + } #endif //DEBUG_CRASHDET_COUNTERS } void tmc2130_setup_chopper(uint8_t axis, uint8_t mres, uint8_t current_h, uint8_t current_r) { - uint8_t intpol = 1; - uint8_t toff = tmc2130_chopper_config[axis].toff; // toff = 3 (fchop = 27.778kHz) - uint8_t hstrt = tmc2130_chopper_config[axis].hstr; //initial 4, modified to 5 - uint8_t hend = tmc2130_chopper_config[axis].hend; //original value = 1 - uint8_t fd3 = 0; - uint8_t rndtf = 0; //random off time - uint8_t chm = 0; //spreadCycle - uint8_t tbl = tmc2130_chopper_config[axis].tbl; //blanking time, original value = 2 - if (axis == E_AXIS) - { + uint8_t intpol = 1; + uint8_t toff = tmc2130_chopper_config[axis].toff; // toff = 3 (fchop = 27.778kHz) + uint8_t hstrt = tmc2130_chopper_config[axis].hstr; //initial 4, modified to 5 + uint8_t hend = tmc2130_chopper_config[axis].hend; //original value = 1 + uint8_t fd3 = 0; + uint8_t rndtf = 0; //random off time + uint8_t chm = 0; //spreadCycle + uint8_t tbl = tmc2130_chopper_config[axis].tbl; //blanking time, original value = 2 + if (axis == E_AXIS) + { #ifdef TMC2130_CNSTOFF_E - // fd = 0 (slow decay only) - hstrt = 0; //fd0..2 - fd3 = 0; //fd3 - hend = 0; //sine wave offset - chm = 1; // constant off time mod + // fd = 0 (slow decay only) + hstrt = 0; //fd0..2 + fd3 = 0; //fd3 + hend = 0; //sine wave offset + chm = 1; // constant off time mod #endif //TMC2130_CNSTOFF_E // toff = TMC2130_TOFF_E; // toff = 3-5 // rndtf = 1; - } + } // DBG(_n("tmc2130_setup_chopper(axis=%hhd, mres=%hhd, curh=%hhd, curr=%hhd\n"), axis, mres, current_h, current_r); // DBG(_n(" toff=%hhd, hstr=%hhd, hend=%hhd, tbl=%hhd\n"), toff, hstrt, hend, tbl); - if (current_r <= 31) - { - tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 1, 0, 0, 0, mres, intpol, 0, 0); - tmc2130_wr(axis, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((current_r & 0x1f) << 8) | (current_h & 0x1f)); - } - else - { - tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 0, 0, 0, 0, mres, intpol, 0, 0); - tmc2130_wr(axis, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | (((current_r >> 1) & 0x1f) << 8) | ((current_h >> 1) & 0x1f)); - } + if (current_r <= 31) + { + tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 1, 0, 0, 0, mres, intpol, 0, 0); + tmc2130_wr(axis, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | ((current_r & 0x1f) << 8) | (current_h & 0x1f)); + } + else + { + tmc2130_wr_CHOPCONF(axis, toff, hstrt, hend, fd3, 0, rndtf, chm, tbl, 0, 0, 0, 0, mres, intpol, 0, 0); + tmc2130_wr(axis, TMC2130_REG_IHOLD_IRUN, 0x000f0000 | (((current_r >> 1) & 0x1f) << 8) | ((current_h >> 1) & 0x1f)); + } } void tmc2130_set_current_h(uint8_t axis, uint8_t current) { // DBG(_n("tmc2130_set_current_h(axis=%d, current=%d\n"), axis, current); - tmc2130_current_h[axis] = current; - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_current_h[axis] = current; + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); } void tmc2130_set_current_r(uint8_t axis, uint8_t current) { // DBG(_n("tmc2130_set_current_r(axis=%d, current=%d\n"), axis, current); - tmc2130_current_r[axis] = current; - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_current_r[axis] = current; + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); } void tmc2130_print_currents() { - printf_P(_n("tmc2130_print_currents()\n\tH\tR\nX\t%d\t%d\nY\t%d\t%d\nZ\t%d\t%d\nE\t%d\t%d\n"), - tmc2130_current_h[0], tmc2130_current_r[0], - tmc2130_current_h[1], tmc2130_current_r[1], - tmc2130_current_h[2], tmc2130_current_r[2], - tmc2130_current_h[3], tmc2130_current_r[3] - ); + printf_P(_n("tmc2130_print_currents()\n\tH\tR\nX\t%d\t%d\nY\t%d\t%d\nZ\t%d\t%d\nE\t%d\t%d\n"), + tmc2130_current_h[0], tmc2130_current_r[0], + tmc2130_current_h[1], tmc2130_current_r[1], + tmc2130_current_h[2], tmc2130_current_r[2], + tmc2130_current_h[3], tmc2130_current_r[3] + ); } void tmc2130_set_pwm_ampl(uint8_t axis, uint8_t pwm_ampl) { // DBG(_n("tmc2130_set_pwm_ampl(axis=%hhd, pwm_ampl=%hhd\n"), axis, pwm_ampl); - tmc2130_pwm_ampl[axis] = pwm_ampl; - if (((axis == 0) || (axis == 1)) && (tmc2130_mode == TMC2130_MODE_SILENT)) - tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); + tmc2130_pwm_ampl[axis] = pwm_ampl; + if (((axis == 0) || (axis == 1)) && (tmc2130_mode == TMC2130_MODE_SILENT)) + tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); } void tmc2130_set_pwm_grad(uint8_t axis, uint8_t pwm_grad) { // DBG(_n("tmc2130_set_pwm_grad(axis=%hhd, pwm_grad=%hhd\n"), axis, pwm_grad); - tmc2130_pwm_grad[axis] = pwm_grad; - if (((axis == 0) || (axis == 1)) && (tmc2130_mode == TMC2130_MODE_SILENT)) - tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); + tmc2130_pwm_grad[axis] = pwm_grad; + if (((axis == 0) || (axis == 1)) && (tmc2130_mode == TMC2130_MODE_SILENT)) + tmc2130_wr_PWMCONF(axis, tmc2130_pwm_ampl[axis], tmc2130_pwm_grad[axis], tmc2130_pwm_freq[axis], tmc2130_pwm_auto[axis], 0, 0); } uint16_t tmc2130_rd_TSTEP(uint8_t axis) { - uint32_t val32 = 0; - tmc2130_rd(axis, TMC2130_REG_TSTEP, &val32); - if (val32 & 0x000f0000) return 0xffff; - return val32 & 0xffff; + uint32_t val32 = 0; + tmc2130_rd(axis, TMC2130_REG_TSTEP, &val32); + if (val32 & 0x000f0000) return 0xffff; + return val32 & 0xffff; } uint16_t tmc2130_rd_MSCNT(uint8_t axis) { - uint32_t val32 = 0; - tmc2130_rd(axis, TMC2130_REG_MSCNT, &val32); - return val32 & 0x3ff; + uint32_t val32 = 0; + tmc2130_rd(axis, TMC2130_REG_MSCNT, &val32); + return val32 & 0x3ff; } uint32_t tmc2130_rd_MSCURACT(uint8_t axis) { - uint32_t val32 = 0; - tmc2130_rd(axis, TMC2130_REG_MSCURACT, &val32); - return val32; + uint32_t val32 = 0; + tmc2130_rd(axis, TMC2130_REG_MSCURACT, &val32); + return val32; } void tmc2130_wr_MSLUTSTART(uint8_t axis, uint8_t start_sin, uint8_t start_sin90) { - uint32_t val = 0; - val |= (uint32_t)start_sin; - val |= ((uint32_t)start_sin90) << 16; - tmc2130_wr(axis, TMC2130_REG_MSLUTSTART, val); - //printf_P(PSTR("MSLUTSTART=%08lx (start_sin=%d start_sin90=%d)\n"), val, start_sin, start_sin90); + uint32_t val = 0; + val |= (uint32_t)start_sin; + val |= ((uint32_t)start_sin90) << 16; + tmc2130_wr(axis, TMC2130_REG_MSLUTSTART, val); + //printf_P(PSTR("MSLUTSTART=%08lx (start_sin=%d start_sin90=%d)\n"), val, start_sin, start_sin90); } void tmc2130_wr_MSLUTSEL(uint8_t axis, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t w0, uint8_t w1, uint8_t w2, uint8_t w3) { - uint32_t val = 0; - val |= ((uint32_t)w0); - val |= ((uint32_t)w1) << 2; - val |= ((uint32_t)w2) << 4; - val |= ((uint32_t)w3) << 6; - val |= ((uint32_t)x1) << 8; - val |= ((uint32_t)x2) << 16; - val |= ((uint32_t)x3) << 24; - tmc2130_wr(axis, TMC2130_REG_MSLUTSEL, val); - //printf_P(PSTR("MSLUTSEL=%08lx (x1=%d x2=%d x3=%d w0=%d w1=%d w2=%d w3=%d)\n"), val, x1, x2, x3, w0, w1, w2, w3); + uint32_t val = 0; + val |= ((uint32_t)w0); + val |= ((uint32_t)w1) << 2; + val |= ((uint32_t)w2) << 4; + val |= ((uint32_t)w3) << 6; + val |= ((uint32_t)x1) << 8; + val |= ((uint32_t)x2) << 16; + val |= ((uint32_t)x3) << 24; + tmc2130_wr(axis, TMC2130_REG_MSLUTSEL, val); + //printf_P(PSTR("MSLUTSEL=%08lx (x1=%d x2=%d x3=%d w0=%d w1=%d w2=%d w3=%d)\n"), val, x1, x2, x3, w0, w1, w2, w3); } void tmc2130_wr_MSLUT(uint8_t axis, uint8_t i, uint32_t val) { - tmc2130_wr(axis, TMC2130_REG_MSLUT0 + (i & 7), val); - //printf_P(PSTR("MSLUT[%d]=%08lx\n"), i, val); + tmc2130_wr(axis, TMC2130_REG_MSLUT0 + (i & 7), val); + //printf_P(PSTR("MSLUT[%d]=%08lx\n"), i, val); } void tmc2130_wr_CHOPCONF(uint8_t axis, uint8_t toff, uint8_t hstrt, uint8_t hend, uint8_t fd3, uint8_t disfdcc, uint8_t rndtf, uint8_t chm, uint8_t tbl, uint8_t vsense, uint8_t vhighfs, uint8_t vhighchm, uint8_t sync, uint8_t mres, uint8_t intpol, uint8_t dedge, uint8_t diss2g) { - uint32_t val = 0; - val |= (uint32_t)(toff & 15); - val |= (uint32_t)(hstrt & 7) << 4; - val |= (uint32_t)(hend & 15) << 7; - val |= (uint32_t)(fd3 & 1) << 11; - val |= (uint32_t)(disfdcc & 1) << 12; - val |= (uint32_t)(rndtf & 1) << 13; - val |= (uint32_t)(chm & 1) << 14; - val |= (uint32_t)(tbl & 3) << 15; - val |= (uint32_t)(vsense & 1) << 17; - val |= (uint32_t)(vhighfs & 1) << 18; - val |= (uint32_t)(vhighchm & 1) << 19; - val |= (uint32_t)(sync & 15) << 20; - val |= (uint32_t)(mres & 15) << 24; - val |= (uint32_t)(intpol & 1) << 28; - val |= (uint32_t)(dedge & 1) << 29; - val |= (uint32_t)(diss2g & 1) << 30; - tmc2130_wr(axis, TMC2130_REG_CHOPCONF, val); + uint32_t val = 0; + val |= (uint32_t)(toff & 15); + val |= (uint32_t)(hstrt & 7) << 4; + val |= (uint32_t)(hend & 15) << 7; + val |= (uint32_t)(fd3 & 1) << 11; + val |= (uint32_t)(disfdcc & 1) << 12; + val |= (uint32_t)(rndtf & 1) << 13; + val |= (uint32_t)(chm & 1) << 14; + val |= (uint32_t)(tbl & 3) << 15; + val |= (uint32_t)(vsense & 1) << 17; + val |= (uint32_t)(vhighfs & 1) << 18; + val |= (uint32_t)(vhighchm & 1) << 19; + val |= (uint32_t)(sync & 15) << 20; + val |= (uint32_t)(mres & 15) << 24; + val |= (uint32_t)(intpol & 1) << 28; + val |= (uint32_t)(dedge & 1) << 29; + val |= (uint32_t)(diss2g & 1) << 30; + tmc2130_wr(axis, TMC2130_REG_CHOPCONF, val); } //void tmc2130_wr_PWMCONF(uint8_t axis, uint8_t PWMautoScale, uint8_t PWMfreq, uint8_t PWMgrad, uint8_t PWMampl) void tmc2130_wr_PWMCONF(uint8_t axis, uint8_t pwm_ampl, uint8_t pwm_grad, uint8_t pwm_freq, uint8_t pwm_auto, uint8_t pwm_symm, uint8_t freewheel) { - uint32_t val = 0; - val |= (uint32_t)(pwm_ampl & 255); - val |= (uint32_t)(pwm_grad & 255) << 8; - val |= (uint32_t)(pwm_freq & 3) << 16; - val |= (uint32_t)(pwm_auto & 1) << 18; - val |= (uint32_t)(pwm_symm & 1) << 19; - val |= (uint32_t)(freewheel & 3) << 20; - tmc2130_wr(axis, TMC2130_REG_PWMCONF, val); + uint32_t val = 0; + val |= (uint32_t)(pwm_ampl & 255); + val |= (uint32_t)(pwm_grad & 255) << 8; + val |= (uint32_t)(pwm_freq & 3) << 16; + val |= (uint32_t)(pwm_auto & 1) << 18; + val |= (uint32_t)(pwm_symm & 1) << 19; + val |= (uint32_t)(freewheel & 3) << 20; + tmc2130_wr(axis, TMC2130_REG_PWMCONF, val); // tmc2130_wr(axis, TMC2130_REG_PWMCONF, ((uint32_t)(PWMautoScale+PWMfreq) << 16) | ((uint32_t)PWMgrad << 8) | PWMampl); // TMC LJ -> For better readability changed to 0x00 and added PWMautoScale and PWMfreq } void tmc2130_wr_TPWMTHRS(uint8_t axis, uint32_t val32) { - tmc2130_wr(axis, TMC2130_REG_TPWMTHRS, val32); + tmc2130_wr(axis, TMC2130_REG_TPWMTHRS, val32); } void tmc2130_wr_THIGH(uint8_t axis, uint32_t val32) { - tmc2130_wr(axis, TMC2130_REG_THIGH, val32); + tmc2130_wr(axis, TMC2130_REG_THIGH, val32); } uint8_t tmc2130_usteps2mres(uint16_t usteps) { - uint8_t mres = 8; while (mres && (usteps >>= 1)) mres--; - return mres; + uint8_t mres = 8; + while (mres && (usteps >>= 1)) mres--; + return mres; } inline void tmc2130_cs_low(uint8_t axis) { - switch (axis) - { - case X_AXIS: WRITE(X_TMC2130_CS, LOW); break; - case Y_AXIS: WRITE(Y_TMC2130_CS, LOW); break; - case Z_AXIS: WRITE(Z_TMC2130_CS, LOW); break; - case E_AXIS: WRITE(E0_TMC2130_CS, LOW); break; - } + switch (axis) + { + case X_AXIS: + WRITE(X_TMC2130_CS, LOW); + break; + case Y_AXIS: + WRITE(Y_TMC2130_CS, LOW); + break; + case Z_AXIS: + WRITE(Z_TMC2130_CS, LOW); + break; + case E_AXIS: + WRITE(E0_TMC2130_CS, LOW); + break; + } } inline void tmc2130_cs_high(uint8_t axis) { - switch (axis) - { - case X_AXIS: WRITE(X_TMC2130_CS, HIGH); break; - case Y_AXIS: WRITE(Y_TMC2130_CS, HIGH); break; - case Z_AXIS: WRITE(Z_TMC2130_CS, HIGH); break; - case E_AXIS: WRITE(E0_TMC2130_CS, HIGH); break; - } + switch (axis) + { + case X_AXIS: + WRITE(X_TMC2130_CS, HIGH); + break; + case Y_AXIS: + WRITE(Y_TMC2130_CS, HIGH); + break; + case Z_AXIS: + WRITE(Z_TMC2130_CS, HIGH); + break; + case E_AXIS: + WRITE(E0_TMC2130_CS, HIGH); + break; + } } //spi @@ -624,43 +643,43 @@ inline void tmc2130_cs_high(uint8_t axis) static void tmc2130_tx(uint8_t axis, uint8_t addr, uint32_t wval) { - //datagram1 - request - TMC2130_SPI_ENTER(); - tmc2130_cs_low(axis); - TMC2130_SPI_TXRX(addr); // address - TMC2130_SPI_TXRX((wval >> 24) & 0xff); // MSB - TMC2130_SPI_TXRX((wval >> 16) & 0xff); - TMC2130_SPI_TXRX((wval >> 8) & 0xff); - TMC2130_SPI_TXRX(wval & 0xff); // LSB - tmc2130_cs_high(axis); - TMC2130_SPI_LEAVE(); + //datagram1 - request + TMC2130_SPI_ENTER(); + tmc2130_cs_low(axis); + TMC2130_SPI_TXRX(addr); // address + TMC2130_SPI_TXRX((wval >> 24) & 0xff); // MSB + TMC2130_SPI_TXRX((wval >> 16) & 0xff); + TMC2130_SPI_TXRX((wval >> 8) & 0xff); + TMC2130_SPI_TXRX(wval & 0xff); // LSB + tmc2130_cs_high(axis); + TMC2130_SPI_LEAVE(); } static uint8_t tmc2130_rx(uint8_t axis, uint8_t addr, uint32_t* rval) { - //datagram1 - request - TMC2130_SPI_ENTER(); - tmc2130_cs_low(axis); - TMC2130_SPI_TXRX(addr); // address - TMC2130_SPI_TXRX(0); // MSB - TMC2130_SPI_TXRX(0); - TMC2130_SPI_TXRX(0); - TMC2130_SPI_TXRX(0); // LSB - tmc2130_cs_high(axis); - TMC2130_SPI_LEAVE(); - //datagram2 - response - TMC2130_SPI_ENTER(); - tmc2130_cs_low(axis); - uint8_t stat = TMC2130_SPI_TXRX(0); // status - uint32_t val32 = 0; - val32 = TMC2130_SPI_TXRX(0); // MSB - val32 = (val32 << 8) | TMC2130_SPI_TXRX(0); - val32 = (val32 << 8) | TMC2130_SPI_TXRX(0); - val32 = (val32 << 8) | TMC2130_SPI_TXRX(0); // LSB - tmc2130_cs_high(axis); - TMC2130_SPI_LEAVE(); - if (rval != 0) *rval = val32; - return stat; + //datagram1 - request + TMC2130_SPI_ENTER(); + tmc2130_cs_low(axis); + TMC2130_SPI_TXRX(addr); // address + TMC2130_SPI_TXRX(0); // MSB + TMC2130_SPI_TXRX(0); + TMC2130_SPI_TXRX(0); + TMC2130_SPI_TXRX(0); // LSB + tmc2130_cs_high(axis); + TMC2130_SPI_LEAVE(); + //datagram2 - response + TMC2130_SPI_ENTER(); + tmc2130_cs_low(axis); + uint8_t stat = TMC2130_SPI_TXRX(0); // status + uint32_t val32 = 0; + val32 = TMC2130_SPI_TXRX(0); // MSB + val32 = (val32 << 8) | TMC2130_SPI_TXRX(0); + val32 = (val32 << 8) | TMC2130_SPI_TXRX(0); + val32 = (val32 << 8) | TMC2130_SPI_TXRX(0); // LSB + tmc2130_cs_high(axis); + TMC2130_SPI_LEAVE(); + if (rval != 0) *rval = val32; + return stat; } #define _GET_PWR_X (READ(X_ENABLE_PIN) == X_ENABLE_ON) @@ -691,157 +710,194 @@ static uint8_t tmc2130_rx(uint8_t axis, uint8_t addr, uint32_t* rval) uint16_t tmc2130_get_res(uint8_t axis) { - return tmc2130_mres2usteps(tmc2130_mres[axis]); + return tmc2130_mres2usteps(tmc2130_mres[axis]); } void tmc2130_set_res(uint8_t axis, uint16_t res) { - tmc2130_mres[axis] = tmc2130_usteps2mres(res); + tmc2130_mres[axis] = tmc2130_usteps2mres(res); // uint32_t u = micros(); - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); // u = micros() - u; // printf_P(PSTR("tmc2130_setup_chopper %c %lu us"), "XYZE"[axis], u); } uint8_t tmc2130_get_pwr(uint8_t axis) { - switch (axis) - { - case X_AXIS: return _GET_PWR_X; - case Y_AXIS: return _GET_PWR_Y; - case Z_AXIS: return _GET_PWR_Z; - case E_AXIS: return _GET_PWR_E; - } - return 0; + switch (axis) + { + case X_AXIS: + return _GET_PWR_X; + case Y_AXIS: + return _GET_PWR_Y; + case Z_AXIS: + return _GET_PWR_Z; + case E_AXIS: + return _GET_PWR_E; + } + return 0; } void tmc2130_set_pwr(uint8_t axis, uint8_t pwr) { - switch (axis) - { - case X_AXIS: _SET_PWR_X(pwr); break; - case Y_AXIS: _SET_PWR_Y(pwr); break; - case Z_AXIS: _SET_PWR_Z(pwr); break; - case E_AXIS: _SET_PWR_E(pwr); break; - } + switch (axis) + { + case X_AXIS: + _SET_PWR_X(pwr); + break; + case Y_AXIS: + _SET_PWR_Y(pwr); + break; + case Z_AXIS: + _SET_PWR_Z(pwr); + break; + case E_AXIS: + _SET_PWR_E(pwr); + break; + } } uint8_t tmc2130_get_inv(uint8_t axis) { - switch (axis) - { - case X_AXIS: return INVERT_X_DIR; - case Y_AXIS: return INVERT_Y_DIR; - case Z_AXIS: return INVERT_Z_DIR; - case E_AXIS: return INVERT_E0_DIR; - } - return 0; + switch (axis) + { + case X_AXIS: + return INVERT_X_DIR; + case Y_AXIS: + return INVERT_Y_DIR; + case Z_AXIS: + return INVERT_Z_DIR; + case E_AXIS: + return INVERT_E0_DIR; + } + return 0; } uint8_t tmc2130_get_dir(uint8_t axis) { - switch (axis) - { - case X_AXIS: return _GET_DIR_X; - case Y_AXIS: return _GET_DIR_Y; - case Z_AXIS: return _GET_DIR_Z; - case E_AXIS: return _GET_DIR_E; - } - return 0; + switch (axis) + { + case X_AXIS: + return _GET_DIR_X; + case Y_AXIS: + return _GET_DIR_Y; + case Z_AXIS: + return _GET_DIR_Z; + case E_AXIS: + return _GET_DIR_E; + } + return 0; } void tmc2130_set_dir(uint8_t axis, uint8_t dir) { - switch (axis) - { - case X_AXIS: _SET_DIR_X(dir); break; - case Y_AXIS: _SET_DIR_Y(dir); break; - case Z_AXIS: _SET_DIR_Z(dir); break; - case E_AXIS: _SET_DIR_E(dir); break; - } + switch (axis) + { + case X_AXIS: + _SET_DIR_X(dir); + break; + case Y_AXIS: + _SET_DIR_Y(dir); + break; + case Z_AXIS: + _SET_DIR_Z(dir); + break; + case E_AXIS: + _SET_DIR_E(dir); + break; + } } void tmc2130_do_step(uint8_t axis) { - switch (axis) - { - case X_AXIS: _DO_STEP_X; break; - case Y_AXIS: _DO_STEP_Y; break; - case Z_AXIS: _DO_STEP_Z; break; - case E_AXIS: _DO_STEP_E; break; - } + switch (axis) + { + case X_AXIS: + _DO_STEP_X; + break; + case Y_AXIS: + _DO_STEP_Y; + break; + case Z_AXIS: + _DO_STEP_Z; + break; + case E_AXIS: + _DO_STEP_E; + break; + } } void tmc2130_do_steps(uint8_t axis, uint16_t steps, uint8_t dir, uint16_t delay_us) { - tmc2130_set_dir(axis, dir); - delayMicroseconds(100); - while (steps--) - { - tmc2130_do_step(axis); - delayMicroseconds(delay_us); - } + tmc2130_set_dir(axis, dir); + delayMicroseconds(100); + while (steps--) + { + tmc2130_do_step(axis); + delayMicroseconds(delay_us); + } } void tmc2130_goto_step(uint8_t axis, uint8_t step, uint8_t dir, uint16_t delay_us, uint16_t microstep_resolution) { - printf_P(PSTR("tmc2130_goto_step %d %d %d %d \n"), axis, step, dir, delay_us, microstep_resolution); - uint8_t shift; for (shift = 0; shift < 8; shift++) if (microstep_resolution == (256u >> shift)) break; - uint16_t cnt = 4 * (1 << (8 - shift)); - uint16_t mscnt = tmc2130_rd_MSCNT(axis); - if (dir == 2) - { - dir = tmc2130_get_inv(axis)?0:1; - int steps = (int)step - (int)(mscnt >> shift); - if (steps < 0) - { - dir ^= 1; - steps = -steps; - } - if (steps > static_cast(cnt / 2)) - { - dir ^= 1; - steps = cnt - steps; - } - cnt = steps; - } - tmc2130_set_dir(axis, dir); - delayMicroseconds(100); - mscnt = tmc2130_rd_MSCNT(axis); - while ((cnt--) && ((mscnt >> shift) != step)) - { - tmc2130_do_step(axis); - delayMicroseconds(delay_us); - mscnt = tmc2130_rd_MSCNT(axis); - } + printf_P(PSTR("tmc2130_goto_step %d %d %d %d \n"), axis, step, dir, delay_us, microstep_resolution); + uint8_t shift; + for (shift = 0; shift < 8; shift++) if (microstep_resolution == (256u >> shift)) break; + uint16_t cnt = 4 * (1 << (8 - shift)); + uint16_t mscnt = tmc2130_rd_MSCNT(axis); + if (dir == 2) + { + dir = tmc2130_get_inv(axis)?0:1; + int steps = (int)step - (int)(mscnt >> shift); + if (steps < 0) + { + dir ^= 1; + steps = -steps; + } + if (steps > static_cast(cnt / 2)) + { + dir ^= 1; + steps = cnt - steps; + } + cnt = steps; + } + tmc2130_set_dir(axis, dir); + delayMicroseconds(100); + mscnt = tmc2130_rd_MSCNT(axis); + while ((cnt--) && ((mscnt >> shift) != step)) + { + tmc2130_do_step(axis); + delayMicroseconds(delay_us); + mscnt = tmc2130_rd_MSCNT(axis); + } } void tmc2130_get_wave(uint8_t axis, uint8_t* data, FILE* stream) { - uint8_t pwr = tmc2130_get_pwr(axis); - tmc2130_set_pwr(axis, 0); - tmc2130_setup_chopper(axis, tmc2130_usteps2mres(256), tmc2130_current_h[axis], tmc2130_current_r[axis]); - tmc2130_goto_step(axis, 0, 2, 100, 256); - tmc2130_set_dir(axis, tmc2130_get_inv(axis)?0:1); - for (unsigned int i = 0; i <= 255; i++) - { - uint32_t val = tmc2130_rd_MSCURACT(axis); - uint16_t mscnt = tmc2130_rd_MSCNT(axis); - int curA = (val & 0xff) | ((val << 7) & 0x8000); - if (stream) - { - if (mscnt == i) - fprintf_P(stream, PSTR("%d\t%d\n"), i, curA); - else //TODO - remove this check - fprintf_P(stream, PSTR("!! (i=%d MSCNT=%d)\n"), i, mscnt); - } - if (data) *(data++) = curA; - tmc2130_do_step(axis); - delayMicroseconds(100); - } - tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); - tmc2130_set_pwr(axis, pwr); + uint8_t pwr = tmc2130_get_pwr(axis); + tmc2130_set_pwr(axis, 0); + tmc2130_setup_chopper(axis, tmc2130_usteps2mres(256), tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_goto_step(axis, 0, 2, 100, 256); + tmc2130_set_dir(axis, tmc2130_get_inv(axis)?0:1); + for (unsigned int i = 0; i <= 255; i++) + { + uint32_t val = tmc2130_rd_MSCURACT(axis); + uint16_t mscnt = tmc2130_rd_MSCNT(axis); + int curA = (val & 0xff) | ((val << 7) & 0x8000); + if (stream) + { + if (mscnt == i) + fprintf_P(stream, PSTR("%d\t%d\n"), i, curA); + else //TODO - remove this check + fprintf_P(stream, PSTR("!! (i=%d MSCNT=%d)\n"), i, mscnt); + } + if (data) *(data++) = curA; + tmc2130_do_step(axis); + delayMicroseconds(100); + } + tmc2130_setup_chopper(axis, tmc2130_mres[axis], tmc2130_current_h[axis], tmc2130_current_r[axis]); + tmc2130_set_pwr(axis, pwr); } void tmc2130_set_wave(uint8_t axis, uint8_t amp, uint8_t fac1000) @@ -849,175 +905,209 @@ void tmc2130_set_wave(uint8_t axis, uint8_t amp, uint8_t fac1000) // TMC2130 wave compression algorithm // optimized for minimal memory requirements // printf_P(PSTR("tmc2130_set_wave %hhd %hhd\n"), axis, fac1000); - if (fac1000 < TMC2130_WAVE_FAC1000_MIN) fac1000 = 0; - if (fac1000 > TMC2130_WAVE_FAC1000_MAX) fac1000 = TMC2130_WAVE_FAC1000_MAX; - float fac = 0; - if (fac1000) fac = ((float)((uint16_t)fac1000 + 1000) / 1000); //correction factor + if (fac1000 < TMC2130_WAVE_FAC1000_MIN) fac1000 = 0; + if (fac1000 > TMC2130_WAVE_FAC1000_MAX) fac1000 = TMC2130_WAVE_FAC1000_MAX; + float fac = 0; + if (fac1000) fac = ((float)((uint16_t)fac1000 + 1000) / 1000); //correction factor // printf_P(PSTR(" factor: %s\n"), ftostr43(fac)); - uint8_t vA = 0; //value of currentA - uint8_t va = 0; //previous vA - int8_t d0 = 0; //delta0 - int8_t d1 = 1; //delta1 - uint8_t w[4] = {1,1,1,1}; //W bits (MSLUTSEL) - uint8_t x[3] = {255,255,255}; //X segment bounds (MSLUTSEL) - uint8_t s = 0; //current segment - int8_t b; //encoded bit value + uint8_t vA = 0; //value of currentA + uint8_t va = 0; //previous vA + int8_t d0 = 0; //delta0 + int8_t d1 = 1; //delta1 + uint8_t w[4] = {1,1,1,1}; //W bits (MSLUTSEL) + uint8_t x[3] = {255,255,255}; //X segment bounds (MSLUTSEL) + uint8_t s = 0; //current segment + int8_t b; //encoded bit value int8_t dA; //delta value - int i; //microstep index - uint32_t reg = 0; //tmc2130 register - tmc2130_wr_MSLUTSTART(axis, 0, amp); - for (i = 0; i < 256; i++) - { - if ((i & 0x1f) == 0) - reg = 0; - // calculate value - if (fac == 0) // default TMC wave - vA = (uint8_t)((amp+1) * sin((2*PI*i + PI)/1024) + 0.5) - 1; - else // corrected wave - vA = (uint8_t)(amp * pow(sin(2*PI*i/1024), fac) + 0.5); - dA = vA - va; // calculate delta - va = vA; - b = -1; - if (dA == d0) b = 0; //delta == delta0 => bit=0 - else if (dA == d1) b = 1; //delta == delta1 => bit=1 - else - { - if (dA < d0) // delta < delta0 => switch wbit down - { - //printf("dn\n"); - b = 0; - switch (dA) - { - case -1: d0 = -1; d1 = 0; w[s+1] = 0; break; - case 0: d0 = 0; d1 = 1; w[s+1] = 1; break; - case 1: d0 = 1; d1 = 2; w[s+1] = 2; break; - default: b = -1; break; - } - if (b >= 0) { x[s] = i; s++; } - } - else if (dA > d1) // delta > delta0 => switch wbit up - { - //printf("up\n"); - b = 1; - switch (dA) - { - case 1: d0 = 0; d1 = 1; w[s+1] = 1; break; - case 2: d0 = 1; d1 = 2; w[s+1] = 2; break; - case 3: d0 = 2; d1 = 3; w[s+1] = 3; break; - default: b = -1; break; - } - if (b >= 0) { x[s] = i; s++; } - } - } - if (b < 0) break; // delta out of range (<-1 or >3) - if (s > 3) break; // segment out of range (> 3) - //printf("%d\n", vA); - if (b == 1) reg |= 0x80000000; - if ((i & 31) == 31) - tmc2130_wr_MSLUT(axis, (uint8_t)(i >> 5), reg); - else - reg >>= 1; + int i; //microstep index + uint32_t reg = 0; //tmc2130 register + tmc2130_wr_MSLUTSTART(axis, 0, amp); + for (i = 0; i < 256; i++) + { + if ((i & 0x1f) == 0) + reg = 0; + // calculate value + if (fac == 0) // default TMC wave + vA = (uint8_t)((amp+1) * sin((2*PI*i + PI)/1024) + 0.5) - 1; + else // corrected wave + vA = (uint8_t)(amp * pow(sin(2*PI*i/1024), fac) + 0.5); + dA = vA - va; // calculate delta + va = vA; + b = -1; + if (dA == d0) b = 0; //delta == delta0 => bit=0 + else if (dA == d1) b = 1; //delta == delta1 => bit=1 + else + { + if (dA < d0) // delta < delta0 => switch wbit down + { + //printf("dn\n"); + b = 0; + switch (dA) + { + case -1: + d0 = -1; + d1 = 0; + w[s+1] = 0; + break; + case 0: + d0 = 0; + d1 = 1; + w[s+1] = 1; + break; + case 1: + d0 = 1; + d1 = 2; + w[s+1] = 2; + break; + default: + b = -1; + break; + } + if (b >= 0) { + x[s] = i; + s++; + } + } + else if (dA > d1) // delta > delta0 => switch wbit up + { + //printf("up\n"); + b = 1; + switch (dA) + { + case 1: + d0 = 0; + d1 = 1; + w[s+1] = 1; + break; + case 2: + d0 = 1; + d1 = 2; + w[s+1] = 2; + break; + case 3: + d0 = 2; + d1 = 3; + w[s+1] = 3; + break; + default: + b = -1; + break; + } + if (b >= 0) { + x[s] = i; + s++; + } + } + } + if (b < 0) break; // delta out of range (<-1 or >3) + if (s > 3) break; // segment out of range (> 3) + //printf("%d\n", vA); + if (b == 1) reg |= 0x80000000; + if ((i & 31) == 31) + tmc2130_wr_MSLUT(axis, (uint8_t)(i >> 5), reg); + else + reg >>= 1; // printf("%3d\t%3d\t%2d\t%2d\t%2d\t%2d %08x\n", i, vA, dA, b, w[s], s, reg); - } - tmc2130_wr_MSLUTSEL(axis, x[0], x[1], x[2], w[0], w[1], w[2], w[3]); + } + tmc2130_wr_MSLUTSEL(axis, x[0], x[1], x[2], w[0], w[1], w[2], w[3]); } void bubblesort_uint8(uint8_t* data, uint8_t size, uint8_t* data2) { - uint8_t changed = 1; - while (changed) - { - changed = 0; - for (uint8_t i = 0; i < (size - 1); i++) - if (data[i] > data[i+1]) - { - uint8_t register d = data[i]; - data[i] = data[i+1]; - data[i+1] = d; - if (data2) - { - d = data2[i]; - data2[i] = data2[i+1]; - data2[i+1] = d; - } - changed = 1; - } - } + uint8_t changed = 1; + while (changed) + { + changed = 0; + for (uint8_t i = 0; i < (size - 1); i++) + if (data[i] > data[i+1]) + { + uint8_t register d = data[i]; + data[i] = data[i+1]; + data[i+1] = d; + if (data2) + { + d = data2[i]; + data2[i] = data2[i+1]; + data2[i+1] = d; + } + changed = 1; + } + } } uint8_t clusterize_uint8(uint8_t* data, uint8_t size, uint8_t* ccnt, uint8_t* cval, uint8_t tol) { - uint8_t cnt = 1; - uint16_t sum = data[0]; - uint8_t cl = 0; - for (uint8_t i = 1; i < size; i++) - { - uint8_t d = data[i]; - uint8_t val = sum / cnt; - uint8_t dif = 0; - if (val > d) dif = val - d; - else dif = d - val; - if (dif <= tol) - { - cnt += 1; - sum += d; - } - else - { - if (ccnt) ccnt[cl] = cnt; - if (cval) cval[cl] = val; - cnt = 1; - sum = d; - cl += 1; - } - } - if (ccnt) ccnt[cl] = cnt; - if (cval) cval[cl] = sum / cnt; - return ++cl; + uint8_t cnt = 1; + uint16_t sum = data[0]; + uint8_t cl = 0; + for (uint8_t i = 1; i < size; i++) + { + uint8_t d = data[i]; + uint8_t val = sum / cnt; + uint8_t dif = 0; + if (val > d) dif = val - d; + else dif = d - val; + if (dif <= tol) + { + cnt += 1; + sum += d; + } + else + { + if (ccnt) ccnt[cl] = cnt; + if (cval) cval[cl] = val; + cnt = 1; + sum = d; + cl += 1; + } + } + if (ccnt) ccnt[cl] = cnt; + if (cval) cval[cl] = sum / cnt; + return ++cl; } bool tmc2130_home_calibrate(uint8_t axis) { - uint8_t step[16]; - uint8_t cnt[16]; - uint8_t val[16]; - homeaxis(axis, 16, step); - bubblesort_uint8(step, 16, 0); - printf_P(PSTR("sorted samples:\n")); - for (uint8_t i = 0; i < 16; i++) - printf_P(PSTR(" i=%2d step=%2d\n"), i, step[i]); - uint8_t cl = clusterize_uint8(step, 16, cnt, val, 1); - printf_P(PSTR("clusters:\n")); - for (uint8_t i = 0; i < cl; i++) - printf_P(PSTR(" i=%2d cnt=%2d val=%2d\n"), i, cnt[i], val[i]); - bubblesort_uint8(cnt, cl, val); - tmc2130_home_origin[axis] = val[cl-1]; - printf_P(PSTR("result value: %d\n"), tmc2130_home_origin[axis]); - if (axis == X_AXIS) eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_X_ORIGIN, tmc2130_home_origin[X_AXIS]); - else if (axis == Y_AXIS) eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_ORIGIN, tmc2130_home_origin[Y_AXIS]); - return true; + uint8_t step[16]; + uint8_t cnt[16]; + uint8_t val[16]; + homeaxis(axis, 16, step); + bubblesort_uint8(step, 16, 0); + printf_P(PSTR("sorted samples:\n")); + for (uint8_t i = 0; i < 16; i++) + printf_P(PSTR(" i=%2d step=%2d\n"), i, step[i]); + uint8_t cl = clusterize_uint8(step, 16, cnt, val, 1); + printf_P(PSTR("clusters:\n")); + for (uint8_t i = 0; i < cl; i++) + printf_P(PSTR(" i=%2d cnt=%2d val=%2d\n"), i, cnt[i], val[i]); + bubblesort_uint8(cnt, cl, val); + tmc2130_home_origin[axis] = val[cl-1]; + printf_P(PSTR("result value: %d\n"), tmc2130_home_origin[axis]); + if (axis == X_AXIS) eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_X_ORIGIN, tmc2130_home_origin[X_AXIS]); + else if (axis == Y_AXIS) eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_Y_ORIGIN, tmc2130_home_origin[Y_AXIS]); + return true; } uint8_t tmc2130_cur2val(float cur) { - if (cur < 0) cur = 0; //limit min - if (cur > 1029) cur = 1029; //limit max - //540mA is threshold for switch from high sense to low sense - //for higher currents is maximum current 1029mA - if (cur >= 540) return 63 * (float)cur / 1029; - //for lower currents must be the value divided by 1.125 (= 0.18*2/0.32) - return 63 * (float)cur / (1029 * 1.125); + if (cur < 0) cur = 0; //limit min + if (cur > 1029) cur = 1029; //limit max + //540mA is threshold for switch from high sense to low sense + //for higher currents is maximum current 1029mA + if (cur >= 540) return 63 * (float)cur / 1029; + //for lower currents must be the value divided by 1.125 (= 0.18*2/0.32) + return 63 * (float)cur / (1029 * 1.125); } float tmc2130_val2cur(uint8_t val) { - float rsense = 0.2; //0.2 ohm sense resistors - uint8_t vsense = (val & 0x20)?0:1; //vsense bit = val>31 - float vfs = vsense?0.18:0.32; //vfs depends on vsense bit - uint8_t val2 = vsense?val:(val >> 1); //vals 32..63 shifted right (16..31) - // equation from datasheet (0.7071 ~= 1/sqrt(2)) - float cur = ((float)(val2 + 1)/32) * (vfs/(rsense + 0.02)) * 0.7071; - return cur * 1000; //return current in mA + float rsense = 0.2; //0.2 ohm sense resistors + uint8_t vsense = (val & 0x20)?0:1; //vsense bit = val>31 + float vfs = vsense?0.18:0.32; //vfs depends on vsense bit + uint8_t val2 = vsense?val:(val >> 1); //vals 32..63 shifted right (16..31) + // equation from datasheet (0.7071 ~= 1/sqrt(2)) + float cur = ((float)(val2 + 1)/32) * (vfs/(rsense + 0.02)) * 0.7071; + return cur * 1000; //return current in mA } diff --git a/Firmware/tmc2130.h b/Firmware/tmc2130.h index 1c854f79c0..9412179479 100755 --- a/Firmware/tmc2130.h +++ b/Firmware/tmc2130.h @@ -40,11 +40,11 @@ extern uint8_t tmc2130_wave_fac[4]; #pragma pack(1) typedef struct { - uint8_t toff:4; - uint8_t hstr:3; - uint8_t hend:4; - uint8_t tbl:2; - uint8_t res:3; + uint8_t toff:4; + uint8_t hstr:3; + uint8_t hend:4; + uint8_t tbl:2; + uint8_t res:3; } tmc2130_chopper_config_t; #pragma pack(pop) diff --git a/Firmware/uart2.c b/Firmware/uart2.c index 472389994d..a12f556786 100755 --- a/Firmware/uart2.c +++ b/Firmware/uart2.c @@ -18,67 +18,67 @@ FILE _uart2io = {0}; int uart2_putchar(char c, FILE *stream __attribute__((unused))) { - while (!uart2_txready); - UDR2 = c; // transmit byte + while (!uart2_txready); + UDR2 = c; // transmit byte // while (!uart2_txcomplete); // wait until byte sent // UCSR2A |= (1 << TXC2); // delete TXCflag - return 0; + return 0; } int uart2_getchar(FILE *stream __attribute__((unused))) { - if (rbuf_empty(uart2_ibuf)) return -1; - return rbuf_get(uart2_ibuf); + if (rbuf_empty(uart2_ibuf)) return -1; + return rbuf_get(uart2_ibuf); } //uart init (io + FILE stream) void uart2_init(void) { - DDRH &= ~0x01; - PORTH |= 0x01; - rbuf_ini(uart2_ibuf, sizeof(uart2_ibuf) - 4); - UCSR2A |= (1 << U2X2); // baudrate multiplier - UBRR2L = UART_BAUD_SELECT(UART2_BAUD, F_CPU); // select baudrate - UCSR2B = (1 << RXEN2) | (1 << TXEN2); // enable receiver and transmitter - UCSR2B |= (1 << RXCIE2); // enable rx interrupt - fdev_setup_stream(uart2io, uart2_putchar, uart2_getchar, _FDEV_SETUP_WRITE | _FDEV_SETUP_READ); //setup uart2 i/o stream + DDRH &= ~0x01; + PORTH |= 0x01; + rbuf_ini(uart2_ibuf, sizeof(uart2_ibuf) - 4); + UCSR2A |= (1 << U2X2); // baudrate multiplier + UBRR2L = UART_BAUD_SELECT(UART2_BAUD, F_CPU); // select baudrate + UCSR2B = (1 << RXEN2) | (1 << TXEN2); // enable receiver and transmitter + UCSR2B |= (1 << RXCIE2); // enable rx interrupt + fdev_setup_stream(uart2io, uart2_putchar, uart2_getchar, _FDEV_SETUP_WRITE | _FDEV_SETUP_READ); //setup uart2 i/o stream } //returns 1 if chars in input buffer match to str //returns -1 if chars does not match and 0 for empty buffer int8_t uart2_rx_str_P(const char* str) { - uint8_t r = rbuf_r(uart2_ibuf); //get read index - uint8_t w = rbuf_w(uart2_ibuf); //get write index + uint8_t r = rbuf_r(uart2_ibuf); //get read index + uint8_t w = rbuf_w(uart2_ibuf); //get write index // printf_P(PSTR("uart2_rx_str_P r=%d w=%d\n"), r, w); - uint8_t e = rbuf_l(uart2_ibuf) - 1; //get end index - uint8_t len = strlen_P(str); //get string length - str += len; //last char will be compared first + uint8_t e = rbuf_l(uart2_ibuf) - 1; //get end index + uint8_t len = strlen_P(str); //get string length + str += len; //last char will be compared first // printf_P(PSTR(" len=%d\n"), len); - while (len--) //loop over all chars - { - if (w == r) return 0; //empty buffer - return 0 - if ((--w) == 255) w = e; //decrement index - char c0 = pgm_read_byte(--str); //read char from str - char c1 = uart2_ibuf[4 + w]; //read char from input buffer + while (len--) //loop over all chars + { + if (w == r) return 0; //empty buffer - return 0 + if ((--w) == 255) w = e; //decrement index + char c0 = pgm_read_byte(--str); //read char from str + char c1 = uart2_ibuf[4 + w]; //read char from input buffer // printf_P(PSTR(" uart2_rx_str_P w=%d l=%d c0=%02x c1=%02x\n"), w, len, c0, c1); - if (c0 == c1) continue; //if match, continue with next char - if ((c0 == '\r') && (c1 == '\n')) //match cr as lf - continue; - if ((c0 == '\n') && (c1 == '\r')) //match lf as cr - continue; - return -1; //no match - return -1 - } - return 1; //all characters match - return 1 + if (c0 == c1) continue; //if match, continue with next char + if ((c0 == '\r') && (c1 == '\n')) //match cr as lf + continue; + if ((c0 == '\n') && (c1 == '\r')) //match lf as cr + continue; + return -1; //no match - return -1 + } + return 1; //all characters match - return 1 } ISR(USART2_RX_vect) { - //printf_P(PSTR("USART2_RX_vect \n") ); - if (rbuf_put(uart2_ibuf, UDR2) < 0) // put received byte to buffer - { //rx buffer full - //uart2_rx_clr(); //for sure, clear input buffer - printf_P(PSTR("USART2 rx Full!!!\n")); - } + //printf_P(PSTR("USART2_RX_vect \n") ); + if (rbuf_put(uart2_ibuf, UDR2) < 0) // put received byte to buffer + { //rx buffer full + //uart2_rx_clr(); //for sure, clear input buffer + printf_P(PSTR("USART2 rx Full!!!\n")); + } } diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 951c934850..ede3ecfdf2 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -171,7 +171,7 @@ static void lcd_disable_farm_mode(); static void lcd_set_fan_check(); static char snmm_stop_print_menu(); #ifdef SDCARD_SORT_ALPHA - static void lcd_sort_type_set(); +static void lcd_sort_type_set(); #endif static float count_e(float layer_heigth, float extrusion_width, float extrusion_length); static void lcd_babystep_z(); @@ -239,9 +239,9 @@ static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, char* longF char c; int enc_dif = lcd_encoder_diff; uint8_t n = LCD_WIDTH - 1; - for(int g = 0; g<4;g++){ - lcd_set_cursor(0, g); - lcd_print(' '); + for(int g = 0; g<4; g++) { + lcd_set_cursor(0, g); + lcd_print(' '); } lcd_set_cursor(0, row); @@ -256,29 +256,29 @@ static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, char* longF lcd_print(c); i++; longFilenameTMP++; - if(i==LCD_WIDTH){ - i=1; - j++; - longFilenameTMP = longFilename + j; - n = LCD_WIDTH - 1; - for(int g = 0; g<300 ;g++){ - manage_heater(); - if(LCD_CLICKED || ( enc_dif != lcd_encoder_diff )){ - longFilenameTMP = longFilename; - *(longFilenameTMP + LCD_WIDTH - 2) = '\0'; - i = 1; - j = 0; - break; - }else{ - if (j == 1) delay(3); //wait around 1.2 s to start scrolling text - delay(1); //then scroll with redrawing every 300 ms - } + if(i==LCD_WIDTH) { + i=1; + j++; + longFilenameTMP = longFilename + j; + n = LCD_WIDTH - 1; + for(int g = 0; g<300 ; g++) { + manage_heater(); + if(LCD_CLICKED || ( enc_dif != lcd_encoder_diff )) { + longFilenameTMP = longFilename; + *(longFilenameTMP + LCD_WIDTH - 2) = '\0'; + i = 1; + j = 0; + break; + } else { + if (j == 1) delay(3); //wait around 1.2 s to start scrolling text + delay(1); //then scroll with redrawing every 300 ms + } - } + } } } - if(c!='\0'){ - lcd_set_cursor(i, row); + if(c!='\0') { + lcd_set_cursor(i, row); lcd_print(c); i++; } @@ -365,123 +365,123 @@ uint8_t menu_item_sddir(const char* str_fn, char* str_fnl) #ifdef NEW_SD_MENU // str_fnl[18] = 0; // printf_P(PSTR("menu dir %d '%s' '%s'\n"), menu_row, str_fn, str_fnl); - if (menu_item == menu_line) - { - if (lcd_draw_update) - { - lcd_set_cursor(0, menu_row); - int cnt = lcd_printf_P(PSTR("%c%c%-18s"), (lcd_encoder == menu_item)?'>':' ', LCD_STR_FOLDER[0], str_fnl[0]?str_fnl:str_fn); + if (menu_item == menu_line) + { + if (lcd_draw_update) + { + lcd_set_cursor(0, menu_row); + int cnt = lcd_printf_P(PSTR("%c%c%-18s"), (lcd_encoder == menu_item)?'>':' ', LCD_STR_FOLDER[0], str_fnl[0]?str_fnl:str_fn); // int cnt = lcd_printf_P(PSTR("%c%c%-18s"), (lcd_encoder == menu_item)?'>':' ', LCD_STR_FOLDER[0], str_fn); - } - if (menu_clicked && (lcd_encoder == menu_item)) - { - uint8_t depth = (uint8_t)card.getWorkDirDepth(); - strcpy(dir_names[depth], str_fn); + } + if (menu_clicked && (lcd_encoder == menu_item)) + { + uint8_t depth = (uint8_t)card.getWorkDirDepth(); + strcpy(dir_names[depth], str_fn); // printf_P(PSTR("%s\n"), dir_names[depth]); - card.chdir(str_fn); - lcd_encoder = 0; - return menu_item_ret(); - } - } - menu_item++; - return 0; + card.chdir(str_fn); + lcd_encoder = 0; + return menu_item_ret(); + } + } + menu_item++; + return 0; #else //NEW_SD_MENU - if (menu_item == menu_line) - { - if (lcd_draw_update) - { - if (lcd_encoder == menu_item) - lcd_implementation_drawmenu_sddirectory_selected(menu_row, str_fn, str_fnl); - else - lcd_implementation_drawmenu_sddirectory(menu_row, str_fn, str_fnl); - } - if (menu_clicked && (lcd_encoder == menu_item)) - { - menu_clicked = false; - lcd_update_enabled = 0; - menu_action_sddirectory(str_fn); - lcd_update_enabled = 1; - return menu_item_ret(); - } - } - menu_item++; - return 0; + if (menu_item == menu_line) + { + if (lcd_draw_update) + { + if (lcd_encoder == menu_item) + lcd_implementation_drawmenu_sddirectory_selected(menu_row, str_fn, str_fnl); + else + lcd_implementation_drawmenu_sddirectory(menu_row, str_fn, str_fnl); + } + if (menu_clicked && (lcd_encoder == menu_item)) + { + menu_clicked = false; + lcd_update_enabled = 0; + menu_action_sddirectory(str_fn); + lcd_update_enabled = 1; + return menu_item_ret(); + } + } + menu_item++; + return 0; #endif //NEW_SD_MENU } static uint8_t menu_item_sdfile(const char* #ifdef NEW_SD_MENU - str + str #endif //NEW_SD_MENU - ,const char* str_fn, char* str_fnl) + ,const char* str_fn, char* str_fnl) { #ifdef NEW_SD_MENU // printf_P(PSTR("menu sdfile\n")); // str_fnl[19] = 0; // printf_P(PSTR("menu file %d '%s' '%s'\n"), menu_row, str_fn, str_fnl); - if (menu_item == menu_line) - { - if (lcd_draw_update) - { + if (menu_item == menu_line) + { + if (lcd_draw_update) + { // printf_P(PSTR("menu file %d %d '%s'\n"), menu_row, menuData.sdcard_menu.viewState, str_fnl[0]?str_fnl:str_fn); - lcd_set_cursor(0, menu_row); -/* if (lcd_encoder == menu_item) - { - lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1); - if (menuData.sdcard_menu.viewState == 0) - { - menuData.sdcard_menu.viewState++; - lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1); - } - else if (menuData.sdcard_menu.viewState == 1) - { - lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 2); - } - } - else*/ - { - str_fnl[19] = 0; - lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', str_fnl[0]?str_fnl:str_fn); - } + lcd_set_cursor(0, menu_row); + /* if (lcd_encoder == menu_item) + { + lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1); + if (menuData.sdcard_menu.viewState == 0) + { + menuData.sdcard_menu.viewState++; + lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1); + } + else if (menuData.sdcard_menu.viewState == 1) + { + lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 2); + } + } + else*/ + { + str_fnl[19] = 0; + lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', str_fnl[0]?str_fnl:str_fn); + } // int cnt = lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', str_fnl); // int cnt = lcd_printf_P(PSTR("%cTESTIK.gcode"), (lcd_encoder == menu_item)?'>':' '); - } - if (menu_clicked && (lcd_encoder == menu_item)) - { - return menu_item_ret(); - } - } - menu_item++; - return 0; + } + if (menu_clicked && (lcd_encoder == menu_item)) + { + return menu_item_ret(); + } + } + menu_item++; + return 0; #else //NEW_SD_MENU - if (menu_item == menu_line) - { - if (lcd_draw_update) - { - if (lcd_encoder == menu_item) - lcd_implementation_drawmenu_sdfile_selected(menu_row, str_fnl); - else - lcd_implementation_drawmenu_sdfile(menu_row, str_fn, str_fnl); - } - if (menu_clicked && (lcd_encoder == menu_item)) - { - lcd_consume_click(); - menu_action_sdfile(str_fn); - return menu_item_ret(); - } - } - menu_item++; - return 0; + if (menu_item == menu_line) + { + if (lcd_draw_update) + { + if (lcd_encoder == menu_item) + lcd_implementation_drawmenu_sdfile_selected(menu_row, str_fnl); + else + lcd_implementation_drawmenu_sdfile(menu_row, str_fn, str_fnl); + } + if (menu_clicked && (lcd_encoder == menu_item)) + { + lcd_consume_click(); + menu_action_sdfile(str_fn); + return menu_item_ret(); + } + } + menu_item++; + return 0; #endif //NEW_SD_MENU } // Print temperature (nozzle/bed) (9 chars total) void lcdui_print_temp(char type, int val_current, int val_target) { - int chars = lcd_printf_P(_N("%c%3d/%d%c"), type, val_current, val_target, LCD_STR_DEGREE[0]); - lcd_space(9 - chars); + int chars = lcd_printf_P(_N("%c%3d/%d%c"), type, val_current, val_target, LCD_STR_DEGREE[0]); + lcd_space(9 - chars); } // Print Z-coordinate (8 chars total) @@ -490,298 +490,298 @@ void lcdui_print_Z_coord(void) if (custom_message_type == CUSTOM_MSG_TYPE_MESHBL) lcd_puts_P(_N("Z --- ")); else - lcd_printf_P(_N("Z%6.2f "), current_position[Z_AXIS]); + lcd_printf_P(_N("Z%6.2f "), current_position[Z_AXIS]); } #ifdef PLANNER_DIAGNOSTICS // Print planner diagnostics (8 chars total) void lcdui_print_planner_diag(void) { - lcd_set_cursor(LCD_WIDTH - 8-2, 1); - lcd_print(LCD_STR_FEEDRATE[0]); - lcd_print(itostr3(feedmultiply)); - lcd_puts_P(PSTR("% Q")); - { - uint8_t queue = planner_queue_min(); - if (queue < (BLOCK_BUFFER_SIZE >> 1)) - lcd_putc('!'); - else - { - lcd_putc((char)(queue / 10) + '0'); - queue %= 10; - } - lcd_putc((char)queue + '0'); - planner_queue_min_reset(); - } + lcd_set_cursor(LCD_WIDTH - 8-2, 1); + lcd_print(LCD_STR_FEEDRATE[0]); + lcd_print(itostr3(feedmultiply)); + lcd_puts_P(PSTR("% Q")); + { + uint8_t queue = planner_queue_min(); + if (queue < (BLOCK_BUFFER_SIZE >> 1)) + lcd_putc('!'); + else + { + lcd_putc((char)(queue / 10) + '0'); + queue %= 10; + } + lcd_putc((char)queue + '0'); + planner_queue_min_reset(); + } } #endif // PLANNER_DIAGNOSTICS // Print feedrate (8 chars total) void lcdui_print_feedrate(void) { - int chars = lcd_printf_P(_N("%c%3d%%"), LCD_STR_FEEDRATE[0], feedmultiply); - lcd_space(8 - chars); + int chars = lcd_printf_P(_N("%c%3d%%"), LCD_STR_FEEDRATE[0], feedmultiply); + lcd_space(8 - chars); } // Print percent done in form "USB---%", " SD---%", " ---%" (7 chars total) void lcdui_print_percent_done(void) { - const char* src = is_usb_printing?_N("USB"):(IS_SD_PRINTING?_N(" SD"):_N(" ")); - char per[4]; - bool num = IS_SD_PRINTING || (PRINTER_ACTIVE && (print_percent_done_normal != PRINT_PERCENT_DONE_INIT)); - sprintf_P(per, num?_N("%3hhd"):_N("---"), calc_percent_done()); - lcd_printf_P(_N("%3S%3s%%"), src, per); + const char* src = is_usb_printing?_N("USB"):(IS_SD_PRINTING?_N(" SD"):_N(" ")); + char per[4]; + bool num = IS_SD_PRINTING || (PRINTER_ACTIVE && (print_percent_done_normal != PRINT_PERCENT_DONE_INIT)); + sprintf_P(per, num?_N("%3hhd"):_N("---"), calc_percent_done()); + lcd_printf_P(_N("%3S%3s%%"), src, per); } // Print extruder status (5 chars total) void lcdui_print_extruder(void) { - int chars = 0; - if (mmu_extruder == tmp_extruder) - chars = lcd_printf_P(_N(" F%u"), mmu_extruder+1); - else - chars = lcd_printf_P(_N(" %u>%u"), mmu_extruder+1, tmp_extruder+1); - lcd_space(5 - chars); + int chars = 0; + if (mmu_extruder == tmp_extruder) + chars = lcd_printf_P(_N(" F%u"), mmu_extruder+1); + else + chars = lcd_printf_P(_N(" %u>%u"), mmu_extruder+1, tmp_extruder+1); + lcd_space(5 - chars); } // Print farm number (5 chars total) void lcdui_print_farm(void) { - int chars = lcd_printf_P(_N(" F0 ")); + int chars = lcd_printf_P(_N(" F0 ")); // lcd_space(5 - chars); -/* - // Farm number display - if (farm_mode) - { - lcd_set_cursor(6, 2); - lcd_puts_P(PSTR(" F")); - lcd_print(farm_no); - lcd_puts_P(PSTR(" ")); - - // Beat display - lcd_set_cursor(LCD_WIDTH - 1, 0); - if ( (millis() - kicktime) < 60000 ) { - - lcd_puts_P(PSTR("L")); - - }else{ - lcd_puts_P(PSTR(" ")); - } - - } - else { -#ifdef SNMM - lcd_puts_P(PSTR(" E")); - lcd_print(get_ext_nr() + 1); + /* + // Farm number display + if (farm_mode) + { + lcd_set_cursor(6, 2); + lcd_puts_P(PSTR(" F")); + lcd_print(farm_no); + lcd_puts_P(PSTR(" ")); -#else - lcd_set_cursor(LCD_WIDTH - 8 - 2, 2); - lcd_puts_P(PSTR(" ")); -#endif - } -*/ + // Beat display + lcd_set_cursor(LCD_WIDTH - 1, 0); + if ( (millis() - kicktime) < 60000 ) { + + lcd_puts_P(PSTR("L")); + + }else{ + lcd_puts_P(PSTR(" ")); + } + + } + else { + #ifdef SNMM + lcd_puts_P(PSTR(" E")); + lcd_print(get_ext_nr() + 1); + + #else + lcd_set_cursor(LCD_WIDTH - 8 - 2, 2); + lcd_puts_P(PSTR(" ")); + #endif + } + */ } #ifdef CMD_DIAGNOSTICS // Print CMD queue diagnostic (8 chars total) void lcdui_print_cmd_diag(void) { - lcd_set_cursor(LCD_WIDTH - 8 -1, 2); - lcd_puts_P(PSTR(" C")); - lcd_print(buflen); // number of commands in cmd buffer - if (buflen < 9) lcd_puts_P(" "); + lcd_set_cursor(LCD_WIDTH - 8 -1, 2); + lcd_puts_P(PSTR(" C")); + lcd_print(buflen); // number of commands in cmd buffer + if (buflen < 9) lcd_puts_P(" "); } #endif //CMD_DIAGNOSTICS // Print time (8 chars total) void lcdui_print_time(void) { - //if remaining print time estimation is available print it else print elapsed time - uint16_t print_t = 0; - if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) - print_t = print_time_remaining(); - else if(starttime != 0) - print_t = millis() / 60000 - starttime / 60000; - int chars = 0; - if ((PRINTER_ACTIVE) && ((print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) || (starttime != 0))) - { - char suff = ' '; - char suff_doubt = ' '; - if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) - { - suff = 'R'; - if (feedmultiply != 100) - suff_doubt = '?'; - } - if (print_t < 6000) //time<100h - chars = lcd_printf_P(_N("%c%02u:%02u%c%c"), LCD_STR_CLOCK[0], print_t / 60, print_t % 60, suff, suff_doubt); - else //time>=100h - chars = lcd_printf_P(_N("%c%3uh %c%c"), LCD_STR_CLOCK[0], print_t / 60, suff, suff_doubt); - } - else - chars = lcd_printf_P(_N("%c--:-- "), LCD_STR_CLOCK[0]); - lcd_space(8 - chars); + //if remaining print time estimation is available print it else print elapsed time + uint16_t print_t = 0; + if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) + print_t = print_time_remaining(); + else if(starttime != 0) + print_t = millis() / 60000 - starttime / 60000; + int chars = 0; + if ((PRINTER_ACTIVE) && ((print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) || (starttime != 0))) + { + char suff = ' '; + char suff_doubt = ' '; + if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) + { + suff = 'R'; + if (feedmultiply != 100) + suff_doubt = '?'; + } + if (print_t < 6000) //time<100h + chars = lcd_printf_P(_N("%c%02u:%02u%c%c"), LCD_STR_CLOCK[0], print_t / 60, print_t % 60, suff, suff_doubt); + else //time>=100h + chars = lcd_printf_P(_N("%c%3uh %c%c"), LCD_STR_CLOCK[0], print_t / 60, suff, suff_doubt); + } + else + chars = lcd_printf_P(_N("%c--:-- "), LCD_STR_CLOCK[0]); + lcd_space(8 - chars); } //Print status line on status screen void lcdui_print_status_line(void) { - if (IS_SD_PRINTING) - { - if (strcmp(longFilenameOLD, card.longFilename) != 0) - { - memset(longFilenameOLD, '\0', strlen(longFilenameOLD)); - sprintf_P(longFilenameOLD, PSTR("%s"), card.longFilename); - scrollstuff = 0; - } - } + if (IS_SD_PRINTING) + { + if (strcmp(longFilenameOLD, card.longFilename) != 0) + { + memset(longFilenameOLD, '\0', strlen(longFilenameOLD)); + sprintf_P(longFilenameOLD, PSTR("%s"), card.longFilename); + scrollstuff = 0; + } + } - if (heating_status) - { // If heating flag, show progress of heating - heating_status_counter++; - if (heating_status_counter > 13) - { - heating_status_counter = 0; - } - lcd_set_cursor(7, 3); - lcd_puts_P(PSTR(" ")); + if (heating_status) + { // If heating flag, show progress of heating + heating_status_counter++; + if (heating_status_counter > 13) + { + heating_status_counter = 0; + } + lcd_set_cursor(7, 3); + lcd_puts_P(PSTR(" ")); + + for (unsigned int dots = 0; dots < heating_status_counter; dots++) + { + lcd_set_cursor(7 + dots, 3); + lcd_print('.'); + } + switch (heating_status) + { + case 1: + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_HEATING)); + break; + case 2: + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_HEATING_COMPLETE)); + heating_status = 0; + heating_status_counter = 0; + break; + case 3: + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_BED_HEATING)); + break; + case 4: + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_BED_DONE)); + heating_status = 0; + heating_status_counter = 0; + break; + default: + break; + } + } + else if ((IS_SD_PRINTING) && (custom_message_type == CUSTOM_MSG_TYPE_STATUS)) + { // If printing from SD, show what we are printing + if(strlen(card.longFilename) > LCD_WIDTH) + { + int inters = 0; + int gh = scrollstuff; + while (((gh - scrollstuff) < LCD_WIDTH) && (inters == 0)) + { + if (card.longFilename[gh] == '\0') + { + lcd_set_cursor(gh - scrollstuff, 3); + lcd_print(card.longFilename[gh - 1]); + scrollstuff = 0; + gh = scrollstuff; + inters = 1; + } + else + { + lcd_set_cursor(gh - scrollstuff, 3); + lcd_print(card.longFilename[gh - 1]); + gh++; + } + } + scrollstuff++; + } + else + { + lcd_print(longFilenameOLD); + } + } + else + { // Otherwise check for other special events + switch (custom_message_type) + { + case CUSTOM_MSG_TYPE_STATUS: // Nothing special, print status message normally + lcd_print(lcd_status_message); + break; + case CUSTOM_MSG_TYPE_MESHBL: // If mesh bed leveling in progress, show the status + if (custom_message_state > 10) + { + lcd_set_cursor(0, 3); + lcd_puts_P(PSTR(" ")); + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_CALIBRATE_Z_AUTO)); + lcd_puts_P(PSTR(" : ")); + lcd_print(custom_message_state-10); + } + else + { + if (custom_message_state == 3) + { + lcd_puts_P(_T(WELCOME_MSG)); + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = CUSTOM_MSG_TYPE_STATUS; + } + if (custom_message_state > 3 && custom_message_state <= 10 ) + { + lcd_set_cursor(0, 3); + lcd_puts_P(PSTR(" ")); + lcd_set_cursor(0, 3); + lcd_puts_P(_i("Calibration done"));////MSG_HOMEYZ_DONE c=0 r=0 + custom_message_state--; + } + } + break; + case CUSTOM_MSG_TYPE_F_LOAD: // If loading filament, print status + lcd_print(lcd_status_message); + break; + case CUSTOM_MSG_TYPE_PIDCAL: // PID tuning in progress + lcd_print(lcd_status_message); + if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0) + { + lcd_set_cursor(10, 3); + lcd_print(itostr3(pid_cycle)); + lcd_print('/'); + lcd_print(itostr3left(pid_number_of_cycles)); + } + break; + case CUSTOM_MSG_TYPE_TEMCAL: // PINDA temp calibration in progress + { + char progress[4]; + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_TEMP_CALIBRATION)); + lcd_set_cursor(12, 3); + sprintf(progress, "%d/6", custom_message_state); + lcd_print(progress); + } + break; + case CUSTOM_MSG_TYPE_TEMPRE: // temp compensation preheat + lcd_set_cursor(0, 3); + lcd_puts_P(_i("PINDA Heating"));////MSG_PINDA_PREHEAT c=20 r=1 + if (custom_message_state <= PINDA_HEAT_T) + { + lcd_puts_P(PSTR(": ")); + lcd_print(custom_message_state); //seconds + lcd_print(' '); + } + break; + } + } - for (unsigned int dots = 0; dots < heating_status_counter; dots++) - { - lcd_set_cursor(7 + dots, 3); - lcd_print('.'); - } - switch (heating_status) - { - case 1: - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_HEATING)); - break; - case 2: - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_HEATING_COMPLETE)); - heating_status = 0; - heating_status_counter = 0; - break; - case 3: - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_BED_HEATING)); - break; - case 4: - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_BED_DONE)); - heating_status = 0; - heating_status_counter = 0; - break; - default: - break; - } - } - else if ((IS_SD_PRINTING) && (custom_message_type == CUSTOM_MSG_TYPE_STATUS)) - { // If printing from SD, show what we are printing - if(strlen(card.longFilename) > LCD_WIDTH) - { - int inters = 0; - int gh = scrollstuff; - while (((gh - scrollstuff) < LCD_WIDTH) && (inters == 0)) - { - if (card.longFilename[gh] == '\0') - { - lcd_set_cursor(gh - scrollstuff, 3); - lcd_print(card.longFilename[gh - 1]); - scrollstuff = 0; - gh = scrollstuff; - inters = 1; - } - else - { - lcd_set_cursor(gh - scrollstuff, 3); - lcd_print(card.longFilename[gh - 1]); - gh++; - } - } - scrollstuff++; - } - else - { - lcd_print(longFilenameOLD); - } - } - else - { // Otherwise check for other special events - switch (custom_message_type) - { - case CUSTOM_MSG_TYPE_STATUS: // Nothing special, print status message normally - lcd_print(lcd_status_message); - break; - case CUSTOM_MSG_TYPE_MESHBL: // If mesh bed leveling in progress, show the status - if (custom_message_state > 10) - { - lcd_set_cursor(0, 3); - lcd_puts_P(PSTR(" ")); - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_CALIBRATE_Z_AUTO)); - lcd_puts_P(PSTR(" : ")); - lcd_print(custom_message_state-10); - } - else - { - if (custom_message_state == 3) - { - lcd_puts_P(_T(WELCOME_MSG)); - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = CUSTOM_MSG_TYPE_STATUS; - } - if (custom_message_state > 3 && custom_message_state <= 10 ) - { - lcd_set_cursor(0, 3); - lcd_puts_P(PSTR(" ")); - lcd_set_cursor(0, 3); - lcd_puts_P(_i("Calibration done"));////MSG_HOMEYZ_DONE c=0 r=0 - custom_message_state--; - } - } - break; - case CUSTOM_MSG_TYPE_F_LOAD: // If loading filament, print status - lcd_print(lcd_status_message); - break; - case CUSTOM_MSG_TYPE_PIDCAL: // PID tuning in progress - lcd_print(lcd_status_message); - if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0) - { - lcd_set_cursor(10, 3); - lcd_print(itostr3(pid_cycle)); - lcd_print('/'); - lcd_print(itostr3left(pid_number_of_cycles)); - } - break; - case CUSTOM_MSG_TYPE_TEMCAL: // PINDA temp calibration in progress - { - char progress[4]; - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_TEMP_CALIBRATION)); - lcd_set_cursor(12, 3); - sprintf(progress, "%d/6", custom_message_state); - lcd_print(progress); - } - break; - case CUSTOM_MSG_TYPE_TEMPRE: // temp compensation preheat - lcd_set_cursor(0, 3); - lcd_puts_P(_i("PINDA Heating"));////MSG_PINDA_PREHEAT c=20 r=1 - if (custom_message_state <= PINDA_HEAT_T) - { - lcd_puts_P(PSTR(": ")); - lcd_print(custom_message_state); //seconds - lcd_print(' '); - } - break; - } - } - // Fill the rest of line to have nice and clean output - for(int fillspace = 0; fillspace < 20; fillspace++) - if ((lcd_status_message[fillspace] <= 31 )) - lcd_print(' '); + for(int fillspace = 0; fillspace < 20; fillspace++) + if ((lcd_status_message[fillspace] <= 31 )) + lcd_print(' '); } void lcdui_print_status_screen(void) @@ -800,54 +800,54 @@ void lcdui_print_status_screen(void) lcd_set_cursor(0, 0); //line 0 //Print the hotend temperature (9 chars total) - lcdui_print_temp(LCD_STR_THERMOMETER[0], (int)(degHotend(0) + 0.5), (int)(degTargetHotend(0) + 0.5)); + lcdui_print_temp(LCD_STR_THERMOMETER[0], (int)(degHotend(0) + 0.5), (int)(degTargetHotend(0) + 0.5)); - lcd_space(3); //3 spaces + lcd_space(3); //3 spaces //Print Z-coordinate (8 chars total) - lcdui_print_Z_coord(); + lcdui_print_Z_coord(); lcd_set_cursor(0, 1); //line 1 - //Print the Bed temperature (9 chars total) - lcdui_print_temp(LCD_STR_BEDTEMP[0], (int)(degBed() + 0.5), (int)(degTargetBed() + 0.5)); + //Print the Bed temperature (9 chars total) + lcdui_print_temp(LCD_STR_BEDTEMP[0], (int)(degBed() + 0.5), (int)(degTargetBed() + 0.5)); - lcd_space(3); //3 spaces + lcd_space(3); //3 spaces #ifdef PLANNER_DIAGNOSTICS - //Print planner diagnostics (8 chars) - lcdui_print_planner_diag(); + //Print planner diagnostics (8 chars) + lcdui_print_planner_diag(); #else // PLANNER_DIAGNOSTICS //Print Feedrate (8 chars) - lcdui_print_feedrate(); + lcdui_print_feedrate(); #endif // PLANNER_DIAGNOSTICS - lcd_set_cursor(0, 2); //line 2 + lcd_set_cursor(0, 2); //line 2 - //Print SD status (7 chars) - lcdui_print_percent_done(); + //Print SD status (7 chars) + lcdui_print_percent_done(); - if (mmu_enabled) - //Print extruder status (5 chars) - lcdui_print_extruder(); - else if (farm_mode) - //Print farm number (5 chars) - lcdui_print_farm(); - else - lcd_space(5); //5 spaces + if (mmu_enabled) + //Print extruder status (5 chars) + lcdui_print_extruder(); + else if (farm_mode) + //Print farm number (5 chars) + lcdui_print_farm(); + else + lcd_space(5); //5 spaces #ifdef CMD_DIAGNOSTICS //Print cmd queue diagnostics (8chars) - lcdui_print_cmd_diag(); + lcdui_print_cmd_diag(); #else //Print time (8chars) - lcdui_print_time(); + lcdui_print_time(); #endif //CMD_DIAGNOSTICS lcd_set_cursor(0, 3); //line 3 #ifndef DEBUG_DISABLE_LCD_STATUS_LINE - lcdui_print_status_line(); + lcdui_print_status_line(); #endif //DEBUG_DISABLE_LCD_STATUS_LINE } @@ -855,425 +855,425 @@ void lcdui_print_status_screen(void) // 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 (firstrun == 1) - { - firstrun = 0; - if(lcd_status_message_level == 0) - { - strncpy_P(lcd_status_message, _T(WELCOME_MSG), LCD_WIDTH); - lcd_finishstatus(); - } - if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255) - { - eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); - eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); - } - } + if (firstrun == 1) + { + firstrun = 0; + if(lcd_status_message_level == 0) + { + strncpy_P(lcd_status_message, _T(WELCOME_MSG), LCD_WIDTH); + lcd_finishstatus(); + } + if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255) + { + eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0); + eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0); + } + } - if (lcd_status_update_delay) - lcd_status_update_delay--; - else - lcd_draw_update = 1; + if (lcd_status_update_delay) + lcd_status_update_delay--; + else + lcd_draw_update = 1; - if (lcd_draw_update) - { - ReInitLCD++; - if (ReInitLCD == 30) - { - lcd_refresh(); // to maybe revive the LCD if static electricity killed it. - ReInitLCD = 0 ; - } - else - { - if ((ReInitLCD % 10) == 0) - lcd_refresh_noclear(); //to maybe revive the LCD if static electricity killed it. - } + if (lcd_draw_update) + { + ReInitLCD++; + if (ReInitLCD == 30) + { + lcd_refresh(); // to maybe revive the LCD if static electricity killed it. + ReInitLCD = 0 ; + } + else + { + if ((ReInitLCD % 10) == 0) + lcd_refresh_noclear(); //to maybe revive the LCD if static electricity killed it. + } - lcdui_print_status_screen(); + lcdui_print_status_screen(); - if (farm_mode) - { - farm_timer--; - if (farm_timer < 1) - { - farm_timer = 10; - prusa_statistics(0); - } - switch (farm_timer) - { - case 8: - prusa_statistics(21); - break; - case 5: - if (IS_SD_PRINTING) - prusa_statistics(20); - break; - } - } // end of farm_mode + if (farm_mode) + { + farm_timer--; + if (farm_timer < 1) + { + farm_timer = 10; + prusa_statistics(0); + } + switch (farm_timer) + { + case 8: + prusa_statistics(21); + break; + case 5: + if (IS_SD_PRINTING) + prusa_statistics(20); + break; + } + } // end of farm_mode - lcd_status_update_delay = 10; /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */ - if (lcd_commands_type != LCD_COMMAND_IDLE) - lcd_commands(); - } // end of lcd_draw_update + lcd_status_update_delay = 10; /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */ + if (lcd_commands_type != LCD_COMMAND_IDLE) + lcd_commands(); + } // end of lcd_draw_update - bool current_click = LCD_CLICKED; + bool current_click = LCD_CLICKED; - if (ignore_click) - { - if (wait_for_unclick) - { - if (!current_click) - ignore_click = wait_for_unclick = false; - else - current_click = false; - } - else if (current_click) - { - lcd_quick_feedback(); - wait_for_unclick = true; - current_click = false; - } - } + if (ignore_click) + { + if (wait_for_unclick) + { + if (!current_click) + ignore_click = wait_for_unclick = false; + else + current_click = false; + } + else if (current_click) + { + lcd_quick_feedback(); + wait_for_unclick = true; + current_click = false; + } + } - if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes - { - menu_depth = 0; //redundant, as already done in lcd_return_to_status(), just to be sure - menu_submenu(lcd_main_menu); - lcd_refresh(); // to maybe revive the LCD if static electricity killed it. - } + if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes + { + menu_depth = 0; //redundant, as already done in lcd_return_to_status(), just to be sure + menu_submenu(lcd_main_menu); + lcd_refresh(); // to maybe revive the LCD if static electricity killed it. + } #ifdef ULTIPANEL_FEEDMULTIPLY - // Dead zone at 100% feedrate - if ((feedmultiply < 100 && (feedmultiply + int(lcd_encoder)) > 100) || - (feedmultiply > 100 && (feedmultiply + int(lcd_encoder)) < 100)) - { - lcd_encoder = 0; - feedmultiply = 100; - } - if (feedmultiply == 100 && int(lcd_encoder) > ENCODER_FEEDRATE_DEADZONE) - { - feedmultiply += int(lcd_encoder) - ENCODER_FEEDRATE_DEADZONE; - lcd_encoder = 0; - } - else if (feedmultiply == 100 && int(lcd_encoder) < -ENCODER_FEEDRATE_DEADZONE) - { - feedmultiply += int(lcd_encoder) + ENCODER_FEEDRATE_DEADZONE; - lcd_encoder = 0; - } - else if (feedmultiply != 100) - { - feedmultiply += int(lcd_encoder); - lcd_encoder = 0; - } + // Dead zone at 100% feedrate + if ((feedmultiply < 100 && (feedmultiply + int(lcd_encoder)) > 100) || + (feedmultiply > 100 && (feedmultiply + int(lcd_encoder)) < 100)) + { + lcd_encoder = 0; + feedmultiply = 100; + } + if (feedmultiply == 100 && int(lcd_encoder) > ENCODER_FEEDRATE_DEADZONE) + { + feedmultiply += int(lcd_encoder) - ENCODER_FEEDRATE_DEADZONE; + lcd_encoder = 0; + } + else if (feedmultiply == 100 && int(lcd_encoder) < -ENCODER_FEEDRATE_DEADZONE) + { + feedmultiply += int(lcd_encoder) + ENCODER_FEEDRATE_DEADZONE; + lcd_encoder = 0; + } + else if (feedmultiply != 100) + { + feedmultiply += int(lcd_encoder); + lcd_encoder = 0; + } #endif //ULTIPANEL_FEEDMULTIPLY - if (feedmultiply < 10) - feedmultiply = 10; - else if (feedmultiply > 999) - feedmultiply = 999; + if (feedmultiply < 10) + feedmultiply = 10; + else if (feedmultiply > 999) + feedmultiply = 999; } void lcd_commands() -{ - if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE) - { - if (!blocks_queued() && !homing_flag) - { - lcd_setstatuspgm(_i("Print paused"));////MSG_PRINT_PAUSED c=20 r=1 - long_pause(); - lcd_commands_type = 0; - lcd_commands_step = 0; - } - } +{ + if (lcd_commands_type == LCD_COMMAND_LONG_PAUSE) + { + if (!blocks_queued() && !homing_flag) + { + lcd_setstatuspgm(_i("Print paused"));////MSG_PRINT_PAUSED c=20 r=1 + long_pause(); + lcd_commands_type = 0; + lcd_commands_step = 0; + } + } #ifdef SNMM - if (lcd_commands_type == LCD_COMMAND_V2_CAL) - { - char cmd1[30]; - float width = 0.4; - float length = 20 - width; - float extr = count_e(0.2, width, length); - float extr_short_segment = count_e(0.2, width, width); - - if (lcd_commands_step>1) lcd_timeoutToStatus.start(); //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen - if (lcd_commands_step == 0) - { - lcd_commands_step = 10; - } - if (lcd_commands_step == 10 && !blocks_queued() && cmd_buffer_empty()) - { - enquecommand_P(PSTR("M107")); - enquecommand_P(PSTR("M104 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP))); - enquecommand_P(PSTR("M140 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); - enquecommand_P(PSTR("M190 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); - enquecommand_P(PSTR("M109 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP))); - enquecommand_P(PSTR("T0")); //RMM:TODO - enquecommand_P(_T(MSG_M117_V2_CALIBRATION)); - enquecommand_P(PSTR("G87")); //sets calibration status - enquecommand_P(PSTR("G28")); - enquecommand_P(PSTR("G21")); //set units to millimeters - enquecommand_P(PSTR("G90")); //use absolute coordinates - enquecommand_P(PSTR("M83")); //use relative distances for extrusion - enquecommand_P(PSTR("G92 E0")); - enquecommand_P(PSTR("M203 E100")); - enquecommand_P(PSTR("M92 E140")); - lcd_commands_step = 9; - } - if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - enquecommand_P(PSTR("G1 Z0.250 F7200.000")); - enquecommand_P(PSTR("G1 X50.0 E80.0 F1000.0")); - enquecommand_P(PSTR("G1 X160.0 E20.0 F1000.0")); - enquecommand_P(PSTR("G1 Z0.200 F7200.000")); - enquecommand_P(PSTR("G1 X220.0 E13 F1000.0")); - enquecommand_P(PSTR("G1 X240.0 E0 F1000.0")); - enquecommand_P(PSTR("G92 E0.0")); - enquecommand_P(PSTR("G21")); - enquecommand_P(PSTR("G90")); - enquecommand_P(PSTR("M83")); - enquecommand_P(PSTR("G1 E-4 F2100.00000")); - enquecommand_P(PSTR("G1 Z0.150 F7200.000")); - enquecommand_P(PSTR("M204 S1000")); - enquecommand_P(PSTR("G1 F4000")); - - lcd_clear(); - menu_goto(lcd_babystep_z, 0, false, true); - - - lcd_commands_step = 8; - } - if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty()) //draw meander - { - lcd_timeoutToStatus.start(); - - - enquecommand_P(PSTR("G1 X50 Y155")); - enquecommand_P(PSTR("G1 X60 Y155 E4")); - enquecommand_P(PSTR("G1 F1080")); - enquecommand_P(PSTR("G1 X75 Y155 E2.5")); - enquecommand_P(PSTR("G1 X100 Y155 E2")); - enquecommand_P(PSTR("G1 X200 Y155 E2.62773")); - enquecommand_P(PSTR("G1 X200 Y135 E0.66174")); - enquecommand_P(PSTR("G1 X50 Y135 E3.62773")); - enquecommand_P(PSTR("G1 X50 Y115 E0.49386")); - enquecommand_P(PSTR("G1 X200 Y115 E3.62773")); - enquecommand_P(PSTR("G1 X200 Y95 E0.49386")); - enquecommand_P(PSTR("G1 X50 Y95 E3.62773")); - enquecommand_P(PSTR("G1 X50 Y75 E0.49386")); - enquecommand_P(PSTR("G1 X200 Y75 E3.62773")); - enquecommand_P(PSTR("G1 X200 Y55 E0.49386")); - enquecommand_P(PSTR("G1 X50 Y55 E3.62773")); - - lcd_commands_step = 7; - } - - if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - strcpy(cmd1, "G1 X50 Y35 E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - - for (int i = 0; i < 4; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } - - lcd_commands_step = 6; - } + if (lcd_commands_type == LCD_COMMAND_V2_CAL) + { + char cmd1[30]; + float width = 0.4; + float length = 20 - width; + float extr = count_e(0.2, width, length); + float extr_short_segment = count_e(0.2, width, width); + + if (lcd_commands_step>1) lcd_timeoutToStatus.start(); //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen + if (lcd_commands_step == 0) + { + lcd_commands_step = 10; + } + if (lcd_commands_step == 10 && !blocks_queued() && cmd_buffer_empty()) + { + enquecommand_P(PSTR("M107")); + enquecommand_P(PSTR("M104 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP))); + enquecommand_P(PSTR("M140 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); + enquecommand_P(PSTR("M190 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); + enquecommand_P(PSTR("M109 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP))); + enquecommand_P(PSTR("T0")); //RMM:TODO + enquecommand_P(_T(MSG_M117_V2_CALIBRATION)); + enquecommand_P(PSTR("G87")); //sets calibration status + enquecommand_P(PSTR("G28")); + enquecommand_P(PSTR("G21")); //set units to millimeters + enquecommand_P(PSTR("G90")); //use absolute coordinates + enquecommand_P(PSTR("M83")); //use relative distances for extrusion + enquecommand_P(PSTR("G92 E0")); + enquecommand_P(PSTR("M203 E100")); + enquecommand_P(PSTR("M92 E140")); + lcd_commands_step = 9; + } + if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + enquecommand_P(PSTR("G1 Z0.250 F7200.000")); + enquecommand_P(PSTR("G1 X50.0 E80.0 F1000.0")); + enquecommand_P(PSTR("G1 X160.0 E20.0 F1000.0")); + enquecommand_P(PSTR("G1 Z0.200 F7200.000")); + enquecommand_P(PSTR("G1 X220.0 E13 F1000.0")); + enquecommand_P(PSTR("G1 X240.0 E0 F1000.0")); + enquecommand_P(PSTR("G92 E0.0")); + enquecommand_P(PSTR("G21")); + enquecommand_P(PSTR("G90")); + enquecommand_P(PSTR("M83")); + enquecommand_P(PSTR("G1 E-4 F2100.00000")); + enquecommand_P(PSTR("G1 Z0.150 F7200.000")); + enquecommand_P(PSTR("M204 S1000")); + enquecommand_P(PSTR("G1 F4000")); - if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - for (int i = 4; i < 8; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } + lcd_clear(); + menu_goto(lcd_babystep_z, 0, false, true); - lcd_commands_step = 5; - } - if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - for (int i = 8; i < 12; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } + lcd_commands_step = 8; + } + if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty()) //draw meander + { + lcd_timeoutToStatus.start(); + + + enquecommand_P(PSTR("G1 X50 Y155")); + enquecommand_P(PSTR("G1 X60 Y155 E4")); + enquecommand_P(PSTR("G1 F1080")); + enquecommand_P(PSTR("G1 X75 Y155 E2.5")); + enquecommand_P(PSTR("G1 X100 Y155 E2")); + enquecommand_P(PSTR("G1 X200 Y155 E2.62773")); + enquecommand_P(PSTR("G1 X200 Y135 E0.66174")); + enquecommand_P(PSTR("G1 X50 Y135 E3.62773")); + enquecommand_P(PSTR("G1 X50 Y115 E0.49386")); + enquecommand_P(PSTR("G1 X200 Y115 E3.62773")); + enquecommand_P(PSTR("G1 X200 Y95 E0.49386")); + enquecommand_P(PSTR("G1 X50 Y95 E3.62773")); + enquecommand_P(PSTR("G1 X50 Y75 E0.49386")); + enquecommand_P(PSTR("G1 X200 Y75 E3.62773")); + enquecommand_P(PSTR("G1 X200 Y55 E0.49386")); + enquecommand_P(PSTR("G1 X50 Y55 E3.62773")); + + lcd_commands_step = 7; + } - lcd_commands_step = 4; - } + if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + strcpy(cmd1, "G1 X50 Y35 E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + + for (int i = 0; i < 4; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } - if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - for (int i = 12; i < 16; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } + lcd_commands_step = 6; + } - lcd_commands_step = 3; - } + if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + for (int i = 4; i < 8; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } - if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - enquecommand_P(PSTR("G1 E-0.07500 F2100.00000")); - enquecommand_P(PSTR("G4 S0")); - enquecommand_P(PSTR("G1 E-4 F2100.00000")); - enquecommand_P(PSTR("G1 Z0.5 F7200.000")); - enquecommand_P(PSTR("G1 X245 Y1")); - enquecommand_P(PSTR("G1 X240 E4")); - enquecommand_P(PSTR("G1 F4000")); - enquecommand_P(PSTR("G1 X190 E2.7")); - enquecommand_P(PSTR("G1 F4600")); - enquecommand_P(PSTR("G1 X110 E2.8")); - enquecommand_P(PSTR("G1 F5200")); - enquecommand_P(PSTR("G1 X40 E3")); - enquecommand_P(PSTR("G1 E-15.0000 F5000")); - enquecommand_P(PSTR("G1 E-50.0000 F5400")); - enquecommand_P(PSTR("G1 E-15.0000 F3000")); - enquecommand_P(PSTR("G1 E-12.0000 F2000")); - enquecommand_P(PSTR("G1 F1600")); - - lcd_commands_step = 2; - } - if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - - enquecommand_P(PSTR("G1 X0 Y1 E3.0000")); - enquecommand_P(PSTR("G1 X50 Y1 E-5.0000")); - enquecommand_P(PSTR("G1 F2000")); - enquecommand_P(PSTR("G1 X0 Y1 E5.0000")); - enquecommand_P(PSTR("G1 X50 Y1 E-5.0000")); - enquecommand_P(PSTR("G1 F2400")); - enquecommand_P(PSTR("G1 X0 Y1 E5.0000")); - enquecommand_P(PSTR("G1 X50 Y1 E-5.0000")); - enquecommand_P(PSTR("G1 F2400")); - enquecommand_P(PSTR("G1 X0 Y1 E5.0000")); - enquecommand_P(PSTR("G1 X50 Y1 E-3.0000")); - enquecommand_P(PSTR("G4 S0")); - enquecommand_P(PSTR("M107")); - enquecommand_P(PSTR("M104 S0")); - enquecommand_P(PSTR("M140 S0")); - enquecommand_P(PSTR("G1 X10 Y180 F4000")); - enquecommand_P(PSTR("G1 Z10 F1300.000")); - enquecommand_P(PSTR("M84")); - - lcd_commands_step = 1; + lcd_commands_step = 5; + } - } + if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + for (int i = 8; i < 12; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } - if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_setstatuspgm(_T(WELCOME_MSG)); - lcd_commands_step = 0; - lcd_commands_type = 0; - if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) { - lcd_wizard(WizState::RepeatLay1Cal); - } - } + lcd_commands_step = 4; + } - } + if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + for (int i = 12; i < 16; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } + + lcd_commands_step = 3; + } + + if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + enquecommand_P(PSTR("G1 E-0.07500 F2100.00000")); + enquecommand_P(PSTR("G4 S0")); + enquecommand_P(PSTR("G1 E-4 F2100.00000")); + enquecommand_P(PSTR("G1 Z0.5 F7200.000")); + enquecommand_P(PSTR("G1 X245 Y1")); + enquecommand_P(PSTR("G1 X240 E4")); + enquecommand_P(PSTR("G1 F4000")); + enquecommand_P(PSTR("G1 X190 E2.7")); + enquecommand_P(PSTR("G1 F4600")); + enquecommand_P(PSTR("G1 X110 E2.8")); + enquecommand_P(PSTR("G1 F5200")); + enquecommand_P(PSTR("G1 X40 E3")); + enquecommand_P(PSTR("G1 E-15.0000 F5000")); + enquecommand_P(PSTR("G1 E-50.0000 F5400")); + enquecommand_P(PSTR("G1 E-15.0000 F3000")); + enquecommand_P(PSTR("G1 E-12.0000 F2000")); + enquecommand_P(PSTR("G1 F1600")); + + lcd_commands_step = 2; + } + if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + + enquecommand_P(PSTR("G1 X0 Y1 E3.0000")); + enquecommand_P(PSTR("G1 X50 Y1 E-5.0000")); + enquecommand_P(PSTR("G1 F2000")); + enquecommand_P(PSTR("G1 X0 Y1 E5.0000")); + enquecommand_P(PSTR("G1 X50 Y1 E-5.0000")); + enquecommand_P(PSTR("G1 F2400")); + enquecommand_P(PSTR("G1 X0 Y1 E5.0000")); + enquecommand_P(PSTR("G1 X50 Y1 E-5.0000")); + enquecommand_P(PSTR("G1 F2400")); + enquecommand_P(PSTR("G1 X0 Y1 E5.0000")); + enquecommand_P(PSTR("G1 X50 Y1 E-3.0000")); + enquecommand_P(PSTR("G4 S0")); + enquecommand_P(PSTR("M107")); + enquecommand_P(PSTR("M104 S0")); + enquecommand_P(PSTR("M140 S0")); + enquecommand_P(PSTR("G1 X10 Y180 F4000")); + enquecommand_P(PSTR("G1 Z10 F1300.000")); + enquecommand_P(PSTR("M84")); + + lcd_commands_step = 1; + + } + + if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_setstatuspgm(_T(WELCOME_MSG)); + lcd_commands_step = 0; + lcd_commands_type = 0; + if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) { + lcd_wizard(WizState::RepeatLay1Cal); + } + } + + } #else //if not SNMM - if (lcd_commands_type == LCD_COMMAND_V2_CAL) - { - char cmd1[30]; - static uint8_t filament = 0; - float width = 0.4; - float length = 20 - width; - float extr = count_e(0.2, width, length); - float extr_short_segment = count_e(0.2, width, width); - if(lcd_commands_step>1) lcd_timeoutToStatus.start(); //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen - - if (lcd_commands_step == 0 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_commands_step = 10; - } - if (lcd_commands_step == 20 && !blocks_queued() && cmd_buffer_empty()) - { + if (lcd_commands_type == LCD_COMMAND_V2_CAL) + { + char cmd1[30]; + static uint8_t filament = 0; + float width = 0.4; + float length = 20 - width; + float extr = count_e(0.2, width, length); + float extr_short_segment = count_e(0.2, width, width); + if(lcd_commands_step>1) lcd_timeoutToStatus.start(); //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen + + if (lcd_commands_step == 0 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_commands_step = 10; + } + if (lcd_commands_step == 20 && !blocks_queued() && cmd_buffer_empty()) + { filament = 0; lcd_commands_step = 10; - } + } if (lcd_commands_step == 21 && !blocks_queued() && cmd_buffer_empty()) { filament = 1; @@ -1295,19 +1295,19 @@ void lcd_commands() lcd_commands_step = 10; } - if (lcd_commands_step == 10) - { - enquecommand_P(PSTR("M107")); - enquecommand_P(PSTR("M104 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP))); - enquecommand_P(PSTR("M140 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); - enquecommand_P(PSTR("M190 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); + if (lcd_commands_step == 10) + { + enquecommand_P(PSTR("M107")); + enquecommand_P(PSTR("M104 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP))); + enquecommand_P(PSTR("M140 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); + enquecommand_P(PSTR("M190 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP))); enquecommand_P(PSTR("M109 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP))); - enquecommand_P(_T(MSG_M117_V2_CALIBRATION)); - enquecommand_P(PSTR("G28")); - enquecommand_P(PSTR("G92 E0.0")); + enquecommand_P(_T(MSG_M117_V2_CALIBRATION)); + enquecommand_P(PSTR("G28")); + enquecommand_P(PSTR("G92 E0.0")); lcd_commands_step = 9; - } + } if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty()) { lcd_clear(); @@ -1341,411 +1341,421 @@ void lcd_commands() lcd_commands_step = 8; } - if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty()) - { - - enquecommand_P(PSTR("G92 E0.0")); - enquecommand_P(PSTR("G21")); //set units to millimeters - enquecommand_P(PSTR("G90")); //use absolute coordinates - enquecommand_P(PSTR("M83")); //use relative distances for extrusion - enquecommand_P(PSTR("G1 E-1.50000 F2100.00000")); - enquecommand_P(PSTR("G1 Z5 F7200.000")); - enquecommand_P(PSTR("M204 S1000")); //set acceleration - enquecommand_P(PSTR("G1 F4000")); - lcd_commands_step = 7; - } - if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty()) //draw meander - { - lcd_timeoutToStatus.start(); - - - //just opposite direction - /*enquecommand_P(PSTR("G1 X50 Y55")); - enquecommand_P(PSTR("G1 F1080")); - enquecommand_P(PSTR("G1 X200 Y55 E3.62773")); - enquecommand_P(PSTR("G1 X200 Y75 E0.49386")); - enquecommand_P(PSTR("G1 X50 Y75 E3.62773")); - enquecommand_P(PSTR("G1 X50 Y95 E0.49386")); - enquecommand_P(PSTR("G1 X200 Y95 E3.62773")); - enquecommand_P(PSTR("G1 X200 Y115 E0.49386")); - enquecommand_P(PSTR("G1 X50 Y115 E3.62773")); - enquecommand_P(PSTR("G1 X50 Y135 E0.49386")); - enquecommand_P(PSTR("G1 X200 Y135 E3.62773")); - enquecommand_P(PSTR("G1 X200 Y155 E0.66174")); - enquecommand_P(PSTR("G1 X100 Y155 E2.62773")); - enquecommand_P(PSTR("G1 X75 Y155 E2")); - enquecommand_P(PSTR("G1 X50 Y155 E2.5")); - enquecommand_P(PSTR("G1 E - 0.07500 F2100.00000"));*/ - - - enquecommand_P(PSTR("G1 X50 Y155")); - enquecommand_P(PSTR("G1 Z0.150 F7200.000")); - enquecommand_P(PSTR("G1 F1080")); - enquecommand_P(PSTR("G1 X75 Y155 E2.5")); - enquecommand_P(PSTR("G1 X100 Y155 E2")); - enquecommand_P(PSTR("G1 X200 Y155 E2.62773")); - enquecommand_P(PSTR("G1 X200 Y135 E0.66174")); - enquecommand_P(PSTR("G1 X50 Y135 E3.62773")); - enquecommand_P(PSTR("G1 X50 Y115 E0.49386")); - enquecommand_P(PSTR("G1 X200 Y115 E3.62773")); - enquecommand_P(PSTR("G1 X200 Y95 E0.49386")); - enquecommand_P(PSTR("G1 X50 Y95 E3.62773")); - enquecommand_P(PSTR("G1 X50 Y75 E0.49386")); - enquecommand_P(PSTR("G1 X200 Y75 E3.62773")); - enquecommand_P(PSTR("G1 X200 Y55 E0.49386")); - enquecommand_P(PSTR("G1 X50 Y55 E3.62773")); - - strcpy(cmd1, "G1 X50 Y35 E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - - lcd_commands_step = 6; - } + if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty()) + { - if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty()) - { - - lcd_timeoutToStatus.start(); - - for (int i = 0; i < 4; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } + enquecommand_P(PSTR("G92 E0.0")); + enquecommand_P(PSTR("G21")); //set units to millimeters + enquecommand_P(PSTR("G90")); //use absolute coordinates + enquecommand_P(PSTR("M83")); //use relative distances for extrusion + enquecommand_P(PSTR("G1 E-1.50000 F2100.00000")); + enquecommand_P(PSTR("G1 Z5 F7200.000")); + enquecommand_P(PSTR("M204 S1000")); //set acceleration + enquecommand_P(PSTR("G1 F4000")); + lcd_commands_step = 7; + } + if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty()) //draw meander + { + lcd_timeoutToStatus.start(); + + + //just opposite direction + /*enquecommand_P(PSTR("G1 X50 Y55")); + enquecommand_P(PSTR("G1 F1080")); + enquecommand_P(PSTR("G1 X200 Y55 E3.62773")); + enquecommand_P(PSTR("G1 X200 Y75 E0.49386")); + enquecommand_P(PSTR("G1 X50 Y75 E3.62773")); + enquecommand_P(PSTR("G1 X50 Y95 E0.49386")); + enquecommand_P(PSTR("G1 X200 Y95 E3.62773")); + enquecommand_P(PSTR("G1 X200 Y115 E0.49386")); + enquecommand_P(PSTR("G1 X50 Y115 E3.62773")); + enquecommand_P(PSTR("G1 X50 Y135 E0.49386")); + enquecommand_P(PSTR("G1 X200 Y135 E3.62773")); + enquecommand_P(PSTR("G1 X200 Y155 E0.66174")); + enquecommand_P(PSTR("G1 X100 Y155 E2.62773")); + enquecommand_P(PSTR("G1 X75 Y155 E2")); + enquecommand_P(PSTR("G1 X50 Y155 E2.5")); + enquecommand_P(PSTR("G1 E - 0.07500 F2100.00000"));*/ + + + enquecommand_P(PSTR("G1 X50 Y155")); + enquecommand_P(PSTR("G1 Z0.150 F7200.000")); + enquecommand_P(PSTR("G1 F1080")); + enquecommand_P(PSTR("G1 X75 Y155 E2.5")); + enquecommand_P(PSTR("G1 X100 Y155 E2")); + enquecommand_P(PSTR("G1 X200 Y155 E2.62773")); + enquecommand_P(PSTR("G1 X200 Y135 E0.66174")); + enquecommand_P(PSTR("G1 X50 Y135 E3.62773")); + enquecommand_P(PSTR("G1 X50 Y115 E0.49386")); + enquecommand_P(PSTR("G1 X200 Y115 E3.62773")); + enquecommand_P(PSTR("G1 X200 Y95 E0.49386")); + enquecommand_P(PSTR("G1 X50 Y95 E3.62773")); + enquecommand_P(PSTR("G1 X50 Y75 E0.49386")); + enquecommand_P(PSTR("G1 X200 Y75 E3.62773")); + enquecommand_P(PSTR("G1 X200 Y55 E0.49386")); + enquecommand_P(PSTR("G1 X50 Y55 E3.62773")); + + strcpy(cmd1, "G1 X50 Y35 E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + + lcd_commands_step = 6; + } - lcd_commands_step = 5; - } + if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty()) + { - if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - for (int i = 4; i < 8; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } + lcd_timeoutToStatus.start(); - lcd_commands_step = 4; - } + for (int i = 0; i < 4; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } - if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - for (int i = 8; i < 12; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } + lcd_commands_step = 5; + } - lcd_commands_step = 3; - } + if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + for (int i = 4; i < 8; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } - if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - for (int i = 12; i < 16; i++) { - strcpy(cmd1, "G1 X70 Y"); - strcat(cmd1, ftostr32(35 - i*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - strcpy(cmd1, "G1 X50 Y"); - strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr)); - enquecommand(cmd1); - strcpy(cmd1, "G1 Y"); - strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); - strcat(cmd1, " E"); - strcat(cmd1, ftostr43(extr_short_segment)); - enquecommand(cmd1); - } + lcd_commands_step = 4; + } - lcd_commands_step = 2; - } + if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + for (int i = 8; i < 12; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } - if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_timeoutToStatus.start(); - enquecommand_P(PSTR("M107")); //turn off printer fan - enquecommand_P(PSTR("G1 E-0.07500 F2100.00000")); //retract - enquecommand_P(PSTR("M104 S0")); // turn off temperature - enquecommand_P(PSTR("M140 S0")); // turn off heatbed - enquecommand_P(PSTR("G1 Z10 F1300.000")); //lift Z - enquecommand_P(PSTR("G1 X10 Y180 F4000")); //Go to parking position - if (mmu_enabled) enquecommand_P(PSTR("M702 C")); //unload from nozzle - enquecommand_P(PSTR("M84"));// disable motors - forceMenuExpire = true; //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen - lcd_commands_step = 1; - } - if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty()) - { - lcd_setstatuspgm(_T(WELCOME_MSG)); - lcd_commands_step = 0; - lcd_commands_type = 0; - if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) { - lcd_wizard(WizState::RepeatLay1Cal); - } - } + lcd_commands_step = 3; + } - } + if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + for (int i = 12; i < 16; i++) { + strcpy(cmd1, "G1 X70 Y"); + strcat(cmd1, ftostr32(35 - i*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + strcpy(cmd1, "G1 X50 Y"); + strcat(cmd1, ftostr32(35 - (2 * i + 1)*width)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr)); + enquecommand(cmd1); + strcpy(cmd1, "G1 Y"); + strcat(cmd1, ftostr32(35 - (i + 1)*width * 2)); + strcat(cmd1, " E"); + strcat(cmd1, ftostr43(extr_short_segment)); + enquecommand(cmd1); + } + + lcd_commands_step = 2; + } + + if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_timeoutToStatus.start(); + enquecommand_P(PSTR("M107")); //turn off printer fan + enquecommand_P(PSTR("G1 E-0.07500 F2100.00000")); //retract + enquecommand_P(PSTR("M104 S0")); // turn off temperature + enquecommand_P(PSTR("M140 S0")); // turn off heatbed + enquecommand_P(PSTR("G1 Z10 F1300.000")); //lift Z + enquecommand_P(PSTR("G1 X10 Y180 F4000")); //Go to parking position + if (mmu_enabled) enquecommand_P(PSTR("M702 C")); //unload from nozzle + enquecommand_P(PSTR("M84"));// disable motors + forceMenuExpire = true; //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen + lcd_commands_step = 1; + } + if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty()) + { + lcd_setstatuspgm(_T(WELCOME_MSG)); + lcd_commands_step = 0; + lcd_commands_type = 0; + if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) { + lcd_wizard(WizState::RepeatLay1Cal); + } + } + + } #endif // not SNMM - if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) /// stop print - { - + if (lcd_commands_type == LCD_COMMAND_STOP_PRINT) /// stop print + { - if (lcd_commands_step == 0) - { - lcd_commands_step = 6; - } - if (lcd_commands_step == 1 && !blocks_queued()) - { - lcd_commands_step = 0; - lcd_commands_type = 0; - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = CUSTOM_MSG_TYPE_STATUS; - isPrintPaused = false; - } - if (lcd_commands_step == 2 && !blocks_queued()) - { - setTargetBed(0); - enquecommand_P(PSTR("M104 S0")); //set hotend temp to 0 + if (lcd_commands_step == 0) + { + lcd_commands_step = 6; + } - manage_heater(); - lcd_setstatuspgm(_T(WELCOME_MSG)); - cancel_heatup = false; - lcd_commands_step = 1; - } - if (lcd_commands_step == 3 && !blocks_queued()) - { - // M84: Disable steppers. - enquecommand_P(PSTR("M84")); - autotempShutdown(); - lcd_commands_step = 2; - } - if (lcd_commands_step == 4 && !blocks_queued()) - { - lcd_setstatuspgm(_T(MSG_PLEASE_WAIT)); - // G90: Absolute positioning. - enquecommand_P(PSTR("G90")); - // M83: Set extruder to relative mode. - enquecommand_P(PSTR("M83")); - #ifdef X_CANCEL_POS - enquecommand_P(PSTR("G1 X" STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000")); - #else - enquecommand_P(PSTR("G1 X50 Y" STRINGIFY(Y_MAX_POS) " E0 F7000")); - #endif - lcd_ignore_click(false); - if (mmu_enabled) - lcd_commands_step = 8; - else - lcd_commands_step = 3; - } - if (lcd_commands_step == 5 && !blocks_queued()) - { - lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); - // G91: Set to relative positioning. - enquecommand_P(PSTR("G91")); - // Lift up. - enquecommand_P(PSTR("G1 Z15 F1500")); - if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) lcd_commands_step = 4; - else lcd_commands_step = 3; - } - if (lcd_commands_step == 6 && !blocks_queued()) - { - lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); - cancel_heatup = true; - setTargetBed(0); - if (mmu_enabled) - setAllTargetHotends(0); - manage_heater(); - custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; - lcd_commands_step = 5; - } - if (lcd_commands_step == 7 && !blocks_queued()) - { - if (mmu_enabled) - enquecommand_P(PSTR("M702 C")); //current - else - switch(snmm_stop_print_menu()) - { - case 0: enquecommand_P(PSTR("M702")); break;//all - case 1: enquecommand_P(PSTR("M702 U")); break; //used - case 2: enquecommand_P(PSTR("M702 C")); break; //current - default: enquecommand_P(PSTR("M702")); break; - } - lcd_commands_step = 3; - } - if (lcd_commands_step == 8 && !blocks_queued()) { //step 8 is here for delay (going to next step after execution of all gcodes from step 4) - lcd_commands_step = 7; - } - } + if (lcd_commands_step == 1 && !blocks_queued()) + { + lcd_commands_step = 0; + lcd_commands_type = 0; + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = CUSTOM_MSG_TYPE_STATUS; + isPrintPaused = false; + } + if (lcd_commands_step == 2 && !blocks_queued()) + { + setTargetBed(0); + enquecommand_P(PSTR("M104 S0")); //set hotend temp to 0 - if (lcd_commands_type == 3) - { - lcd_commands_type = 0; - } + manage_heater(); + lcd_setstatuspgm(_T(WELCOME_MSG)); + cancel_heatup = false; + lcd_commands_step = 1; + } + if (lcd_commands_step == 3 && !blocks_queued()) + { + // M84: Disable steppers. + enquecommand_P(PSTR("M84")); + autotempShutdown(); + lcd_commands_step = 2; + } + if (lcd_commands_step == 4 && !blocks_queued()) + { + lcd_setstatuspgm(_T(MSG_PLEASE_WAIT)); + // G90: Absolute positioning. + enquecommand_P(PSTR("G90")); + // M83: Set extruder to relative mode. + enquecommand_P(PSTR("M83")); +#ifdef X_CANCEL_POS + enquecommand_P(PSTR("G1 X" STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000")); +#else + enquecommand_P(PSTR("G1 X50 Y" STRINGIFY(Y_MAX_POS) " E0 F7000")); +#endif + lcd_ignore_click(false); + if (mmu_enabled) + lcd_commands_step = 8; + else + lcd_commands_step = 3; + } + if (lcd_commands_step == 5 && !blocks_queued()) + { + lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); + // G91: Set to relative positioning. + enquecommand_P(PSTR("G91")); + // Lift up. + enquecommand_P(PSTR("G1 Z15 F1500")); + if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) lcd_commands_step = 4; + else lcd_commands_step = 3; + } + if (lcd_commands_step == 6 && !blocks_queued()) + { + lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); + cancel_heatup = true; + setTargetBed(0); + if (mmu_enabled) + setAllTargetHotends(0); + manage_heater(); + custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; + lcd_commands_step = 5; + } + if (lcd_commands_step == 7 && !blocks_queued()) + { + if (mmu_enabled) + enquecommand_P(PSTR("M702 C")); //current + else + switch(snmm_stop_print_menu()) + { + case 0: + enquecommand_P(PSTR("M702")); + break;//all + case 1: + enquecommand_P(PSTR("M702 U")); + break; //used + case 2: + enquecommand_P(PSTR("M702 C")); + break; //current + default: + enquecommand_P(PSTR("M702")); + break; + } + lcd_commands_step = 3; + } + if (lcd_commands_step == 8 && !blocks_queued()) { //step 8 is here for delay (going to next step after execution of all gcodes from step 4) + lcd_commands_step = 7; + } + } - if (lcd_commands_type == LCD_COMMAND_FARM_MODE_CONFIRM) /// farm mode confirm - { + if (lcd_commands_type == 3) + { + lcd_commands_type = 0; + } - if (lcd_commands_step == 0) { lcd_commands_step = 6; } + if (lcd_commands_type == LCD_COMMAND_FARM_MODE_CONFIRM) /// farm mode confirm + { - if (lcd_commands_step == 1 && !blocks_queued()) - { - lcd_confirm_print(); - lcd_commands_step = 0; - lcd_commands_type = 0; - } - if (lcd_commands_step == 2 && !blocks_queued()) - { - lcd_commands_step = 1; - } - if (lcd_commands_step == 3 && !blocks_queued()) - { - lcd_commands_step = 2; - } - if (lcd_commands_step == 4 && !blocks_queued()) - { - enquecommand_P(PSTR("G90")); - enquecommand_P(PSTR("G1 X" STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000")); - lcd_commands_step = 3; - } - if (lcd_commands_step == 5 && !blocks_queued()) - { - lcd_commands_step = 4; - } - if (lcd_commands_step == 6 && !blocks_queued()) - { - enquecommand_P(PSTR("G91")); - enquecommand_P(PSTR("G1 Z15 F1500")); - st_synchronize(); - #ifdef SNMM - lcd_commands_step = 7; - #else - lcd_commands_step = 5; - #endif - } + if (lcd_commands_step == 0) { + lcd_commands_step = 6; + } - } - if (lcd_commands_type == LCD_COMMAND_PID_EXTRUDER) { - char cmd1[30]; - - if (lcd_commands_step == 0) { - custom_message_type = CUSTOM_MSG_TYPE_PIDCAL; - custom_message_state = 1; - lcd_draw_update = 3; - lcd_commands_step = 3; - } - if (lcd_commands_step == 3 && !blocks_queued()) { //PID calibration - strcpy(cmd1, "M303 E0 S"); - strcat(cmd1, ftostr3(pid_temp)); - enquecommand(cmd1); - lcd_setstatuspgm(_i("PID cal. "));////MSG_PID_RUNNING c=20 r=1 - lcd_commands_step = 2; - } - if (lcd_commands_step == 2 && pid_tuning_finished) { //saving to eeprom - pid_tuning_finished = false; - custom_message_state = 0; - lcd_setstatuspgm(_i("PID cal. finished"));////MSG_PID_FINISHED c=20 r=1 - if (_Kp != 0 || _Ki != 0 || _Kd != 0) { - strcpy(cmd1, "M301 P"); - strcat(cmd1, ftostr32(_Kp)); - strcat(cmd1, " I"); - strcat(cmd1, ftostr32(_Ki)); - strcat(cmd1, " D"); - strcat(cmd1, ftostr32(_Kd)); - enquecommand(cmd1); - enquecommand_P(PSTR("M500")); - } - else { - SERIAL_ECHOPGM("Invalid PID cal. results. Not stored to EEPROM."); - } - display_time = millis(); - lcd_commands_step = 1; - } - if ((lcd_commands_step == 1) && ((millis()- display_time)>2000)) { //calibration finished message - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = CUSTOM_MSG_TYPE_STATUS; - pid_temp = DEFAULT_PID_TEMP; - lcd_commands_step = 0; - lcd_commands_type = 0; - } - } + if (lcd_commands_step == 1 && !blocks_queued()) + { + lcd_confirm_print(); + lcd_commands_step = 0; + lcd_commands_type = 0; + } + if (lcd_commands_step == 2 && !blocks_queued()) + { + lcd_commands_step = 1; + } + if (lcd_commands_step == 3 && !blocks_queued()) + { + lcd_commands_step = 2; + } + if (lcd_commands_step == 4 && !blocks_queued()) + { + enquecommand_P(PSTR("G90")); + enquecommand_P(PSTR("G1 X" STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000")); + lcd_commands_step = 3; + } + if (lcd_commands_step == 5 && !blocks_queued()) + { + lcd_commands_step = 4; + } + if (lcd_commands_step == 6 && !blocks_queued()) + { + enquecommand_P(PSTR("G91")); + enquecommand_P(PSTR("G1 Z15 F1500")); + st_synchronize(); +#ifdef SNMM + lcd_commands_step = 7; +#else + lcd_commands_step = 5; +#endif + } + + } + if (lcd_commands_type == LCD_COMMAND_PID_EXTRUDER) { + char cmd1[30]; + + if (lcd_commands_step == 0) { + custom_message_type = CUSTOM_MSG_TYPE_PIDCAL; + custom_message_state = 1; + lcd_draw_update = 3; + lcd_commands_step = 3; + } + if (lcd_commands_step == 3 && !blocks_queued()) { //PID calibration + strcpy(cmd1, "M303 E0 S"); + strcat(cmd1, ftostr3(pid_temp)); + enquecommand(cmd1); + lcd_setstatuspgm(_i("PID cal. "));////MSG_PID_RUNNING c=20 r=1 + lcd_commands_step = 2; + } + if (lcd_commands_step == 2 && pid_tuning_finished) { //saving to eeprom + pid_tuning_finished = false; + custom_message_state = 0; + lcd_setstatuspgm(_i("PID cal. finished"));////MSG_PID_FINISHED c=20 r=1 + if (_Kp != 0 || _Ki != 0 || _Kd != 0) { + strcpy(cmd1, "M301 P"); + strcat(cmd1, ftostr32(_Kp)); + strcat(cmd1, " I"); + strcat(cmd1, ftostr32(_Ki)); + strcat(cmd1, " D"); + strcat(cmd1, ftostr32(_Kd)); + enquecommand(cmd1); + enquecommand_P(PSTR("M500")); + } + else { + SERIAL_ECHOPGM("Invalid PID cal. results. Not stored to EEPROM."); + } + display_time = millis(); + lcd_commands_step = 1; + } + if ((lcd_commands_step == 1) && ((millis()- display_time)>2000)) { //calibration finished message + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = CUSTOM_MSG_TYPE_STATUS; + pid_temp = DEFAULT_PID_TEMP; + lcd_commands_step = 0; + lcd_commands_type = 0; + } + } } static float count_e(float layer_heigth, float extrusion_width, float extrusion_length) { - //returns filament length in mm which needs to be extrude to form line with extrusion_length * extrusion_width * layer heigth dimensions - float extr = extrusion_length * layer_heigth * extrusion_width / (M_PI * pow(1.75, 2) / 4); - return extr; + //returns filament length in mm which needs to be extrude to form line with extrusion_length * extrusion_width * layer heigth dimensions + float extr = extrusion_length * layer_heigth * extrusion_width / (M_PI * pow(1.75, 2) / 4); + return extr; } void lcd_return_to_status() { - lcd_refresh(); // to maybe revive the LCD if static electricity killed it. - menu_goto(lcd_status_screen, 0, false, true); - menu_depth = 0; + lcd_refresh(); // to maybe revive the LCD if static electricity killed it. + menu_goto(lcd_status_screen, 0, false, true); + menu_depth = 0; } //! @brief Pause print, disable nozzle heater, move to park position @@ -1771,89 +1781,89 @@ static void lcd_move_menu_axis(); void lcd_preheat_farm() { - setTargetHotend0(FARM_PREHEAT_HOTEND_TEMP); - setTargetBed(FARM_PREHEAT_HPB_TEMP); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer + setTargetHotend0(FARM_PREHEAT_HOTEND_TEMP); + setTargetBed(FARM_PREHEAT_HPB_TEMP); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer } void lcd_preheat_farm_nozzle() { - setTargetHotend0(FARM_PREHEAT_HOTEND_TEMP); - setTargetBed(0); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer + setTargetHotend0(FARM_PREHEAT_HOTEND_TEMP); + setTargetBed(0); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer } void lcd_preheat_pla() { - setTargetHotend0(PLA_PREHEAT_HOTEND_TEMP); - if (!wizard_active) setTargetBed(PLA_PREHEAT_HPB_TEMP); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer - if (wizard_active) lcd_wizard(WizState::Unload); + setTargetHotend0(PLA_PREHEAT_HOTEND_TEMP); + if (!wizard_active) setTargetBed(PLA_PREHEAT_HPB_TEMP); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer + if (wizard_active) lcd_wizard(WizState::Unload); } void lcd_preheat_abs() { - setTargetHotend0(ABS_PREHEAT_HOTEND_TEMP); - if (!wizard_active) setTargetBed(ABS_PREHEAT_HPB_TEMP); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer - if (wizard_active) lcd_wizard(WizState::Unload); + setTargetHotend0(ABS_PREHEAT_HOTEND_TEMP); + if (!wizard_active) setTargetBed(ABS_PREHEAT_HPB_TEMP); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer + if (wizard_active) lcd_wizard(WizState::Unload); } void lcd_preheat_pp() { - setTargetHotend0(PP_PREHEAT_HOTEND_TEMP); - if (!wizard_active) setTargetBed(PP_PREHEAT_HPB_TEMP); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer - if (wizard_active) lcd_wizard(WizState::Unload); + setTargetHotend0(PP_PREHEAT_HOTEND_TEMP); + if (!wizard_active) setTargetBed(PP_PREHEAT_HPB_TEMP); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer + if (wizard_active) lcd_wizard(WizState::Unload); } void lcd_preheat_pet() { - setTargetHotend0(PET_PREHEAT_HOTEND_TEMP); - if (!wizard_active) setTargetBed(PET_PREHEAT_HPB_TEMP); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer - if (wizard_active) lcd_wizard(WizState::Unload); + setTargetHotend0(PET_PREHEAT_HOTEND_TEMP); + if (!wizard_active) setTargetBed(PET_PREHEAT_HPB_TEMP); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer + if (wizard_active) lcd_wizard(WizState::Unload); } void lcd_preheat_hips() { - setTargetHotend0(HIPS_PREHEAT_HOTEND_TEMP); - if (!wizard_active) setTargetBed(HIPS_PREHEAT_HPB_TEMP); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer - if (wizard_active) lcd_wizard(WizState::Unload); + setTargetHotend0(HIPS_PREHEAT_HOTEND_TEMP); + if (!wizard_active) setTargetBed(HIPS_PREHEAT_HPB_TEMP); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer + if (wizard_active) lcd_wizard(WizState::Unload); } void lcd_preheat_flex() { - setTargetHotend0(FLEX_PREHEAT_HOTEND_TEMP); - if (!wizard_active) setTargetBed(FLEX_PREHEAT_HPB_TEMP); - fanSpeed = 0; - lcd_return_to_status(); - setWatch(); // heater sanity check timer - if (wizard_active) lcd_wizard(WizState::Unload); + setTargetHotend0(FLEX_PREHEAT_HOTEND_TEMP); + if (!wizard_active) setTargetBed(FLEX_PREHEAT_HPB_TEMP); + fanSpeed = 0; + lcd_return_to_status(); + setWatch(); // heater sanity check timer + if (wizard_active) lcd_wizard(WizState::Unload); } void lcd_cooldown() { - setAllTargetHotends(0); - setTargetBed(0); - fanSpeed = 0; - lcd_return_to_status(); + setAllTargetHotends(0); + setTargetBed(0); + fanSpeed = 0; + lcd_return_to_status(); } @@ -1865,24 +1875,24 @@ static void lcd_menu_extruder_info() //|Fil. Xd: Yd: | //|Int: Shut: | //---------------------- - int fan_speed_RPM[2]; - // Display Nozzle fan RPM - fan_speed_RPM[0] = 60*fan_speed[0]; - fan_speed_RPM[1] = 60*fan_speed[1]; - - lcd_timeoutToStatus.stop(); //infinite timeout - - lcd_printf_P(_N( - ESC_H(0,0) - "Nozzle FAN: %4d RPM\n" - "Print FAN: %4d RPM\n" - ), - fan_speed_RPM[0], - fan_speed_RPM[1] - ); + int fan_speed_RPM[2]; + // Display Nozzle fan RPM + fan_speed_RPM[0] = 60*fan_speed[0]; + fan_speed_RPM[1] = 60*fan_speed[1]; + + lcd_timeoutToStatus.stop(); //infinite timeout + + lcd_printf_P(_N( + ESC_H(0,0) + "Nozzle FAN: %4d RPM\n" + "Print FAN: %4d RPM\n" + ), + fan_speed_RPM[0], + fan_speed_RPM[1] + ); #ifdef FILAMENT_SENSOR - // Display X and Y difference from Filament sensor + // Display X and Y difference from Filament sensor // Display Light intensity from Filament sensor // Frame_Avg register represents the average brightness of all pixels within a frame (324 pixels). This // value ranges from 0(darkest) to 255(brightest). @@ -1890,25 +1900,25 @@ static void lcd_menu_extruder_info() // Shutter register is an index of LASER shutter time. It is automatically controlled by the chip's internal // auto-exposure algorithm. When the chip is tracking on a good reflection surface, the Shutter is small. // When the chip is tracking on a poor reflection surface, the Shutter is large. Value ranges from 0 to 46. - if (mmu_enabled == false) - { - if (!fsensor_enabled) - lcd_puts_P(_N("Filament sensor\n" "is disabled.")); - else - { - if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL)) - pat9125_update(); - lcd_printf_P(_N( - "Fil. Xd:%3d Yd:%3d\n" - "Int: %3d Shut: %3d" - ), - pat9125_x, pat9125_y, - pat9125_b, pat9125_s - ); - } - } + if (mmu_enabled == false) + { + if (!fsensor_enabled) + lcd_puts_P(_N("Filament sensor\n" "is disabled.")); + else + { + if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL)) + pat9125_update(); + lcd_printf_P(_N( + "Fil. Xd:%3d Yd:%3d\n" + "Int: %3d Shut: %3d" + ), + pat9125_x, pat9125_y, + pat9125_b, pat9125_s + ); + } + } #endif //FILAMENT_SENSOR - + menu_back_if_clicked(); } @@ -1921,13 +1931,13 @@ static void lcd_menu_fails_stats_total() // Filam. runouts 000 // Crash X 000 Y 000 ////////////////////// - lcd_timeoutToStatus.stop(); //infinite timeout + lcd_timeoutToStatus.stop(); //infinite timeout uint16_t power = eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT); uint16_t filam = eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT); uint16_t crashX = eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT); uint16_t crashY = eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT); - lcd_printf_P(PSTR(ESC_H(0,0) "Total failures" ESC_H(1,1) "Power failures %-3d" ESC_H(1,2) "Filam. runouts %-3d" ESC_H(1,3) "Crash X %-3d Y %-3d"), power, filam, crashX, crashY); - menu_back_if_clicked_fb(); + lcd_printf_P(PSTR(ESC_H(0,0) "Total failures" ESC_H(1,1) "Power failures %-3d" ESC_H(1,2) "Filam. runouts %-3d" ESC_H(1,3) "Crash X %-3d Y %-3d"), power, filam, crashX, crashY); + menu_back_if_clicked_fb(); } static void lcd_menu_fails_stats_print() @@ -1938,13 +1948,13 @@ static void lcd_menu_fails_stats_print() // Filam. runouts 000 // Crash X 000 Y 000 ////////////////////// - lcd_timeoutToStatus.stop(); //infinite timeout + lcd_timeoutToStatus.stop(); //infinite timeout uint8_t power = eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT); uint8_t filam = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT); uint8_t crashX = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X); uint8_t crashY = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y); - lcd_printf_P(PSTR(ESC_H(0,0) "Last print failures" ESC_H(1,1) "Power failures %-3d" ESC_H(1,2) "Filam. runouts %-3d" ESC_H(1,3) "Crash X %-3d Y %-3d"), power, filam, crashX, crashY); - menu_back_if_clicked_fb(); + lcd_printf_P(PSTR(ESC_H(0,0) "Last print failures" ESC_H(1,1) "Power failures %-3d" ESC_H(1,2) "Filam. runouts %-3d" ESC_H(1,3) "Crash X %-3d Y %-3d"), power, filam, crashX, crashY); + menu_back_if_clicked_fb(); } /** * @brief Open fail statistics menu @@ -1955,11 +1965,11 @@ static void lcd_menu_fails_stats_print() */ static void lcd_menu_fails_stats() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_SUBMENU_P(PSTR("Last print"), lcd_menu_fails_stats_print); - MENU_ITEM_SUBMENU_P(PSTR("Total"), lcd_menu_fails_stats_total); - MENU_END(); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_ITEM_SUBMENU_P(PSTR("Last print"), lcd_menu_fails_stats_print); + MENU_ITEM_SUBMENU_P(PSTR("Total"), lcd_menu_fails_stats_total); + MENU_END(); } #elif defined(FILAMENT_SENSOR) /** @@ -1979,7 +1989,7 @@ static void lcd_menu_fails_stats() */ static void lcd_menu_fails_stats() { - lcd_timeoutToStatus.stop(); //infinite timeout + lcd_timeoutToStatus.stop(); //infinite timeout uint8_t filamentLast = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT); uint16_t filamentTotal = eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT); lcd_printf_P(PSTR(ESC_H(0,0) "Last print failures" ESC_H(1,1) "Filam. runouts %-3d" ESC_H(0,2) "Total failures" ESC_H(1,3) "Filam. runouts %-3d"), filamentLast, filamentTotal); @@ -1988,10 +1998,10 @@ static void lcd_menu_fails_stats() #else static void lcd_menu_fails_stats() { - lcd_timeoutToStatus.stop(); //infinite timeout - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_END(); + lcd_timeoutToStatus.stop(); //infinite timeout + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_END(); } #endif //TMC2130 @@ -2006,22 +2016,22 @@ extern char* __malloc_heap_end; static void lcd_menu_debug() { #ifdef DEBUG_STACK_MONITOR - lcd_printf_P(PSTR(ESC_H(1,1) "RAM statistics" ESC_H(5,1) "SP_min: 0x%04x" ESC_H(1,2) "heap_start: 0x%04x" ESC_H(3,3) "heap_end: 0x%04x"), SP_min, __malloc_heap_start, __malloc_heap_end); + lcd_printf_P(PSTR(ESC_H(1,1) "RAM statistics" ESC_H(5,1) "SP_min: 0x%04x" ESC_H(1,2) "heap_start: 0x%04x" ESC_H(3,3) "heap_end: 0x%04x"), SP_min, __malloc_heap_start, __malloc_heap_end); #endif //DEBUG_STACK_MONITOR - menu_back_if_clicked_fb(); + menu_back_if_clicked_fb(); } #endif /* DEBUG_BUILD */ static void lcd_menu_temperatures() { - lcd_timeoutToStatus.stop(); //infinite timeout + lcd_timeoutToStatus.stop(); //infinite timeout - lcd_printf_P(PSTR(ESC_H(1,0) "Nozzle: %d%c" ESC_H(1,1) "Bed: %d%c"), (int)current_temperature[0], '\x01', (int)current_temperature_bed, '\x01'); + lcd_printf_P(PSTR(ESC_H(1,0) "Nozzle: %d%c" ESC_H(1,1) "Bed: %d%c"), (int)current_temperature[0], '\x01', (int)current_temperature_bed, '\x01'); #ifdef AMBIENT_THERMISTOR - lcd_printf_P(PSTR(ESC_H(1,2) "Ambient: %d%c" ESC_H(1,3) "PINDA: %d%c"), (int)current_temperature_ambient, '\x01', (int)current_temperature_pinda, '\x01'); + lcd_printf_P(PSTR(ESC_H(1,2) "Ambient: %d%c" ESC_H(1,3) "PINDA: %d%c"), (int)current_temperature_ambient, '\x01', (int)current_temperature_pinda, '\x01'); #else //AMBIENT_THERMISTOR - lcd_printf_P(PSTR(ESC_H(1,2) "PINDA: %d%c"), (int)current_temperature_pinda, '\x01'); + lcd_printf_P(PSTR(ESC_H(1,2) "PINDA: %d%c"), (int)current_temperature_pinda, '\x01'); #endif //AMBIENT_THERMISTOR menu_back_if_clicked(); @@ -2034,10 +2044,10 @@ static void lcd_menu_temperatures() #define VOLT_DIV_REF 5 static void lcd_menu_voltages() { - lcd_timeoutToStatus.stop(); //infinite timeout - float volt_pwr = VOLT_DIV_REF * ((float)current_voltage_raw_pwr / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC; - float volt_bed = VOLT_DIV_REF * ((float)current_voltage_raw_bed / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC; - lcd_printf_P(PSTR(ESC_H(1,1)"PWR: %d.%01dV" ESC_H(1,2)"BED: %d.%01dV"), (int)volt_pwr, (int)(10*fabs(volt_pwr - (int)volt_pwr)), (int)volt_bed, (int)(10*fabs(volt_bed - (int)volt_bed))); + lcd_timeoutToStatus.stop(); //infinite timeout + float volt_pwr = VOLT_DIV_REF * ((float)current_voltage_raw_pwr / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC; + float volt_bed = VOLT_DIV_REF * ((float)current_voltage_raw_bed / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC; + lcd_printf_P(PSTR(ESC_H(1,1)"PWR: %d.%01dV" ESC_H(1,2)"BED: %d.%01dV"), (int)volt_pwr, (int)(10*fabs(volt_pwr - (int)volt_pwr)), (int)volt_bed, (int)(10*fabs(volt_bed - (int)volt_bed))); menu_back_if_clicked(); } #endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN @@ -2050,265 +2060,265 @@ static void lcd_menu_belt_status() } #endif //TMC2130 -#ifdef RESUME_DEBUG +#ifdef RESUME_DEBUG extern void stop_and_save_print_to_ram(float z_move, float e_move); extern void restore_print_from_ram_and_continue(float e_move); static void lcd_menu_test_save() { - stop_and_save_print_to_ram(10, -0.8); + stop_and_save_print_to_ram(10, -0.8); } static void lcd_menu_test_restore() { - restore_print_from_ram_and_continue(0.8); + restore_print_from_ram_and_continue(0.8); } #endif //RESUME_DEBUG static void lcd_preheat_menu() { - MENU_BEGIN(); + MENU_BEGIN(); + + if (!wizard_active) MENU_ITEM_BACK_P(_T(MSG_MAIN)); - if (!wizard_active) MENU_ITEM_BACK_P(_T(MSG_MAIN)); + if (farm_mode) { + MENU_ITEM_FUNCTION_P(PSTR("farm - " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FARM_PREHEAT_HPB_TEMP)), lcd_preheat_farm); + MENU_ITEM_FUNCTION_P(PSTR("nozzle - " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/0"), lcd_preheat_farm_nozzle); + MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown); + MENU_ITEM_FUNCTION_P(PSTR("ABS - " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)), lcd_preheat_abs); + } else { + MENU_ITEM_FUNCTION_P(PSTR("PLA - " STRINGIFY(PLA_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PLA_PREHEAT_HPB_TEMP)), lcd_preheat_pla); + MENU_ITEM_FUNCTION_P(PSTR("PET - " STRINGIFY(PET_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PET_PREHEAT_HPB_TEMP)), lcd_preheat_pet); + MENU_ITEM_FUNCTION_P(PSTR("ABS - " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)), lcd_preheat_abs); + MENU_ITEM_FUNCTION_P(PSTR("HIPS - " STRINGIFY(HIPS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(HIPS_PREHEAT_HPB_TEMP)), lcd_preheat_hips); + MENU_ITEM_FUNCTION_P(PSTR("PP - " STRINGIFY(PP_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PP_PREHEAT_HPB_TEMP)), lcd_preheat_pp); + MENU_ITEM_FUNCTION_P(PSTR("FLEX - " STRINGIFY(FLEX_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FLEX_PREHEAT_HPB_TEMP)), lcd_preheat_flex); + if (!wizard_active) MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown); + } - if (farm_mode) { - MENU_ITEM_FUNCTION_P(PSTR("farm - " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FARM_PREHEAT_HPB_TEMP)), lcd_preheat_farm); - MENU_ITEM_FUNCTION_P(PSTR("nozzle - " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/0"), lcd_preheat_farm_nozzle); - MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown); - MENU_ITEM_FUNCTION_P(PSTR("ABS - " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)), lcd_preheat_abs); - } else { - MENU_ITEM_FUNCTION_P(PSTR("PLA - " STRINGIFY(PLA_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PLA_PREHEAT_HPB_TEMP)), lcd_preheat_pla); - MENU_ITEM_FUNCTION_P(PSTR("PET - " STRINGIFY(PET_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PET_PREHEAT_HPB_TEMP)), lcd_preheat_pet); - MENU_ITEM_FUNCTION_P(PSTR("ABS - " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)), lcd_preheat_abs); - MENU_ITEM_FUNCTION_P(PSTR("HIPS - " STRINGIFY(HIPS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(HIPS_PREHEAT_HPB_TEMP)), lcd_preheat_hips); - MENU_ITEM_FUNCTION_P(PSTR("PP - " STRINGIFY(PP_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PP_PREHEAT_HPB_TEMP)), lcd_preheat_pp); - MENU_ITEM_FUNCTION_P(PSTR("FLEX - " STRINGIFY(FLEX_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FLEX_PREHEAT_HPB_TEMP)), lcd_preheat_flex); - if (!wizard_active) MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown); - } - - MENU_END(); + MENU_END(); } static void lcd_support_menu() { - typedef struct - { // 22bytes total - int8_t status; // 1byte - bool is_flash_air; // 1byte - uint8_t ip[4]; // 4bytes - char ip_str[3*4+3+1]; // 16bytes - } _menu_data_t; + typedef struct + { // 22bytes total + int8_t status; // 1byte + bool is_flash_air; // 1byte + uint8_t ip[4]; // 4bytes + char ip_str[3*4+3+1]; // 16bytes + } _menu_data_t; static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data"); - _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); + _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); if (_md->status == 0 || lcd_draw_update == 2) - { + { // Menu was entered or SD card status has changed (plugged in or removed). // Initialize its status. _md->status = 1; _md->is_flash_air = card.ToshibaFlashAir_isEnabled() && card.ToshibaFlashAir_GetIP(_md->ip); if (_md->is_flash_air) - sprintf_P(_md->ip_str, PSTR("%d.%d.%d.%d"), - _md->ip[0], _md->ip[1], - _md->ip[2], _md->ip[3]); - } else if (_md->is_flash_air && - _md->ip[0] == 0 && _md->ip[1] == 0 && - _md->ip[2] == 0 && _md->ip[3] == 0 && - ++ _md->status == 16) - { + sprintf_P(_md->ip_str, PSTR("%d.%d.%d.%d"), + _md->ip[0], _md->ip[1], + _md->ip[2], _md->ip[3]); + } else if (_md->is_flash_air && + _md->ip[0] == 0 && _md->ip[1] == 0 && + _md->ip[2] == 0 && _md->ip[3] == 0 && + ++ _md->status == 16) + { // Waiting for the FlashAir card to get an IP address from a router. Force an update. _md->status = 0; } - MENU_BEGIN(); + MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_BACK_P(PSTR("Firmware:")); - MENU_ITEM_BACK_P(PSTR(" " FW_VERSION_FULL)); + MENU_ITEM_BACK_P(PSTR("Firmware:")); + MENU_ITEM_BACK_P(PSTR(" " FW_VERSION_FULL)); #if (FW_DEV_VERSION != FW_VERSION_GOLD) && (FW_DEV_VERSION != FW_VERSION_RC) - MENU_ITEM_BACK_P(PSTR(" repo " FW_REPOSITORY)); + MENU_ITEM_BACK_P(PSTR(" repo " FW_REPOSITORY)); #endif - // Ideally this block would be optimized out by the compiler. -/* const uint8_t fw_string_len = strlen_P(FW_VERSION_STR_P()); - if (fw_string_len < 6) { - MENU_ITEM_BACK_P(PSTR(MSG_FW_VERSION " - " FW_version)); - } else { - MENU_ITEM_BACK_P(PSTR("FW - " FW_version)); - }*/ - - MENU_ITEM_BACK_P(_i("prusa3d.com"));////MSG_PRUSA3D c=0 r=0 - MENU_ITEM_BACK_P(_i("forum.prusa3d.com"));////MSG_PRUSA3D_FORUM c=0 r=0 - MENU_ITEM_BACK_P(_i("howto.prusa3d.com"));////MSG_PRUSA3D_HOWTO c=0 r=0 - MENU_ITEM_BACK_P(STR_SEPARATOR); - MENU_ITEM_BACK_P(PSTR(FILAMENT_SIZE)); - MENU_ITEM_BACK_P(PSTR(ELECTRONICS)); - MENU_ITEM_BACK_P(PSTR(NOZZLE_TYPE)); - MENU_ITEM_BACK_P(STR_SEPARATOR); - MENU_ITEM_BACK_P(_i("Date:"));////MSG_DATE c=17 r=1 - MENU_ITEM_BACK_P(PSTR(__DATE__)); - - MENU_ITEM_BACK_P(STR_SEPARATOR); - if (mmu_enabled) - { - MENU_ITEM_BACK_P(PSTR("MMU2 connected")); - MENU_ITEM_BACK_P(PSTR(" FW:")); - if (((menu_item - 1) == menu_line) && lcd_draw_update) - { - lcd_set_cursor(6, menu_row); - if ((mmu_version > 0) && (mmu_buildnr > 0)) - lcd_printf_P(PSTR("%d.%d.%d-%d"), mmu_version/100, mmu_version%100/10, mmu_version%10, mmu_buildnr); - else - lcd_puts_P(PSTR("unknown")); - } - } - else - MENU_ITEM_BACK_P(PSTR("MMU2 N/A")); + // Ideally this block would be optimized out by the compiler. + /* const uint8_t fw_string_len = strlen_P(FW_VERSION_STR_P()); + if (fw_string_len < 6) { + MENU_ITEM_BACK_P(PSTR(MSG_FW_VERSION " - " FW_version)); + } else { + MENU_ITEM_BACK_P(PSTR("FW - " FW_version)); + }*/ + + MENU_ITEM_BACK_P(_i("prusa3d.com"));////MSG_PRUSA3D c=0 r=0 + MENU_ITEM_BACK_P(_i("forum.prusa3d.com"));////MSG_PRUSA3D_FORUM c=0 r=0 + MENU_ITEM_BACK_P(_i("howto.prusa3d.com"));////MSG_PRUSA3D_HOWTO c=0 r=0 + MENU_ITEM_BACK_P(STR_SEPARATOR); + MENU_ITEM_BACK_P(PSTR(FILAMENT_SIZE)); + MENU_ITEM_BACK_P(PSTR(ELECTRONICS)); + MENU_ITEM_BACK_P(PSTR(NOZZLE_TYPE)); + MENU_ITEM_BACK_P(STR_SEPARATOR); + MENU_ITEM_BACK_P(_i("Date:"));////MSG_DATE c=17 r=1 + MENU_ITEM_BACK_P(PSTR(__DATE__)); + + MENU_ITEM_BACK_P(STR_SEPARATOR); + if (mmu_enabled) + { + MENU_ITEM_BACK_P(PSTR("MMU2 connected")); + MENU_ITEM_BACK_P(PSTR(" FW:")); + if (((menu_item - 1) == menu_line) && lcd_draw_update) + { + lcd_set_cursor(6, menu_row); + if ((mmu_version > 0) && (mmu_buildnr > 0)) + lcd_printf_P(PSTR("%d.%d.%d-%d"), mmu_version/100, mmu_version%100/10, mmu_version%10, mmu_buildnr); + else + lcd_puts_P(PSTR("unknown")); + } + } + else + MENU_ITEM_BACK_P(PSTR("MMU2 N/A")); - // Show the FlashAir IP address, if the card is available. - if (_md->is_flash_air) { - MENU_ITEM_BACK_P(STR_SEPARATOR); - MENU_ITEM_BACK_P(PSTR("FlashAir IP Addr:")); + // Show the FlashAir IP address, if the card is available. + if (_md->is_flash_air) { + MENU_ITEM_BACK_P(STR_SEPARATOR); + MENU_ITEM_BACK_P(PSTR("FlashAir IP Addr:")); ///! MENU_ITEM(back_RAM, _md->ip_str, 0); - } + } - #ifndef MK1BP - MENU_ITEM_BACK_P(STR_SEPARATOR); - MENU_ITEM_SUBMENU_P(_i("XYZ cal. details"), lcd_menu_xyz_y_min);////MSG_XYZ_DETAILS c=19 r=1 - MENU_ITEM_SUBMENU_P(_i("Extruder info"), lcd_menu_extruder_info);////MSG_INFO_EXTRUDER c=15 r=1 +#ifndef MK1BP + MENU_ITEM_BACK_P(STR_SEPARATOR); + MENU_ITEM_SUBMENU_P(_i("XYZ cal. details"), lcd_menu_xyz_y_min);////MSG_XYZ_DETAILS c=19 r=1 + MENU_ITEM_SUBMENU_P(_i("Extruder info"), lcd_menu_extruder_info);////MSG_INFO_EXTRUDER c=15 r=1 #ifdef TMC2130 - MENU_ITEM_SUBMENU_P(_i("Belt status"), lcd_menu_belt_status);////MSG_MENU_BELT_STATUS c=15 r=1 + MENU_ITEM_SUBMENU_P(_i("Belt status"), lcd_menu_belt_status);////MSG_MENU_BELT_STATUS c=15 r=1 #endif //TMC2130 - - MENU_ITEM_SUBMENU_P(_i("Temperatures"), lcd_menu_temperatures);////MSG_MENU_TEMPERATURES c=15 r=1 + + MENU_ITEM_SUBMENU_P(_i("Temperatures"), lcd_menu_temperatures);////MSG_MENU_TEMPERATURES c=15 r=1 #if defined (VOLT_BED_PIN) || defined (VOLT_PWR_PIN) - MENU_ITEM_SUBMENU_P(_i("Voltages"), lcd_menu_voltages);////MSG_MENU_VOLTAGES c=15 r=1 + MENU_ITEM_SUBMENU_P(_i("Voltages"), lcd_menu_voltages);////MSG_MENU_VOLTAGES c=15 r=1 #endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN #ifdef DEBUG_BUILD - MENU_ITEM_SUBMENU_P(PSTR("Debug"), lcd_menu_debug); + MENU_ITEM_SUBMENU_P(PSTR("Debug"), lcd_menu_debug); #endif /* DEBUG_BUILD */ - #endif //MK1BP +#endif //MK1BP - MENU_END(); + MENU_END(); } void lcd_set_fan_check() { - fans_check_enabled = !fans_check_enabled; - eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED, fans_check_enabled); + fans_check_enabled = !fans_check_enabled; + eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED, fans_check_enabled); } void lcd_set_filament_autoload() { - fsensor_autoload_set(!fsensor_autoload_enabled); + fsensor_autoload_set(!fsensor_autoload_enabled); } void lcd_set_filament_oq_meass() { - fsensor_oq_meassure_set(!fsensor_oq_meassure_enabled); + fsensor_oq_meassure_set(!fsensor_oq_meassure_enabled); } void lcd_unLoadFilament() { - if (degHotend0() > EXTRUDE_MINTEMP) { - - enquecommand_P(PSTR("M702")); //unload filament + if (degHotend0() > EXTRUDE_MINTEMP) { + + enquecommand_P(PSTR("M702")); //unload filament - } else { - show_preheat_nozzle_warning(); - } + } else { + show_preheat_nozzle_warning(); + } - menu_back(); + menu_back(); } void lcd_wait_interact() { - lcd_clear(); + lcd_clear(); - lcd_set_cursor(0, 1); -#ifdef SNMM - lcd_puts_P(_i("Prepare new filament"));////MSG_PREPARE_FILAMENT c=20 r=1 + lcd_set_cursor(0, 1); +#ifdef SNMM + lcd_puts_P(_i("Prepare new filament"));////MSG_PREPARE_FILAMENT c=20 r=1 #else - lcd_puts_P(_i("Insert filament"));////MSG_INSERT_FILAMENT c=20 r=0 + lcd_puts_P(_i("Insert filament"));////MSG_INSERT_FILAMENT c=20 r=0 #endif - lcd_set_cursor(0, 2); - lcd_puts_P(_i("and press the knob"));////MSG_PRESS c=20 r=0 + lcd_set_cursor(0, 2); + lcd_puts_P(_i("and press the knob"));////MSG_PRESS c=20 r=0 } void lcd_change_success() { - lcd_clear(); + lcd_clear(); - lcd_set_cursor(0, 2); + lcd_set_cursor(0, 2); - lcd_puts_P(_i("Change success!"));////MSG_CHANGE_SUCCESS c=0 r=0 + lcd_puts_P(_i("Change success!"));////MSG_CHANGE_SUCCESS c=0 r=0 } -static void lcd_loading_progress_bar(uint16_t loading_time_ms) { - - for (int i = 0; i < 20; i++) { - lcd_set_cursor(i, 3); - lcd_print("."); - //loading_time_ms/20 delay - for (int j = 0; j < 5; j++) { - delay_keep_alive(loading_time_ms / 100); - } - } +static void lcd_loading_progress_bar(uint16_t loading_time_ms) { + + for (int i = 0; i < 20; i++) { + lcd_set_cursor(i, 3); + lcd_print("."); + //loading_time_ms/20 delay + for (int j = 0; j < 5; j++) { + delay_keep_alive(loading_time_ms / 100); + } + } } void lcd_loading_color() { - //we are extruding 25mm with feedrate 200mm/min -> 7.5 seconds for whole action, 0.375 s for one character + //we are extruding 25mm with feedrate 200mm/min -> 7.5 seconds for whole action, 0.375 s for one character - lcd_clear(); + lcd_clear(); - lcd_set_cursor(0, 0); + lcd_set_cursor(0, 0); - lcd_puts_P(_i("Loading color"));////MSG_LOADING_COLOR c=0 r=0 - lcd_set_cursor(0, 2); - lcd_puts_P(_T(MSG_PLEASE_WAIT)); - lcd_loading_progress_bar((FILAMENTCHANGE_FINALFEED * 1000ul) / FILAMENTCHANGE_EFEED_FINAL); //show progress bar during filament loading slow sequence + lcd_puts_P(_i("Loading color"));////MSG_LOADING_COLOR c=0 r=0 + lcd_set_cursor(0, 2); + lcd_puts_P(_T(MSG_PLEASE_WAIT)); + lcd_loading_progress_bar((FILAMENTCHANGE_FINALFEED * 1000ul) / FILAMENTCHANGE_EFEED_FINAL); //show progress bar during filament loading slow sequence } void lcd_loading_filament() { - lcd_clear(); + lcd_clear(); - lcd_set_cursor(0, 0); + lcd_set_cursor(0, 0); - lcd_puts_P(_T(MSG_LOADING_FILAMENT)); - lcd_set_cursor(0, 2); - lcd_puts_P(_T(MSG_PLEASE_WAIT)); + lcd_puts_P(_T(MSG_LOADING_FILAMENT)); + lcd_set_cursor(0, 2); + lcd_puts_P(_T(MSG_PLEASE_WAIT)); #ifdef SNMM - for (int i = 0; i < 20; i++) { + for (int i = 0; i < 20; i++) { - lcd_set_cursor(i, 3); - lcd_print("."); - for (int j = 0; j < 10 ; j++) { - manage_heater(); - manage_inactivity(true); + lcd_set_cursor(i, 3); + lcd_print("."); + for (int j = 0; j < 10 ; j++) { + manage_heater(); + manage_inactivity(true); - delay(153); - } + delay(153); + } - } + } #else //SNMM - uint16_t slow_seq_time = (FILAMENTCHANGE_FINALFEED * 1000ul) / FILAMENTCHANGE_EFEED_FINAL; - uint16_t fast_seq_time = (FILAMENTCHANGE_FIRSTFEED * 1000ul) / FILAMENTCHANGE_EFEED_FIRST; - lcd_loading_progress_bar(slow_seq_time + fast_seq_time); //show progress bar for total time of filament loading fast + slow sequence + uint16_t slow_seq_time = (FILAMENTCHANGE_FINALFEED * 1000ul) / FILAMENTCHANGE_EFEED_FINAL; + uint16_t fast_seq_time = (FILAMENTCHANGE_FIRSTFEED * 1000ul) / FILAMENTCHANGE_EFEED_FIRST; + lcd_loading_progress_bar(slow_seq_time + fast_seq_time); //show progress bar for total time of filament loading fast + slow sequence #endif //SNMM } @@ -2316,95 +2326,95 @@ void lcd_loading_filament() { void lcd_alright() { - int enc_dif = 0; - int cursor_pos = 1; + int enc_dif = 0; + int cursor_pos = 1; - lcd_clear(); + lcd_clear(); - lcd_set_cursor(0, 0); + lcd_set_cursor(0, 0); - lcd_puts_P(_i("Changed correctly?"));////MSG_CORRECTLY c=20 r=0 + lcd_puts_P(_i("Changed correctly?"));////MSG_CORRECTLY c=20 r=0 - lcd_set_cursor(1, 1); + lcd_set_cursor(1, 1); - lcd_puts_P(_T(MSG_YES)); + lcd_puts_P(_T(MSG_YES)); - lcd_set_cursor(1, 2); + lcd_set_cursor(1, 2); - lcd_puts_P(_i("Filament not loaded"));////MSG_NOT_LOADED c=19 r=0 + lcd_puts_P(_i("Filament not loaded"));////MSG_NOT_LOADED c=19 r=0 - lcd_set_cursor(1, 3); - lcd_puts_P(_i("Color not correct"));////MSG_NOT_COLOR c=0 r=0 + lcd_set_cursor(1, 3); + lcd_puts_P(_i("Color not correct"));////MSG_NOT_COLOR c=0 r=0 - lcd_set_cursor(0, 1); + lcd_set_cursor(0, 1); - lcd_print(">"); + lcd_print(">"); - enc_dif = lcd_encoder_diff; + enc_dif = lcd_encoder_diff; - while (lcd_change_fil_state == 0) { + while (lcd_change_fil_state == 0) { - manage_heater(); - manage_inactivity(true); + manage_heater(); + manage_inactivity(true); - if ( abs((enc_dif - lcd_encoder_diff)) > 4 ) { + if ( abs((enc_dif - lcd_encoder_diff)) > 4 ) { - if ( (abs(enc_dif - lcd_encoder_diff)) > 1 ) { - if (enc_dif > lcd_encoder_diff ) { - cursor_pos --; - } + if ( (abs(enc_dif - lcd_encoder_diff)) > 1 ) { + if (enc_dif > lcd_encoder_diff ) { + cursor_pos --; + } - if (enc_dif < lcd_encoder_diff ) { - cursor_pos ++; - } + if (enc_dif < lcd_encoder_diff ) { + cursor_pos ++; + } - if (cursor_pos > 3) { - cursor_pos = 3; - } + if (cursor_pos > 3) { + cursor_pos = 3; + } - if (cursor_pos < 1) { - cursor_pos = 1; - } - lcd_set_cursor(0, 1); - lcd_print(" "); - lcd_set_cursor(0, 2); - lcd_print(" "); - lcd_set_cursor(0, 3); - lcd_print(" "); - lcd_set_cursor(0, cursor_pos); - lcd_print(">"); - enc_dif = lcd_encoder_diff; - delay(100); - } + if (cursor_pos < 1) { + cursor_pos = 1; + } + lcd_set_cursor(0, 1); + lcd_print(" "); + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); + lcd_set_cursor(0, cursor_pos); + lcd_print(">"); + enc_dif = lcd_encoder_diff; + delay(100); + } - } + } - if (lcd_clicked()) { + if (lcd_clicked()) { - lcd_change_fil_state = cursor_pos; - delay(500); + lcd_change_fil_state = cursor_pos; + delay(500); - } + } - }; + }; - lcd_clear(); - lcd_return_to_status(); + lcd_clear(); + lcd_return_to_status(); } void show_preheat_nozzle_warning() -{ +{ lcd_clear(); lcd_set_cursor(0, 0); lcd_puts_P(_T(MSG_ERROR)); @@ -2416,14 +2426,14 @@ void show_preheat_nozzle_warning() void lcd_load_filament_color_check() { - bool clean = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_FILAMENT_CLEAN), false, true); - while (!clean) { - lcd_update_enable(true); - lcd_update(2); - load_filament_final_feed(); - st_synchronize(); - clean = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_FILAMENT_CLEAN), false, true); - } + bool clean = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_FILAMENT_CLEAN), false, true); + while (!clean) { + lcd_update_enable(true); + lcd_update(2); + load_filament_final_feed(); + st_synchronize(); + clean = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_FILAMENT_CLEAN), false, true); + } } #ifdef FILAMENT_SENSOR @@ -2437,7 +2447,7 @@ static void lcd_menu_AutoLoadFilament() else { static_assert(sizeof(menu_data)>=sizeof(ShortTimer), "ShortTimer doesn't fit into menu_data"); - ShortTimer* ptimer = (ShortTimer*)&(menu_data[0]); + ShortTimer* ptimer = (ShortTimer*)&(menu_data[0]); if (!ptimer->running()) ptimer->start(); lcd_set_cursor(0, 0); lcd_puts_P(_T(MSG_ERROR)); @@ -2451,18 +2461,18 @@ static void lcd_menu_AutoLoadFilament() static void lcd_LoadFilament() { - if (degHotend0() > EXTRUDE_MINTEMP) - { - custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; - loading_flag = true; - enquecommand_P(PSTR("M701")); //load filament - SERIAL_ECHOLN("Loading filament"); - lcd_return_to_status(); - } - else - { - show_preheat_nozzle_warning(); - } + if (degHotend0() > EXTRUDE_MINTEMP) + { + custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; + loading_flag = true; + enquecommand_P(PSTR("M701")); //load filament + SERIAL_ECHOLN("Loading filament"); + lcd_return_to_status(); + } + else + { + show_preheat_nozzle_warning(); + } } @@ -2491,132 +2501,132 @@ static void lcd_LoadFilament() //! @endcode void lcd_menu_statistics() { - if (IS_SD_PRINTING) - { - const float _met = ((float)total_filament_used) / (100000.f); - const uint32_t _t = (millis() - starttime) / 1000ul; - const int _h = _t / 3600; - const int _m = (_t - (_h * 3600ul)) / 60ul; - const int _s = _t - ((_h * 3600ul) + (_m * 60ul)); - - lcd_printf_P(_N( - ESC_2J - "%S:" - ESC_H(6,1) "%8.2fm \n" - "%S :" - ESC_H(8,3) "%2dh %02dm %02ds" - ), - _i("Filament used"), - _met, - _i("Print time"), - _h, _m, _s - ); - menu_back_if_clicked_fb(); - } - else - { - unsigned long _filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED); - unsigned long _time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //in minutes - uint8_t _hours, _minutes; - uint32_t _days; - float _filament_m = (float)_filament/100; + if (IS_SD_PRINTING) + { + const float _met = ((float)total_filament_used) / (100000.f); + const uint32_t _t = (millis() - starttime) / 1000ul; + const int _h = _t / 3600; + const int _m = (_t - (_h * 3600ul)) / 60ul; + const int _s = _t - ((_h * 3600ul) + (_m * 60ul)); + + lcd_printf_P(_N( + ESC_2J + "%S:" + ESC_H(6,1) "%8.2fm \n" + "%S :" + ESC_H(8,3) "%2dh %02dm %02ds" + ), + _i("Filament used"), + _met, + _i("Print time"), + _h, _m, _s + ); + menu_back_if_clicked_fb(); + } + else + { + unsigned long _filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED); + unsigned long _time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //in minutes + uint8_t _hours, _minutes; + uint32_t _days; + float _filament_m = (float)_filament/100; // int _filament_km = (_filament >= 100000) ? _filament / 100000 : 0; // if (_filament_km > 0) _filament_m = _filament - (_filament_km * 100000); - _days = _time / 1440; - _hours = (_time - (_days * 1440)) / 60; - _minutes = _time - ((_days * 1440) + (_hours * 60)); - - lcd_printf_P(_N( - ESC_2J - "%S :" - ESC_H(9,1) "%8.2f m\n" - "%S :\n" - "%7ldd :%2hhdh :%02hhd m" - ), - _i("Total filament"), - _filament_m, - _i("Total print time"), - _days, _hours, _minutes - ); - KEEPALIVE_STATE(PAUSED_FOR_USER); - while (!lcd_clicked()) - { - manage_heater(); - manage_inactivity(true); - delay(100); - } - KEEPALIVE_STATE(NOT_BUSY); - lcd_quick_feedback(); - menu_back(); - } + _days = _time / 1440; + _hours = (_time - (_days * 1440)) / 60; + _minutes = _time - ((_days * 1440) + (_hours * 60)); + + lcd_printf_P(_N( + ESC_2J + "%S :" + ESC_H(9,1) "%8.2f m\n" + "%S :\n" + "%7ldd :%2hhdh :%02hhd m" + ), + _i("Total filament"), + _filament_m, + _i("Total print time"), + _days, _hours, _minutes + ); + KEEPALIVE_STATE(PAUSED_FOR_USER); + while (!lcd_clicked()) + { + manage_heater(); + manage_inactivity(true); + delay(100); + } + KEEPALIVE_STATE(NOT_BUSY); + lcd_quick_feedback(); + menu_back(); + } } static void _lcd_move(const char *name, int axis, int min, int max) { - typedef struct - { // 2bytes total - bool initialized; // 1byte - bool endstopsEnabledPrevious; // 1byte - } _menu_data_t; - static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data"); - _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); - if (!_md->initialized) - { - _md->endstopsEnabledPrevious = enable_endstops(false); - _md->initialized = true; - } - if (lcd_encoder != 0) - { - refresh_cmd_timeout(); - if (! planner_queue_full()) - { - current_position[axis] += float((int)lcd_encoder) * move_menu_scale; - if (min_software_endstops && current_position[axis] < min) current_position[axis] = min; - if (max_software_endstops && current_position[axis] > max) current_position[axis] = max; - lcd_encoder = 0; - world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis] / 60, active_extruder); - lcd_draw_update = 1; - } - } - if (lcd_draw_update) - { - lcd_set_cursor(0, 1); - menu_draw_float31(' ', name, current_position[axis]); - } - if (menu_leaving || LCD_CLICKED) (void)enable_endstops(_md->endstopsEnabledPrevious); - if (LCD_CLICKED) menu_back(); + typedef struct + { // 2bytes total + bool initialized; // 1byte + bool endstopsEnabledPrevious; // 1byte + } _menu_data_t; + static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data"); + _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); + if (!_md->initialized) + { + _md->endstopsEnabledPrevious = enable_endstops(false); + _md->initialized = true; + } + if (lcd_encoder != 0) + { + refresh_cmd_timeout(); + if (! planner_queue_full()) + { + current_position[axis] += float((int)lcd_encoder) * move_menu_scale; + if (min_software_endstops && current_position[axis] < min) current_position[axis] = min; + if (max_software_endstops && current_position[axis] > max) current_position[axis] = max; + lcd_encoder = 0; + world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[axis] / 60, active_extruder); + lcd_draw_update = 1; + } + } + if (lcd_draw_update) + { + lcd_set_cursor(0, 1); + menu_draw_float31(' ', name, current_position[axis]); + } + if (menu_leaving || LCD_CLICKED) (void)enable_endstops(_md->endstopsEnabledPrevious); + if (LCD_CLICKED) menu_back(); } static void lcd_move_e() { - if (degHotend0() > EXTRUDE_MINTEMP) - { - if (lcd_encoder != 0) - { - refresh_cmd_timeout(); - if (! planner_queue_full()) - { - current_position[E_AXIS] += float((int)lcd_encoder) * move_menu_scale; - lcd_encoder = 0; - 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); - lcd_draw_update = 1; - } - } - if (lcd_draw_update) - { - lcd_set_cursor(0, 1); - menu_draw_float31(' ', PSTR("Extruder"), current_position[E_AXIS]); - } - if (LCD_CLICKED) menu_back(); - } - else - { - show_preheat_nozzle_warning(); - lcd_return_to_status(); - } + if (degHotend0() > EXTRUDE_MINTEMP) + { + if (lcd_encoder != 0) + { + refresh_cmd_timeout(); + if (! planner_queue_full()) + { + current_position[E_AXIS] += float((int)lcd_encoder) * move_menu_scale; + lcd_encoder = 0; + 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); + lcd_draw_update = 1; + } + } + if (lcd_draw_update) + { + lcd_set_cursor(0, 1); + menu_draw_float31(' ', PSTR("Extruder"), current_position[E_AXIS]); + } + if (LCD_CLICKED) menu_back(); + } + else + { + show_preheat_nozzle_warning(); + lcd_return_to_status(); + } } @@ -2631,26 +2641,26 @@ static void lcd_menu_xyz_y_min() //|Left: N/A | //|Right: N/A | //---------------------- - float distanceMin[2]; + float distanceMin[2]; count_xyz_details(distanceMin); - lcd_printf_P(_N( - ESC_H(0,0) - "%S:\n" - "%S\n" - "%S:\n" - "%S:" - ), - _i("Y distance from min"), - separator, - _i("Left"), - _i("Right") - ); - for (uint8_t i = 0; i < 2; i++) - { - lcd_set_cursor(11,2+i); - if (distanceMin[i] >= 200) lcd_puts_P(_N("N/A")); - else lcd_printf_P(_N("%6.2fmm"), distanceMin[i]); - } + lcd_printf_P(_N( + ESC_H(0,0) + "%S:\n" + "%S\n" + "%S:\n" + "%S:" + ), + _i("Y distance from min"), + separator, + _i("Left"), + _i("Right") + ); + for (uint8_t i = 0; i < 2; i++) + { + lcd_set_cursor(11,2+i); + if (distanceMin[i] >= 200) lcd_puts_P(_N("N/A")); + else lcd_printf_P(_N("%6.2fmm"), distanceMin[i]); + } if (lcd_clicked()) menu_goto(lcd_menu_xyz_skew, 0, true, true); } @@ -2658,7 +2668,7 @@ static void lcd_menu_xyz_y_min() //@brief Show measured axis skewness float _deg(float rad) { - return rad * 180 / M_PI; + return rad * 180 / M_PI; } static void lcd_menu_xyz_skew() @@ -2670,22 +2680,22 @@ static void lcd_menu_xyz_skew() //|Severe skew: 0.25d| //---------------------- float angleDiff = eeprom_read_float((float*)(EEPROM_XYZ_CAL_SKEW)); - lcd_printf_P(_N( - ESC_H(0,0) - "%S:\n" - "%S\n" - "%S: %5.2f\x01\n" - "%S: %5.2f\x01" - ), - _i("Measured skew"), - separator, - _i("Slight skew"), _deg(bed_skew_angle_mild), - _i("Severe skew"), _deg(bed_skew_angle_extreme) - ); - if (angleDiff < 100) - lcd_printf_P(_N(ESC_H(15,0)"%4.2f\x01"), _deg(angleDiff)); - else - lcd_puts_P(_N(ESC_H(15,0)"N/A")); + lcd_printf_P(_N( + ESC_H(0,0) + "%S:\n" + "%S\n" + "%S: %5.2f\x01\n" + "%S: %5.2f\x01" + ), + _i("Measured skew"), + separator, + _i("Slight skew"), _deg(bed_skew_angle_mild), + _i("Severe skew"), _deg(bed_skew_angle_extreme) + ); + if (angleDiff < 100) + lcd_printf_P(_N(ESC_H(15,0)"%4.2f\x01"), _deg(angleDiff)); + else + lcd_puts_P(_N(ESC_H(15,0)"N/A")); if (lcd_clicked()) menu_goto(lcd_menu_xyz_offset, 0, true, true); } @@ -2717,25 +2727,25 @@ static void lcd_menu_xyz_offset() // Save a single axis babystep value. void EEPROM_save_B(int pos, int* value) { - eeprom_update_byte((unsigned char*)pos, (unsigned char)((*value) & 0xff)); - eeprom_update_byte((unsigned char*)pos + 1, (unsigned char)((*value) >> 8)); + eeprom_update_byte((unsigned char*)pos, (unsigned char)((*value) & 0xff)); + eeprom_update_byte((unsigned char*)pos + 1, (unsigned char)((*value) >> 8)); } // Read a single axis babystep value. void EEPROM_read_B(int pos, int* value) { - *value = (int)eeprom_read_byte((unsigned char*)pos) | (int)(eeprom_read_byte((unsigned char*)pos + 1) << 8); + *value = (int)eeprom_read_byte((unsigned char*)pos) | (int)(eeprom_read_byte((unsigned char*)pos + 1) << 8); } static void lcd_move_x() { - _lcd_move(PSTR("X"), X_AXIS, X_MIN_POS, X_MAX_POS); + _lcd_move(PSTR("X"), X_AXIS, X_MIN_POS, X_MAX_POS); } static void lcd_move_y() { - _lcd_move(PSTR("Y"), Y_AXIS, Y_MIN_POS, Y_MAX_POS); + _lcd_move(PSTR("Y"), Y_AXIS, Y_MIN_POS, Y_MAX_POS); } static void lcd_move_z() { - _lcd_move(PSTR("Z"), Z_AXIS, Z_MIN_POS, Z_MAX_POS); + _lcd_move(PSTR("Z"), Z_AXIS, Z_MIN_POS, Z_MAX_POS); } @@ -2750,139 +2760,139 @@ static void lcd_move_z() { * other value leads to storing Z_AXIS * @param msg text to be displayed */ -static void _lcd_babystep(int axis, const char *msg) -{ - typedef struct - { // 19bytes total - int8_t status; // 1byte - int babystepMem[3]; // 6bytes - float babystepMemMM[3]; // 12bytes - } _menu_data_t; - static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data"); - _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); - if (_md->status == 0) - { - // Menu was entered. - // Initialize its status. - _md->status = 1; - check_babystep(); - - EEPROM_read_B(EEPROM_BABYSTEP_X, &_md->babystepMem[0]); - EEPROM_read_B(EEPROM_BABYSTEP_Y, &_md->babystepMem[1]); - EEPROM_read_B(EEPROM_BABYSTEP_Z, &_md->babystepMem[2]); - - // same logic as in babystep_load - if (calibration_status() >= CALIBRATION_STATUS_LIVE_ADJUST) - _md->babystepMem[2] = 0; - - _md->babystepMemMM[0] = _md->babystepMem[0]/cs.axis_steps_per_unit[X_AXIS]; - _md->babystepMemMM[1] = _md->babystepMem[1]/cs.axis_steps_per_unit[Y_AXIS]; - _md->babystepMemMM[2] = _md->babystepMem[2]/cs.axis_steps_per_unit[Z_AXIS]; - lcd_draw_update = 1; - //SERIAL_ECHO("Z baby step: "); - //SERIAL_ECHO(_md->babystepMem[2]); - // Wait 90 seconds before closing the live adjust dialog. - lcd_timeoutToStatus.start(); - } +static void _lcd_babystep(int axis, const char *msg) +{ + typedef struct + { // 19bytes total + int8_t status; // 1byte + int babystepMem[3]; // 6bytes + float babystepMemMM[3]; // 12bytes + } _menu_data_t; + static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data"); + _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); + if (_md->status == 0) + { + // Menu was entered. + // Initialize its status. + _md->status = 1; + check_babystep(); + + EEPROM_read_B(EEPROM_BABYSTEP_X, &_md->babystepMem[0]); + EEPROM_read_B(EEPROM_BABYSTEP_Y, &_md->babystepMem[1]); + EEPROM_read_B(EEPROM_BABYSTEP_Z, &_md->babystepMem[2]); + + // same logic as in babystep_load + if (calibration_status() >= CALIBRATION_STATUS_LIVE_ADJUST) + _md->babystepMem[2] = 0; + + _md->babystepMemMM[0] = _md->babystepMem[0]/cs.axis_steps_per_unit[X_AXIS]; + _md->babystepMemMM[1] = _md->babystepMem[1]/cs.axis_steps_per_unit[Y_AXIS]; + _md->babystepMemMM[2] = _md->babystepMem[2]/cs.axis_steps_per_unit[Z_AXIS]; + lcd_draw_update = 1; + //SERIAL_ECHO("Z baby step: "); + //SERIAL_ECHO(_md->babystepMem[2]); + // Wait 90 seconds before closing the live adjust dialog. + lcd_timeoutToStatus.start(); + } - if (lcd_encoder != 0) - { - if (homing_flag) lcd_encoder = 0; - _md->babystepMem[axis] += (int)lcd_encoder; - if (axis == 2) - { - if (_md->babystepMem[axis] < Z_BABYSTEP_MIN) _md->babystepMem[axis] = Z_BABYSTEP_MIN; //-3999 -> -9.99 mm - else if (_md->babystepMem[axis] > Z_BABYSTEP_MAX) _md->babystepMem[axis] = Z_BABYSTEP_MAX; //0 - else - { - CRITICAL_SECTION_START - babystepsTodo[axis] += (int)lcd_encoder; - CRITICAL_SECTION_END - } - } - _md->babystepMemMM[axis] = _md->babystepMem[axis]/cs.axis_steps_per_unit[axis]; - delay(50); - lcd_encoder = 0; - lcd_draw_update = 1; - } - if (lcd_draw_update) - { - lcd_set_cursor(0, 1); - menu_draw_float13(' ', msg, _md->babystepMemMM[axis]); - } - if (LCD_CLICKED || menu_leaving) - { - // Only update the EEPROM when leaving the menu. - EEPROM_save_B( - (axis == X_AXIS) ? EEPROM_BABYSTEP_X : ((axis == Y_AXIS) ? EEPROM_BABYSTEP_Y : EEPROM_BABYSTEP_Z), - &_md->babystepMem[axis]); - if(Z_AXIS == axis) calibration_status_store(CALIBRATION_STATUS_CALIBRATED); - } - if (LCD_CLICKED) menu_back(); + if (lcd_encoder != 0) + { + if (homing_flag) lcd_encoder = 0; + _md->babystepMem[axis] += (int)lcd_encoder; + if (axis == 2) + { + if (_md->babystepMem[axis] < Z_BABYSTEP_MIN) _md->babystepMem[axis] = Z_BABYSTEP_MIN; //-3999 -> -9.99 mm + else if (_md->babystepMem[axis] > Z_BABYSTEP_MAX) _md->babystepMem[axis] = Z_BABYSTEP_MAX; //0 + else + { + CRITICAL_SECTION_START + babystepsTodo[axis] += (int)lcd_encoder; + CRITICAL_SECTION_END + } + } + _md->babystepMemMM[axis] = _md->babystepMem[axis]/cs.axis_steps_per_unit[axis]; + delay(50); + lcd_encoder = 0; + lcd_draw_update = 1; + } + if (lcd_draw_update) + { + lcd_set_cursor(0, 1); + menu_draw_float13(' ', msg, _md->babystepMemMM[axis]); + } + if (LCD_CLICKED || menu_leaving) + { + // Only update the EEPROM when leaving the menu. + EEPROM_save_B( + (axis == X_AXIS) ? EEPROM_BABYSTEP_X : ((axis == Y_AXIS) ? EEPROM_BABYSTEP_Y : EEPROM_BABYSTEP_Z), + &_md->babystepMem[axis]); + if(Z_AXIS == axis) calibration_status_store(CALIBRATION_STATUS_CALIBRATED); + } + if (LCD_CLICKED) menu_back(); } static void lcd_babystep_z() { - _lcd_babystep(Z_AXIS, (_i("Adjusting Z")));////MSG_BABYSTEPPING_Z c=20 r=0 + _lcd_babystep(Z_AXIS, (_i("Adjusting Z")));////MSG_BABYSTEPPING_Z c=20 r=0 } typedef struct -{ // 12bytes + 9bytes = 21bytes total +{ // 12bytes + 9bytes = 21bytes total menu_data_edit_t reserved; //12 bytes reserved for number editing functions - int8_t status; // 1byte - int16_t left; // 2byte - int16_t right; // 2byte - int16_t front; // 2byte - int16_t rear; // 2byte + int8_t status; // 1byte + int16_t left; // 2byte + int16_t right; // 2byte + int16_t front; // 2byte + int16_t rear; // 2byte } _menu_data_adjust_bed_t; static_assert(sizeof(menu_data)>= sizeof(_menu_data_adjust_bed_t),"_menu_data_adjust_bed_t doesn't fit into menu_data"); void lcd_adjust_bed_reset(void) { - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT , 0); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0); - eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR , 0); - _menu_data_adjust_bed_t* _md = (_menu_data_adjust_bed_t*)&(menu_data[0]); - _md->status = 0; + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT, 0); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0); + eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR, 0); + _menu_data_adjust_bed_t* _md = (_menu_data_adjust_bed_t*)&(menu_data[0]); + _md->status = 0; } #define BED_ADJUSTMENT_UM_MAX 50 void lcd_adjust_bed(void) { - _menu_data_adjust_bed_t* _md = (_menu_data_adjust_bed_t*)&(menu_data[0]); + _menu_data_adjust_bed_t* _md = (_menu_data_adjust_bed_t*)&(menu_data[0]); if (_md->status == 0) - { + { // Menu was entered. - _md->left = 0; - _md->right = 0; - _md->front = 0; - _md->rear = 0; + _md->left = 0; + _md->right = 0; + _md->front = 0; + _md->rear = 0; if (eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1) - { - _md->left = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_LEFT); - _md->right = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_RIGHT); - _md->front = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_FRONT); - _md->rear = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_REAR); - } + { + _md->left = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_LEFT); + _md->right = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_RIGHT); + _md->front = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_FRONT); + _md->rear = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_REAR); + } _md->status = 1; } MENU_BEGIN(); - // leaving menu - this condition must be immediately before MENU_ITEM_BACK_P - if (((menu_item == menu_line) && menu_clicked && (lcd_encoder == menu_item)) || menu_leaving) - { + // leaving menu - this condition must be immediately before MENU_ITEM_BACK_P + if (((menu_item == menu_line) && menu_clicked && (lcd_encoder == menu_item)) || menu_leaving) + { eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_LEFT, _md->left); eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, _md->right); eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_FRONT, _md->front); eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_REAR, _md->rear); eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1); - } - MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); - MENU_ITEM_EDIT_int3_P(_i("Left side [um]"), &_md->left, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_LEFT c=14 r=1 + } + MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); + MENU_ITEM_EDIT_int3_P(_i("Left side [um]"), &_md->left, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_LEFT c=14 r=1 MENU_ITEM_EDIT_int3_P(_i("Right side[um]"), &_md->right, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_RIGHT c=14 r=1 MENU_ITEM_EDIT_int3_P(_i("Front side[um]"), &_md->front, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_FRONT c=14 r=1 MENU_ITEM_EDIT_int3_P(_i("Rear side [um]"), &_md->rear, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_REAR c=14 r=1 @@ -2892,22 +2902,22 @@ void lcd_adjust_bed(void) void pid_extruder() { - lcd_clear(); - lcd_set_cursor(1, 0); - lcd_puts_P(_i("Set temperature:"));////MSG_SET_TEMPERATURE c=19 r=1 - pid_temp += int(lcd_encoder); - if (pid_temp > HEATER_0_MAXTEMP) pid_temp = HEATER_0_MAXTEMP; - if (pid_temp < HEATER_0_MINTEMP) pid_temp = HEATER_0_MINTEMP; - lcd_encoder = 0; - lcd_set_cursor(1, 2); - lcd_print(ftostr3(pid_temp)); - if (lcd_clicked()) { - lcd_commands_type = LCD_COMMAND_PID_EXTRUDER; - lcd_return_to_status(); - lcd_update(2); - } - -} + lcd_clear(); + lcd_set_cursor(1, 0); + lcd_puts_P(_i("Set temperature:"));////MSG_SET_TEMPERATURE c=19 r=1 + pid_temp += int(lcd_encoder); + if (pid_temp > HEATER_0_MAXTEMP) pid_temp = HEATER_0_MAXTEMP; + if (pid_temp < HEATER_0_MINTEMP) pid_temp = HEATER_0_MINTEMP; + lcd_encoder = 0; + lcd_set_cursor(1, 2); + lcd_print(ftostr3(pid_temp)); + if (lcd_clicked()) { + lcd_commands_type = LCD_COMMAND_PID_EXTRUDER; + lcd_return_to_status(); + lcd_update(2); + } + +} /* void lcd_adjust_z() { int enc_dif = 0; @@ -2994,69 +3004,69 @@ void lcd_adjust_z() { }*/ bool lcd_wait_for_pinda(float temp) { - lcd_set_custom_characters_degree(); - setAllTargetHotends(0); - setTargetBed(0); - LongTimer pinda_timeout; - pinda_timeout.start(); - bool target_temp_reached = true; - - while (current_temperature_pinda > temp){ - lcd_display_message_fullscreen_P(_i("Waiting for PINDA probe cooling"));////MSG_WAITING_TEMP_PINDA c=20 r=3 - - lcd_set_cursor(0, 4); - lcd_print(LCD_STR_THERMOMETER[0]); - lcd_print(ftostr3(current_temperature_pinda)); - lcd_print("/"); - lcd_print(ftostr3(temp)); - lcd_print(LCD_STR_DEGREE); - delay_keep_alive(1000); - serialecho_temperatures(); - if (pinda_timeout.expired(8 * 60 * 1000ul)) { //PINDA cooling from 60 C to 35 C takes about 7 minutes - target_temp_reached = false; - break; - } - } - lcd_set_custom_characters_arrows(); - lcd_update_enable(true); - return target_temp_reached; + lcd_set_custom_characters_degree(); + setAllTargetHotends(0); + setTargetBed(0); + LongTimer pinda_timeout; + pinda_timeout.start(); + bool target_temp_reached = true; + + while (current_temperature_pinda > temp) { + lcd_display_message_fullscreen_P(_i("Waiting for PINDA probe cooling"));////MSG_WAITING_TEMP_PINDA c=20 r=3 + + lcd_set_cursor(0, 4); + lcd_print(LCD_STR_THERMOMETER[0]); + lcd_print(ftostr3(current_temperature_pinda)); + lcd_print("/"); + lcd_print(ftostr3(temp)); + lcd_print(LCD_STR_DEGREE); + delay_keep_alive(1000); + serialecho_temperatures(); + if (pinda_timeout.expired(8 * 60 * 1000ul)) { //PINDA cooling from 60 C to 35 C takes about 7 minutes + target_temp_reached = false; + break; + } + } + lcd_set_custom_characters_arrows(); + lcd_update_enable(true); + return target_temp_reached; } void lcd_wait_for_heater() { - lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING)); - lcd_set_degree(); - lcd_set_cursor(0, 4); - lcd_print(LCD_STR_THERMOMETER[0]); - lcd_print(ftostr3(degHotend(active_extruder))); - lcd_print("/"); - lcd_print(ftostr3(degTargetHotend(active_extruder))); - lcd_print(LCD_STR_DEGREE); + lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING)); + lcd_set_degree(); + lcd_set_cursor(0, 4); + lcd_print(LCD_STR_THERMOMETER[0]); + lcd_print(ftostr3(degHotend(active_extruder))); + lcd_print("/"); + lcd_print(ftostr3(degTargetHotend(active_extruder))); + lcd_print(LCD_STR_DEGREE); } void lcd_wait_for_cool_down() { - lcd_set_custom_characters_degree(); - setAllTargetHotends(0); - setTargetBed(0); - while ((degHotend(0)>MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) { - lcd_display_message_fullscreen_P(_i("Waiting for nozzle and bed cooling"));////MSG_WAITING_TEMP c=20 r=3 - - lcd_set_cursor(0, 4); - lcd_print(LCD_STR_THERMOMETER[0]); - lcd_print(ftostr3(degHotend(0))); - lcd_print("/0"); - lcd_print(LCD_STR_DEGREE); - - lcd_set_cursor(9, 4); - lcd_print(LCD_STR_BEDTEMP[0]); - lcd_print(ftostr3(degBed())); - lcd_print("/0"); - lcd_print(LCD_STR_DEGREE); - lcd_set_custom_characters(); - delay_keep_alive(1000); - serialecho_temperatures(); - } - lcd_set_custom_characters_arrows(); - lcd_update_enable(true); + lcd_set_custom_characters_degree(); + setAllTargetHotends(0); + setTargetBed(0); + while ((degHotend(0)>MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) { + lcd_display_message_fullscreen_P(_i("Waiting for nozzle and bed cooling"));////MSG_WAITING_TEMP c=20 r=3 + + lcd_set_cursor(0, 4); + lcd_print(LCD_STR_THERMOMETER[0]); + lcd_print(ftostr3(degHotend(0))); + lcd_print("/0"); + lcd_print(LCD_STR_DEGREE); + + lcd_set_cursor(9, 4); + lcd_print(LCD_STR_BEDTEMP[0]); + lcd_print(ftostr3(degBed())); + lcd_print("/0"); + lcd_print(LCD_STR_DEGREE); + lcd_set_custom_characters(); + delay_keep_alive(1000); + serialecho_temperatures(); + } + lcd_set_custom_characters_arrows(); + lcd_update_enable(true); } // Lets the user move the Z carriage up to the end stoppers. @@ -3182,7 +3192,7 @@ static const char* lcd_display_message_fullscreen_nonBlocking_P(const char *msg, if (pgm_read_byte(msgend) != 0 && ! pgm_is_whitespace(msgend) && ! pgm_is_interpunction(msgend)) { // Splitting a word. Find the start of the current word. while (msgend > msg && ! pgm_is_whitespace(msgend - 1)) - -- msgend; + -- msgend; if (msgend == msg) // Found a single long word, which cannot be split. Just cut it. msgend = msgend2; @@ -3216,10 +3226,10 @@ const char* lcd_display_message_fullscreen_P(const char *msg, uint8_t &nlines) // uint8_t nlines; return lcd_display_message_fullscreen_nonBlocking_P(msg, nlines); } -const char* lcd_display_message_fullscreen_P(const char *msg) +const char* lcd_display_message_fullscreen_P(const char *msg) { - uint8_t nlines; - return lcd_display_message_fullscreen_P(msg, nlines); + uint8_t nlines; + return lcd_display_message_fullscreen_P(msg, nlines); } @@ -3234,41 +3244,41 @@ void lcd_show_fullscreen_message_and_wait_P(const char *msg) LcdUpdateDisabler lcdUpdateDisabler; const char *msg_next = lcd_display_message_fullscreen_P(msg); bool multi_screen = msg_next != NULL; - lcd_set_custom_characters_nextpage(); - KEEPALIVE_STATE(PAUSED_FOR_USER); - // Until confirmed by a button click. - for (;;) { - if (!multi_screen) { - lcd_set_cursor(19, 3); - // Display the confirm char. - lcd_print(char(2)); - } + lcd_set_custom_characters_nextpage(); + KEEPALIVE_STATE(PAUSED_FOR_USER); + // Until confirmed by a button click. + for (;;) { + if (!multi_screen) { + lcd_set_cursor(19, 3); + // Display the confirm char. + lcd_print(char(2)); + } // Wait for 5 seconds before displaying the next text. for (uint8_t i = 0; i < 100; ++ i) { delay_keep_alive(50); if (lcd_clicked()) { - if (msg_next == NULL) { - KEEPALIVE_STATE(IN_HANDLER); - lcd_set_custom_characters(); - lcd_update_enable(true); - lcd_update(2); - return; - } - else { - break; - } + if (msg_next == NULL) { + KEEPALIVE_STATE(IN_HANDLER); + lcd_set_custom_characters(); + lcd_update_enable(true); + lcd_update(2); + return; + } + else { + break; + } } } if (multi_screen) { if (msg_next == NULL) msg_next = msg; msg_next = lcd_display_message_fullscreen_P(msg_next); - if (msg_next == NULL) { + if (msg_next == NULL) { - lcd_set_cursor(19, 3); - // Display the confirm char. - lcd_print(char(2)); - } + lcd_set_cursor(19, 3); + // Display the confirm char. + lcd_print(char(2)); + } } } } @@ -3277,17 +3287,17 @@ bool lcd_wait_for_click_delay(uint16_t nDelay) // nDelay :: timeout [s] (0 ~ no timeout) // true ~ clicked, false ~ delayed { -bool bDelayed; -long nTime0 = millis()/1000; + bool bDelayed; + long nTime0 = millis()/1000; - KEEPALIVE_STATE(PAUSED_FOR_USER); + KEEPALIVE_STATE(PAUSED_FOR_USER); for (;;) { manage_heater(); manage_inactivity(true); bDelayed = ((millis()/1000-nTime0) > nDelay); bDelayed = (bDelayed && (nDelay != 0)); // 0 ~ no timeout, always waiting for click if (lcd_clicked() || bDelayed) { - KEEPALIVE_STATE(IN_HANDLER); + KEEPALIVE_STATE(IN_HANDLER); return(!bDelayed); } } @@ -3295,7 +3305,7 @@ long nTime0 = millis()/1000; void lcd_wait_for_click() { -lcd_wait_for_click_delay(0); + lcd_wait_for_click_delay(0); } //! @brief Show multiple screen message with yes and no possible choices and wait with possible timeout @@ -3321,69 +3331,69 @@ int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allo int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_first, const char *first_choice, const char *second_choice) { - const char *msg_next = lcd_display_message_fullscreen_P(msg); - bool multi_screen = msg_next != NULL; - bool yes = default_first ? true : false; - - // Wait for user confirmation or a timeout. - unsigned long previous_millis_cmd = millis(); - int8_t enc_dif = lcd_encoder_diff; - //KEEPALIVE_STATE(PAUSED_FOR_USER); - for (;;) { - for (uint8_t i = 0; i < 100; ++i) { - delay_keep_alive(50); - if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS) - return -1; - manage_heater(); - manage_inactivity(true); - - if (abs(enc_dif - lcd_encoder_diff) > 4) { - if (msg_next == NULL) { - lcd_set_cursor(0, 3); - if (enc_dif < lcd_encoder_diff && yes) { - lcd_puts_P((PSTR(" "))); - lcd_set_cursor(7, 3); - lcd_puts_P((PSTR(">"))); - yes = false; - } - else if (enc_dif > lcd_encoder_diff && !yes) { - lcd_puts_P((PSTR(">"))); - lcd_set_cursor(7, 3); - lcd_puts_P((PSTR(" "))); - yes = true; - } - enc_dif = lcd_encoder_diff; - } - else { - break; //turning knob skips waiting loop - } - } - if (lcd_clicked()) { - if (msg_next == NULL) { - //KEEPALIVE_STATE(IN_HANDLER); - lcd_set_custom_characters(); - return yes; - } - else break; - } - } - if (multi_screen) { - if (msg_next == NULL) { - msg_next = msg; - } - msg_next = lcd_display_message_fullscreen_P(msg_next); - } - if (msg_next == NULL) { - lcd_set_cursor(0, 3); - if (yes) lcd_puts_P(PSTR(">")); - lcd_set_cursor(1, 3); - lcd_puts_P(first_choice); - lcd_set_cursor(7, 3); - if (!yes) lcd_puts_P(PSTR(">")); - lcd_set_cursor(8, 3); - lcd_puts_P(second_choice); - } - } + const char *msg_next = lcd_display_message_fullscreen_P(msg); + bool multi_screen = msg_next != NULL; + bool yes = default_first ? true : false; + + // Wait for user confirmation or a timeout. + unsigned long previous_millis_cmd = millis(); + int8_t enc_dif = lcd_encoder_diff; + //KEEPALIVE_STATE(PAUSED_FOR_USER); + for (;;) { + for (uint8_t i = 0; i < 100; ++i) { + delay_keep_alive(50); + if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS) + return -1; + manage_heater(); + manage_inactivity(true); + + if (abs(enc_dif - lcd_encoder_diff) > 4) { + if (msg_next == NULL) { + lcd_set_cursor(0, 3); + if (enc_dif < lcd_encoder_diff && yes) { + lcd_puts_P((PSTR(" "))); + lcd_set_cursor(7, 3); + lcd_puts_P((PSTR(">"))); + yes = false; + } + else if (enc_dif > lcd_encoder_diff && !yes) { + lcd_puts_P((PSTR(">"))); + lcd_set_cursor(7, 3); + lcd_puts_P((PSTR(" "))); + yes = true; + } + enc_dif = lcd_encoder_diff; + } + else { + break; //turning knob skips waiting loop + } + } + if (lcd_clicked()) { + if (msg_next == NULL) { + //KEEPALIVE_STATE(IN_HANDLER); + lcd_set_custom_characters(); + return yes; + } + else break; + } + } + if (multi_screen) { + if (msg_next == NULL) { + msg_next = msg; + } + msg_next = lcd_display_message_fullscreen_P(msg_next); + } + if (msg_next == NULL) { + lcd_set_cursor(0, 3); + if (yes) lcd_puts_P(PSTR(">")); + lcd_set_cursor(1, 3); + lcd_puts_P(first_choice); + lcd_set_cursor(7, 3); + if (!yes) lcd_puts_P(PSTR(">")); + lcd_set_cursor(8, 3); + lcd_puts_P(second_choice); + } + } } //! @brief Show single screen message with yes and no possible choices and wait with possible timeout @@ -3396,54 +3406,54 @@ int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes) { - lcd_display_message_fullscreen_P(msg); - - if (default_yes) { - lcd_set_cursor(0, 2); - lcd_puts_P(PSTR(">")); - lcd_puts_P(_T(MSG_YES)); - lcd_set_cursor(1, 3); - lcd_puts_P(_T(MSG_NO)); - } - else { - lcd_set_cursor(1, 2); - lcd_puts_P(_T(MSG_YES)); - lcd_set_cursor(0, 3); - lcd_puts_P(PSTR(">")); - lcd_puts_P(_T(MSG_NO)); - } - bool yes = default_yes ? true : false; - - // Wait for user confirmation or a timeout. - unsigned long previous_millis_cmd = millis(); - int8_t enc_dif = lcd_encoder_diff; - KEEPALIVE_STATE(PAUSED_FOR_USER); - for (;;) { - if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS) - return -1; - manage_heater(); - manage_inactivity(true); - if (abs(enc_dif - lcd_encoder_diff) > 4) { - lcd_set_cursor(0, 2); - if (enc_dif < lcd_encoder_diff && yes) { - lcd_puts_P((PSTR(" "))); - lcd_set_cursor(0, 3); - lcd_puts_P((PSTR(">"))); - yes = false; - } - else if (enc_dif > lcd_encoder_diff && !yes) { - lcd_puts_P((PSTR(">"))); - lcd_set_cursor(0, 3); - lcd_puts_P((PSTR(" "))); - yes = true; - } - enc_dif = lcd_encoder_diff; - } - if (lcd_clicked()) { - KEEPALIVE_STATE(IN_HANDLER); - return yes; - } - } + lcd_display_message_fullscreen_P(msg); + + if (default_yes) { + lcd_set_cursor(0, 2); + lcd_puts_P(PSTR(">")); + lcd_puts_P(_T(MSG_YES)); + lcd_set_cursor(1, 3); + lcd_puts_P(_T(MSG_NO)); + } + else { + lcd_set_cursor(1, 2); + lcd_puts_P(_T(MSG_YES)); + lcd_set_cursor(0, 3); + lcd_puts_P(PSTR(">")); + lcd_puts_P(_T(MSG_NO)); + } + bool yes = default_yes ? true : false; + + // Wait for user confirmation or a timeout. + unsigned long previous_millis_cmd = millis(); + int8_t enc_dif = lcd_encoder_diff; + KEEPALIVE_STATE(PAUSED_FOR_USER); + for (;;) { + if (allow_timeouting && millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS) + return -1; + manage_heater(); + manage_inactivity(true); + if (abs(enc_dif - lcd_encoder_diff) > 4) { + lcd_set_cursor(0, 2); + if (enc_dif < lcd_encoder_diff && yes) { + lcd_puts_P((PSTR(" "))); + lcd_set_cursor(0, 3); + lcd_puts_P((PSTR(">"))); + yes = false; + } + else if (enc_dif > lcd_encoder_diff && !yes) { + lcd_puts_P((PSTR(">"))); + lcd_set_cursor(0, 3); + lcd_puts_P((PSTR(" "))); + yes = true; + } + enc_dif = lcd_encoder_diff; + } + if (lcd_clicked()) { + KEEPALIVE_STATE(IN_HANDLER); + return yes; + } + } } void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask) @@ -3479,19 +3489,19 @@ void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, ui } if (point_too_far_mask == 0 || result > 0) { switch (result) { - default: - // should not happen - msg = _T(MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED); - break; - case BED_SKEW_OFFSET_DETECTION_PERFECT: - msg = _i("XYZ calibration ok. X/Y axes are perpendicular. Congratulations!");////MSG_BED_SKEW_OFFSET_DETECTION_PERFECT c=20 r=8 - break; - case BED_SKEW_OFFSET_DETECTION_SKEW_MILD: - msg = _i("XYZ calibration all right. X/Y axes are slightly skewed. Good job!");////MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD c=20 r=8 - break; - case BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME: - msg = _i("XYZ calibration all right. Skew will be corrected automatically.");////MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME c=20 r=8 - break; + default: + // should not happen + msg = _T(MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED); + break; + case BED_SKEW_OFFSET_DETECTION_PERFECT: + msg = _i("XYZ calibration ok. X/Y axes are perpendicular. Congratulations!");////MSG_BED_SKEW_OFFSET_DETECTION_PERFECT c=20 r=8 + break; + case BED_SKEW_OFFSET_DETECTION_SKEW_MILD: + msg = _i("XYZ calibration all right. X/Y axes are slightly skewed. Good job!");////MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD c=20 r=8 + break; + case BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME: + msg = _i("XYZ calibration all right. Skew will be corrected automatically.");////MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME c=20 r=8 + break; } lcd_show_fullscreen_message_and_wait_P(msg); } @@ -3499,43 +3509,43 @@ void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, ui } void lcd_temp_cal_show_result(bool result) { - - custom_message_type = CUSTOM_MSG_TYPE_STATUS; - disable_x(); - disable_y(); - disable_z(); - disable_e0(); - disable_e1(); - disable_e2(); - setTargetBed(0); //set bed target temperature back to 0 - - if (result == true) { - eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); - SERIAL_ECHOLNPGM("Temperature calibration done. Continue with pressing the knob."); - lcd_show_fullscreen_message_and_wait_P(_T(MSG_TEMP_CALIBRATION_DONE)); - temp_cal_active = true; - eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 1); - } - else { - eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); - SERIAL_ECHOLNPGM("Temperature calibration failed. Continue with pressing the knob."); - lcd_show_fullscreen_message_and_wait_P(_i("Temperature calibration failed"));////MSG_TEMP_CAL_FAILED c=20 r=8 - temp_cal_active = false; - eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 0); - } - lcd_update_enable(true); - lcd_update(2); + + custom_message_type = CUSTOM_MSG_TYPE_STATUS; + disable_x(); + disable_y(); + disable_z(); + disable_e0(); + disable_e1(); + disable_e2(); + setTargetBed(0); //set bed target temperature back to 0 + + if (result == true) { + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1); + SERIAL_ECHOLNPGM("Temperature calibration done. Continue with pressing the knob."); + lcd_show_fullscreen_message_and_wait_P(_T(MSG_TEMP_CALIBRATION_DONE)); + temp_cal_active = true; + eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 1); + } + else { + eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0); + SERIAL_ECHOLNPGM("Temperature calibration failed. Continue with pressing the knob."); + lcd_show_fullscreen_message_and_wait_P(_i("Temperature calibration failed"));////MSG_TEMP_CAL_FAILED c=20 r=8 + temp_cal_active = false; + eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 0); + } + lcd_update_enable(true); + lcd_update(2); } static void lcd_show_end_stops() { - lcd_set_cursor(0, 0); - lcd_puts_P((PSTR("End stops diag"))); - lcd_set_cursor(0, 1); - lcd_puts_P((READ(X_MIN_PIN) ^ (bool)X_MIN_ENDSTOP_INVERTING) ? (PSTR("X1")) : (PSTR("X0"))); - lcd_set_cursor(0, 2); - lcd_puts_P((READ(Y_MIN_PIN) ^ (bool)Y_MIN_ENDSTOP_INVERTING) ? (PSTR("Y1")) : (PSTR("Y0"))); - lcd_set_cursor(0, 3); - lcd_puts_P((READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING) ? (PSTR("Z1")) : (PSTR("Z0"))); + lcd_set_cursor(0, 0); + lcd_puts_P((PSTR("End stops diag"))); + lcd_set_cursor(0, 1); + lcd_puts_P((READ(X_MIN_PIN) ^ (bool)X_MIN_ENDSTOP_INVERTING) ? (PSTR("X1")) : (PSTR("X0"))); + lcd_set_cursor(0, 2); + lcd_puts_P((READ(Y_MIN_PIN) ^ (bool)Y_MIN_ENDSTOP_INVERTING) ? (PSTR("Y1")) : (PSTR("Y0"))); + lcd_set_cursor(0, 3); + lcd_puts_P((READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING) ? (PSTR("Z1")) : (PSTR("Z0"))); } #ifndef TMC2130 @@ -3566,21 +3576,21 @@ void lcd_diag_show_end_stops() #ifdef TMC2130 static void lcd_show_pinda_state() { -lcd_set_cursor(0, 0); -lcd_puts_P((PSTR("P.I.N.D.A. state"))); -lcd_set_cursor(0, 2); -lcd_puts_P(READ(Z_MIN_PIN)?(PSTR("Z1 (LED off)")):(PSTR("Z0 (LED on) "))); // !!! both strings must have same length (due to dynamic refreshing) + lcd_set_cursor(0, 0); + lcd_puts_P((PSTR("P.I.N.D.A. state"))); + lcd_set_cursor(0, 2); + lcd_puts_P(READ(Z_MIN_PIN)?(PSTR("Z1 (LED off)")):(PSTR("Z0 (LED on) "))); // !!! both strings must have same length (due to dynamic refreshing) } static void menu_show_pinda_state() { -lcd_timeoutToStatus.stop(); -lcd_show_pinda_state(); -if(LCD_CLICKED) - { - lcd_timeoutToStatus.start(); - menu_back(); - } + lcd_timeoutToStatus.stop(); + lcd_show_pinda_state(); + if(LCD_CLICKED) + { + lcd_timeoutToStatus.start(); + menu_back(); + } } #endif // defined TMC2130 @@ -3588,215 +3598,215 @@ if(LCD_CLICKED) void prusa_statistics(int _message, uint8_t _fil_nr) { #ifdef DEBUG_DISABLE_PRUSA_STATISTICS - return; + return; #endif //DEBUG_DISABLE_PRUSA_STATISTICS - switch (_message) - { + switch (_message) + { - case 0: // default message - if (IS_SD_PRINTING) - { - SERIAL_ECHO("{"); - prusa_stat_printerstatus(4); - prusa_stat_farm_number(); - prusa_stat_printinfo(); - SERIAL_ECHOLN("}"); - status_number = 4; - } - else - { - SERIAL_ECHO("{"); - prusa_stat_printerstatus(1); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 1; - } - break; - - case 1: // 1 heating - farm_status = 2; - SERIAL_ECHO("{"); - prusa_stat_printerstatus(2); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 2; - farm_timer = 1; - break; - - case 2: // heating done - farm_status = 3; - SERIAL_ECHO("{"); - prusa_stat_printerstatus(3); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 3; - farm_timer = 1; - - if (IS_SD_PRINTING) - { - farm_status = 4; - SERIAL_ECHO("{"); - prusa_stat_printerstatus(4); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 4; - } - else - { - SERIAL_ECHO("{"); - prusa_stat_printerstatus(3); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 3; - } - farm_timer = 1; - break; - - case 3: // filament change - - break; - case 4: // print succesfull - SERIAL_ECHO("{[RES:1][FIL:"); - MYSERIAL.print(int(_fil_nr)); - SERIAL_ECHO("]"); - prusa_stat_printerstatus(status_number); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - farm_timer = 2; - break; - case 5: // print not succesfull - SERIAL_ECHO("{[RES:0][FIL:"); - MYSERIAL.print(int(_fil_nr)); - SERIAL_ECHO("]"); - prusa_stat_printerstatus(status_number); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - farm_timer = 2; - break; - case 6: // print done - SERIAL_ECHO("{[PRN:8]"); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 8; - farm_timer = 2; - break; - case 7: // print done - stopped - SERIAL_ECHO("{[PRN:9]"); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 9; - farm_timer = 2; - break; - case 8: // printer started - SERIAL_ECHO("{[PRN:0][PFN:"); - status_number = 0; - SERIAL_ECHO(farm_no); - SERIAL_ECHOLN("]}"); - farm_timer = 2; - break; - case 20: // echo farm no - SERIAL_ECHO("{"); - prusa_stat_printerstatus(status_number); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - farm_timer = 4; - break; - case 21: // temperatures - SERIAL_ECHO("{"); - prusa_stat_temperatures(); - prusa_stat_farm_number(); - prusa_stat_printerstatus(status_number); - SERIAL_ECHOLN("}"); - break; + case 0: // default message + if (IS_SD_PRINTING) + { + SERIAL_ECHO("{"); + prusa_stat_printerstatus(4); + prusa_stat_farm_number(); + prusa_stat_printinfo(); + SERIAL_ECHOLN("}"); + status_number = 4; + } + else + { + SERIAL_ECHO("{"); + prusa_stat_printerstatus(1); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 1; + } + break; + + case 1: // 1 heating + farm_status = 2; + SERIAL_ECHO("{"); + prusa_stat_printerstatus(2); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 2; + farm_timer = 1; + break; + + case 2: // heating done + farm_status = 3; + SERIAL_ECHO("{"); + prusa_stat_printerstatus(3); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 3; + farm_timer = 1; + + if (IS_SD_PRINTING) + { + farm_status = 4; + SERIAL_ECHO("{"); + prusa_stat_printerstatus(4); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 4; + } + else + { + SERIAL_ECHO("{"); + prusa_stat_printerstatus(3); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 3; + } + farm_timer = 1; + break; + + case 3: // filament change + + break; + case 4: // print succesfull + SERIAL_ECHO("{[RES:1][FIL:"); + MYSERIAL.print(int(_fil_nr)); + SERIAL_ECHO("]"); + prusa_stat_printerstatus(status_number); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + farm_timer = 2; + break; + case 5: // print not succesfull + SERIAL_ECHO("{[RES:0][FIL:"); + MYSERIAL.print(int(_fil_nr)); + SERIAL_ECHO("]"); + prusa_stat_printerstatus(status_number); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + farm_timer = 2; + break; + case 6: // print done + SERIAL_ECHO("{[PRN:8]"); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 8; + farm_timer = 2; + break; + case 7: // print done - stopped + SERIAL_ECHO("{[PRN:9]"); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 9; + farm_timer = 2; + break; + case 8: // printer started + SERIAL_ECHO("{[PRN:0][PFN:"); + status_number = 0; + SERIAL_ECHO(farm_no); + SERIAL_ECHOLN("]}"); + farm_timer = 2; + break; + case 20: // echo farm no + SERIAL_ECHO("{"); + prusa_stat_printerstatus(status_number); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + farm_timer = 4; + break; + case 21: // temperatures + SERIAL_ECHO("{"); + prusa_stat_temperatures(); + prusa_stat_farm_number(); + prusa_stat_printerstatus(status_number); + SERIAL_ECHOLN("}"); + break; case 22: // waiting for filament change SERIAL_ECHO("{[PRN:5]"); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - status_number = 5; + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + status_number = 5; + break; + + case 90: // Error - Thermal Runaway + SERIAL_ECHO("{[ERR:1]"); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + break; + case 91: // Error - Thermal Runaway Preheat + SERIAL_ECHO("{[ERR:2]"); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + break; + case 92: // Error - Min temp + SERIAL_ECHO("{[ERR:3]"); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); + break; + case 93: // Error - Max temp + SERIAL_ECHO("{[ERR:4]"); + prusa_stat_farm_number(); + SERIAL_ECHOLN("}"); break; - - case 90: // Error - Thermal Runaway - SERIAL_ECHO("{[ERR:1]"); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - break; - case 91: // Error - Thermal Runaway Preheat - SERIAL_ECHO("{[ERR:2]"); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - break; - case 92: // Error - Min temp - SERIAL_ECHO("{[ERR:3]"); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - break; - case 93: // Error - Max temp - SERIAL_ECHO("{[ERR:4]"); - prusa_stat_farm_number(); - SERIAL_ECHOLN("}"); - break; case 99: // heartbeat SERIAL_ECHO("{[PRN:99]"); prusa_stat_temperatures(); - SERIAL_ECHO("[PFN:"); - SERIAL_ECHO(farm_no); - SERIAL_ECHO("]"); + SERIAL_ECHO("[PFN:"); + SERIAL_ECHO(farm_no); + SERIAL_ECHO("]"); SERIAL_ECHOLN("}"); - + break; - } + } } static void prusa_stat_printerstatus(int _status) { - SERIAL_ECHO("[PRN:"); - SERIAL_ECHO(_status); - SERIAL_ECHO("]"); + SERIAL_ECHO("[PRN:"); + SERIAL_ECHO(_status); + SERIAL_ECHO("]"); } static void prusa_stat_farm_number() { - SERIAL_ECHO("[PFN:"); - SERIAL_ECHO(farm_no); - SERIAL_ECHO("]"); + SERIAL_ECHO("[PFN:"); + SERIAL_ECHO(farm_no); + SERIAL_ECHO("]"); } static void prusa_stat_temperatures() { - SERIAL_ECHO("[ST0:"); - SERIAL_ECHO(target_temperature[0]); - SERIAL_ECHO("][STB:"); - SERIAL_ECHO(target_temperature_bed); - SERIAL_ECHO("][AT0:"); - SERIAL_ECHO(current_temperature[0]); - SERIAL_ECHO("][ATB:"); - SERIAL_ECHO(current_temperature_bed); - SERIAL_ECHO("]"); + SERIAL_ECHO("[ST0:"); + SERIAL_ECHO(target_temperature[0]); + SERIAL_ECHO("][STB:"); + SERIAL_ECHO(target_temperature_bed); + SERIAL_ECHO("][AT0:"); + SERIAL_ECHO(current_temperature[0]); + SERIAL_ECHO("][ATB:"); + SERIAL_ECHO(current_temperature_bed); + SERIAL_ECHO("]"); } static void prusa_stat_printinfo() { - SERIAL_ECHO("[TFU:"); - SERIAL_ECHO(total_filament_used); - SERIAL_ECHO("][PCD:"); - SERIAL_ECHO(itostr3(card.percentDone())); - SERIAL_ECHO("][FEM:"); - SERIAL_ECHO(itostr3(feedmultiply)); - SERIAL_ECHO("][FNM:"); - SERIAL_ECHO(longFilenameOLD); - SERIAL_ECHO("][TIM:"); - if (starttime != 0) - { - SERIAL_ECHO(millis() / 1000 - starttime / 1000); - } - else - { - SERIAL_ECHO(0); - } - SERIAL_ECHO("][FWR:"); - SERIAL_ECHO(FW_VERSION); - SERIAL_ECHO("]"); + SERIAL_ECHO("[TFU:"); + SERIAL_ECHO(total_filament_used); + SERIAL_ECHO("][PCD:"); + SERIAL_ECHO(itostr3(card.percentDone())); + SERIAL_ECHO("][FEM:"); + SERIAL_ECHO(itostr3(feedmultiply)); + SERIAL_ECHO("][FNM:"); + SERIAL_ECHO(longFilenameOLD); + SERIAL_ECHO("][TIM:"); + if (starttime != 0) + { + SERIAL_ECHO(millis() / 1000 - starttime / 1000); + } + else + { + SERIAL_ECHO(0); + } + SERIAL_ECHO("][FWR:"); + SERIAL_ECHO(FW_VERSION); + SERIAL_ECHO("]"); } /* @@ -3804,65 +3814,65 @@ void lcd_pick_babystep(){ int enc_dif = 0; int cursor_pos = 1; int fsm = 0; - - - - + + + + lcd_clear(); - + lcd_set_cursor(0, 0); - + lcd_puts_P(_i("Pick print"));////MSG_PICK_Z c=0 r=0 - - + + lcd_set_cursor(3, 2); - + lcd_print("1"); - + lcd_set_cursor(3, 3); - + lcd_print("2"); - + lcd_set_cursor(12, 2); - + lcd_print("3"); - + lcd_set_cursor(12, 3); - + lcd_print("4"); - + lcd_set_cursor(1, 2); - + lcd_print(">"); - - + + enc_dif = lcd_encoder_diff; - + while (fsm == 0) { - + manage_heater(); manage_inactivity(true); - + if ( abs((enc_dif - lcd_encoder_diff)) > 4 ) { - + if ( (abs(enc_dif - lcd_encoder_diff)) > 1 ) { if (enc_dif > lcd_encoder_diff ) { cursor_pos --; } - + if (enc_dif < lcd_encoder_diff ) { cursor_pos ++; } - + if (cursor_pos > 4) { cursor_pos = 4; } - + if (cursor_pos < 1) { cursor_pos = 1; } - + lcd_set_cursor(1, 2); lcd_print(" "); lcd_set_cursor(1, 3); @@ -3871,7 +3881,7 @@ void lcd_pick_babystep(){ lcd_print(" "); lcd_set_cursor(10, 3); lcd_print(" "); - + if (cursor_pos < 3) { lcd_set_cursor(1, cursor_pos+1); lcd_print(">"); @@ -3879,14 +3889,14 @@ void lcd_pick_babystep(){ lcd_set_cursor(10, cursor_pos-1); lcd_print(">"); } - - + + enc_dif = lcd_encoder_diff; delay(100); } - + } - + if (lcd_clicked()) { fsm = cursor_pos; int babyStepZ; @@ -3894,88 +3904,93 @@ void lcd_pick_babystep(){ EEPROM_save_B(EEPROM_BABYSTEP_Z,&babyStepZ); calibration_status_store(CALIBRATION_STATUS_CALIBRATED); delay(500); - + } }; - + lcd_clear(); lcd_return_to_status(); } */ void lcd_move_menu_axis() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); - MENU_ITEM_SUBMENU_P(_i("Move X"), lcd_move_x);////MSG_MOVE_X c=0 r=0 - MENU_ITEM_SUBMENU_P(_i("Move Y"), lcd_move_y);////MSG_MOVE_Y c=0 r=0 - MENU_ITEM_SUBMENU_P(_i("Move Z"), lcd_move_z);////MSG_MOVE_Z c=0 r=0 - MENU_ITEM_SUBMENU_P(_i("Extruder"), lcd_move_e);////MSG_MOVE_E c=0 r=0 - MENU_END(); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); + MENU_ITEM_SUBMENU_P(_i("Move X"), lcd_move_x);////MSG_MOVE_X c=0 r=0 + MENU_ITEM_SUBMENU_P(_i("Move Y"), lcd_move_y);////MSG_MOVE_Y c=0 r=0 + MENU_ITEM_SUBMENU_P(_i("Move Z"), lcd_move_z);////MSG_MOVE_Z c=0 r=0 + MENU_ITEM_SUBMENU_P(_i("Extruder"), lcd_move_e);////MSG_MOVE_E c=0 r=0 + MENU_END(); } static void lcd_move_menu_1mm() { - move_menu_scale = 1.0; - lcd_move_menu_axis(); + move_menu_scale = 1.0; + lcd_move_menu_axis(); } void EEPROM_save(int pos, uint8_t* value, uint8_t size) { - do - { - eeprom_write_byte((unsigned char*)pos, *value); - pos++; - value++; - } while (--size); + do + { + eeprom_write_byte((unsigned char*)pos, *value); + pos++; + value++; + } while (--size); } void EEPROM_read(int pos, uint8_t* value, uint8_t size) { - do - { - *value = eeprom_read_byte((unsigned char*)pos); - pos++; - value++; - } while (--size); + do + { + *value = eeprom_read_byte((unsigned char*)pos); + pos++; + value++; + } while (--size); } #ifdef SDCARD_SORT_ALPHA static void lcd_sort_type_set() { - uint8_t sdSort; - EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort)); - switch (sdSort) { - case SD_SORT_TIME: sdSort = SD_SORT_ALPHA; break; - case SD_SORT_ALPHA: sdSort = SD_SORT_NONE; break; - default: sdSort = SD_SORT_TIME; - } - eeprom_update_byte((unsigned char *)EEPROM_SD_SORT, sdSort); - presort_flag = true; + uint8_t sdSort; + EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort)); + switch (sdSort) { + case SD_SORT_TIME: + sdSort = SD_SORT_ALPHA; + break; + case SD_SORT_ALPHA: + sdSort = SD_SORT_NONE; + break; + default: + sdSort = SD_SORT_TIME; + } + eeprom_update_byte((unsigned char *)EEPROM_SD_SORT, sdSort); + presort_flag = true; } #endif //SDCARD_SORT_ALPHA #ifdef TMC2130 static void lcd_crash_mode_info() { - lcd_update_enable(true); - static uint32_t tim = 0; - if ((tim + 1000) < millis()) - { - fputs_P(_i("\x1b[2JCrash detection can\x1b[1;0Hbe turned on only in\x1b[2;0HNormal mode"), lcdout);////MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4 - tim = millis(); - } + lcd_update_enable(true); + static uint32_t tim = 0; + if ((tim + 1000) < millis()) + { + fputs_P(_i("\x1b[2JCrash detection can\x1b[1;0Hbe turned on only in\x1b[2;0HNormal mode"), lcdout);////MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4 + tim = millis(); + } menu_back_if_clicked(); } static void lcd_crash_mode_info2() { - lcd_update_enable(true); - static uint32_t tim = 0; - if ((tim + 1000) < millis()) - { - fputs_P(_i("\x1b[2JWARNING:\x1b[1;0HCrash detection\x1b[2;0Hdisabled in\x1b[3;0HStealth mode"), lcdout);////MSG_CRASH_DET_STEALTH_FORCE_OFF c=20 r=4 - tim = millis(); - } + lcd_update_enable(true); + static uint32_t tim = 0; + if ((tim + 1000) < millis()) + { + fputs_P(_i("\x1b[2JWARNING:\x1b[1;0HCrash detection\x1b[2;0Hdisabled in\x1b[3;0HStealth mode"), lcdout);////MSG_CRASH_DET_STEALTH_FORCE_OFF c=20 r=4 + tim = millis(); + } menu_back_if_clicked(); } #endif //TMC2130 @@ -3983,27 +3998,27 @@ static void lcd_crash_mode_info2() #ifdef FILAMENT_SENSOR static void lcd_filament_autoload_info() { -uint8_t nlines; - lcd_update_enable(true); - static uint32_t tim = 0; - if ((tim + 1000) < millis()) - { - lcd_display_message_fullscreen_nonBlocking_P(_i("Autoloading filament available only when filament sensor is turned on..."), nlines); ////MSG_AUTOLOADING_ONLY_IF_FSENS_ON c=20 r=4 - tim = millis(); - } + uint8_t nlines; + lcd_update_enable(true); + static uint32_t tim = 0; + if ((tim + 1000) < millis()) + { + lcd_display_message_fullscreen_nonBlocking_P(_i("Autoloading filament available only when filament sensor is turned on..."), nlines); ////MSG_AUTOLOADING_ONLY_IF_FSENS_ON c=20 r=4 + tim = millis(); + } menu_back_if_clicked(); } static void lcd_fsensor_fail() { -uint8_t nlines; - lcd_update_enable(true); - static uint32_t tim = 0; - if ((tim + 1000) < millis()) - { - lcd_display_message_fullscreen_nonBlocking_P(_i("ERROR: Filament sensor is not responding, please check connection."), nlines);////MSG_FSENS_NOT_RESPONDING c=20 r=4 - tim = millis(); - } + uint8_t nlines; + lcd_update_enable(true); + static uint32_t tim = 0; + if ((tim + 1000) < millis()) + { + lcd_display_message_fullscreen_nonBlocking_P(_i("ERROR: Filament sensor is not responding, please check connection."), nlines);////MSG_FSENS_NOT_RESPONDING c=20 r=4 + tim = millis(); + } menu_back_if_clicked(); } #endif //FILAMENT_SENSOR @@ -4011,88 +4026,102 @@ uint8_t nlines; //-// static void lcd_sound_state_set(void) { -Sound_CycleState(); + Sound_CycleState(); } static void lcd_silent_mode_set() { - switch (SilentModeMenu) { + switch (SilentModeMenu) { #ifdef TMC2130 - case SILENT_MODE_NORMAL: SilentModeMenu = SILENT_MODE_STEALTH; break; - case SILENT_MODE_STEALTH: SilentModeMenu = SILENT_MODE_NORMAL; break; - default: SilentModeMenu = SILENT_MODE_NORMAL; break; // (probably) not needed + case SILENT_MODE_NORMAL: + SilentModeMenu = SILENT_MODE_STEALTH; + break; + case SILENT_MODE_STEALTH: + SilentModeMenu = SILENT_MODE_NORMAL; + break; + default: + SilentModeMenu = SILENT_MODE_NORMAL; + break; // (probably) not needed #else - case SILENT_MODE_POWER: SilentModeMenu = SILENT_MODE_SILENT; break; - case SILENT_MODE_SILENT: SilentModeMenu = SILENT_MODE_AUTO; break; - case SILENT_MODE_AUTO: SilentModeMenu = SILENT_MODE_POWER; break; - default: SilentModeMenu = SILENT_MODE_POWER; break; // (probably) not needed + case SILENT_MODE_POWER: + SilentModeMenu = SILENT_MODE_SILENT; + break; + case SILENT_MODE_SILENT: + SilentModeMenu = SILENT_MODE_AUTO; + break; + case SILENT_MODE_AUTO: + SilentModeMenu = SILENT_MODE_POWER; + break; + default: + SilentModeMenu = SILENT_MODE_POWER; + break; // (probably) not needed #endif //TMC2130 - } - eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu); + } + eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu); #ifdef TMC2130 - // Wait until the planner queue is drained and the stepper routine achieves - // an idle state. - st_synchronize(); - if (tmc2130_wait_standstill_xy(1000)) {} + // Wait until the planner queue is drained and the stepper routine achieves + // an idle state. + st_synchronize(); + if (tmc2130_wait_standstill_xy(1000)) {} // MYSERIAL.print("standstill OK"); // else // MYSERIAL.print("standstill NG!"); - cli(); - tmc2130_mode = (SilentModeMenu != SILENT_MODE_NORMAL)?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL; - update_mode_profile(); - tmc2130_init(); - // We may have missed a stepper timer interrupt due to the time spent in tmc2130_init. - // Be safe than sorry, reset the stepper timer before re-enabling interrupts. - st_reset_timer(); - sei(); + cli(); + tmc2130_mode = (SilentModeMenu != SILENT_MODE_NORMAL)?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL; + update_mode_profile(); + tmc2130_init(); + // We may have missed a stepper timer interrupt due to the time spent in tmc2130_init. + // Be safe than sorry, reset the stepper timer before re-enabling interrupts. + st_reset_timer(); + sei(); #endif //TMC2130 - st_current_init(); + st_current_init(); #ifdef TMC2130 - if (CrashDetectMenu && (SilentModeMenu != SILENT_MODE_NORMAL)) - menu_submenu(lcd_crash_mode_info2); + if (CrashDetectMenu && (SilentModeMenu != SILENT_MODE_NORMAL)) + menu_submenu(lcd_crash_mode_info2); #endif //TMC2130 } #ifdef TMC2130 static void lcd_crash_mode_set() { - CrashDetectMenu = !CrashDetectMenu; //set also from crashdet_enable() and crashdet_disable() + CrashDetectMenu = !CrashDetectMenu; //set also from crashdet_enable() and crashdet_disable() if (CrashDetectMenu==0) { crashdet_disable(); - }else{ + } else { crashdet_enable(); } - if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) menu_goto(lcd_tune_menu, 9, true, true); - else menu_goto(lcd_settings_menu, 9, true, true); - + if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) menu_goto(lcd_tune_menu, 9, true, true); + else menu_goto(lcd_settings_menu, 9, true, true); + } #endif //TMC2130 - + #ifdef FILAMENT_SENSOR static void lcd_fsensor_state_set() { - FSensorStateMenu = !FSensorStateMenu; //set also from fsensor_enable() and fsensor_disable() - if (!FSensorStateMenu) { - fsensor_disable(); - if (fsensor_autoload_enabled && !mmu_enabled) - menu_submenu(lcd_filament_autoload_info); - } - else { - fsensor_enable(); - if (fsensor_not_responding && !mmu_enabled) - menu_submenu(lcd_fsensor_fail); - } + FSensorStateMenu = !FSensorStateMenu; //set also from fsensor_enable() and fsensor_disable() + if (!FSensorStateMenu) { + fsensor_disable(); + if (fsensor_autoload_enabled && !mmu_enabled) + menu_submenu(lcd_filament_autoload_info); + } + else { + fsensor_enable(); + if (fsensor_not_responding && !mmu_enabled) + menu_submenu(lcd_fsensor_fail); + } } #endif //FILAMENT_SENSOR #if !SDSORT_USES_RAM void lcd_set_degree() { - lcd_set_custom_characters_degree(); + lcd_set_custom_characters_degree(); } void lcd_set_progress() { - lcd_set_custom_characters_progress(); + lcd_set_custom_characters_progress(); } #endif @@ -4100,108 +4129,108 @@ void lcd_set_progress() { void menu_setlang(unsigned char lang) { - if (!lang_select(lang)) - { - if (lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Copy selected language from XFLASH?"), false, true)) - lang_boot_update_start(lang); - lcd_update_enable(true); - lcd_clear(); - menu_goto(lcd_language_menu, 0, true, true); - lcd_timeoutToStatus.stop(); //infinite timeout - lcd_draw_update = 2; - } + if (!lang_select(lang)) + { + if (lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Copy selected language from XFLASH?"), false, true)) + lang_boot_update_start(lang); + lcd_update_enable(true); + lcd_clear(); + menu_goto(lcd_language_menu, 0, true, true); + lcd_timeoutToStatus.stop(); //infinite timeout + lcd_draw_update = 2; + } } static void lcd_language_menu() { - MENU_BEGIN(); - if (lang_is_selected()) MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); // - if (menu_item_text_P(lang_get_name_by_code(lang_get_code(0)))) //primary language - { - menu_setlang(0); - return; - } - uint8_t cnt = lang_get_count(); -#ifdef W25X20CL - if (cnt == 2) //display secondary language in case of clear xflash - { - if (menu_item_text_P(lang_get_name_by_code(lang_get_code(1)))) - { - menu_setlang(1); - return; - } - } - else - for (int i = 2; i < cnt; i++) //skip seconday language - solved in lang_select (MK3) + MENU_BEGIN(); + if (lang_is_selected()) MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); // + if (menu_item_text_P(lang_get_name_by_code(lang_get_code(0)))) //primary language + { + menu_setlang(0); + return; + } + uint8_t cnt = lang_get_count(); +#ifdef W25X20CL + if (cnt == 2) //display secondary language in case of clear xflash + { + if (menu_item_text_P(lang_get_name_by_code(lang_get_code(1)))) + { + menu_setlang(1); + return; + } + } + else + for (int i = 2; i < cnt; i++) //skip seconday language - solved in lang_select (MK3) #else //W25X20CL - for (int i = 1; i < cnt; i++) //all seconday languages (MK2/25) + for (int i = 1; i < cnt; i++) //all seconday languages (MK2/25) #endif //W25X20CL - if (menu_item_text_P(lang_get_name_by_code(lang_get_code(i)))) - { - menu_setlang(i); - return; - } - MENU_END(); + if (menu_item_text_P(lang_get_name_by_code(lang_get_code(i)))) + { + menu_setlang(i); + return; + } + MENU_END(); } #endif //(LANG_MODE != 0) void lcd_mesh_bedleveling() { - mesh_bed_run_from_menu = true; - enquecommand_P(PSTR("G80")); - lcd_return_to_status(); + mesh_bed_run_from_menu = true; + enquecommand_P(PSTR("G80")); + lcd_return_to_status(); } void lcd_mesh_calibration() { - enquecommand_P(PSTR("M45")); - lcd_return_to_status(); + enquecommand_P(PSTR("M45")); + lcd_return_to_status(); } void lcd_mesh_calibration_z() { - enquecommand_P(PSTR("M45 Z")); - lcd_return_to_status(); + enquecommand_P(PSTR("M45 Z")); + lcd_return_to_status(); } void lcd_pinda_calibration_menu() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MENU_CALIBRATION)); - MENU_ITEM_SUBMENU_P(_i("Calibrate"), lcd_calibrate_pinda);////MSG_CALIBRATE_PINDA c=17 r=1 - MENU_END(); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MENU_CALIBRATION)); + MENU_ITEM_SUBMENU_P(_i("Calibrate"), lcd_calibrate_pinda);////MSG_CALIBRATE_PINDA c=17 r=1 + MENU_END(); } void lcd_temp_calibration_set() { - temp_cal_active = !temp_cal_active; - eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, temp_cal_active); - st_current_init(); + temp_cal_active = !temp_cal_active; + eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, temp_cal_active); + st_current_init(); } #ifdef HAS_SECOND_SERIAL_PORT void lcd_second_serial_set() { - if(selectedSerialPort == 1) selectedSerialPort = 0; - else selectedSerialPort = 1; - eeprom_update_byte((unsigned char *)EEPROM_SECOND_SERIAL_ACTIVE, selectedSerialPort); - MYSERIAL.begin(BAUDRATE); + if(selectedSerialPort == 1) selectedSerialPort = 0; + else selectedSerialPort = 1; + eeprom_update_byte((unsigned char *)EEPROM_SECOND_SERIAL_ACTIVE, selectedSerialPort); + MYSERIAL.begin(BAUDRATE); } #endif //HAS_SECOND_SERIAL_PORT void lcd_calibrate_pinda() { - enquecommand_P(PSTR("G76")); - lcd_return_to_status(); + enquecommand_P(PSTR("G76")); + lcd_return_to_status(); } #ifndef SNMM /*void lcd_calibrate_extruder() { - + if (degHotend0() > EXTRUDE_MINTEMP) { current_position[E_AXIS] = 0; //set initial position to zero plan_set_e_position(current_position[E_AXIS]); - + //long steps_start = st_get_position(E_AXIS); long steps_final; @@ -4215,8 +4244,8 @@ void lcd_calibrate_pinda() { lcd_show_fullscreen_message_and_wait_P(_i("Mark filament 100mm from extruder body. Click when done."));////MSG_MARK_FIL c=20 r=8 lcd_clear(); - - + + lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_PLEASE_WAIT)); current_position[E_AXIS] += e_shift_calibration; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder); @@ -4243,23 +4272,23 @@ void lcd_calibrate_pinda() { current_position[E_AXIS] += float(abs((int)lcd_encoder)) * 0.01; //0.05 lcd_encoder = 0; plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], feedrate, active_extruder); - + } - } + } } - + steps_final = current_position[E_AXIS] * axis_steps_per_unit[E_AXIS]; //steps_final = st_get_position(E_AXIS); lcd_draw_update = 1; e_steps_per_unit = ((float)(steps_final)) / 100.0f; - if (e_steps_per_unit < MIN_E_STEPS_PER_UNIT) e_steps_per_unit = MIN_E_STEPS_PER_UNIT; + if (e_steps_per_unit < MIN_E_STEPS_PER_UNIT) e_steps_per_unit = MIN_E_STEPS_PER_UNIT; if (e_steps_per_unit > MAX_E_STEPS_PER_UNIT) e_steps_per_unit = MAX_E_STEPS_PER_UNIT; lcd_clear(); axis_steps_per_unit[E_AXIS] = e_steps_per_unit; enquecommand_P(PSTR("M500")); //store settings to eeprom - + //lcd_drawedit(PSTR("Result"), ftostr31(axis_steps_per_unit[E_AXIS])); //delay_keep_alive(2000); delay_keep_alive(500); @@ -4286,75 +4315,75 @@ void lcd_extr_cal_reset() { void lcd_toshiba_flash_air_compatibility_toggle() { - card.ToshibaFlashAir_enable(! card.ToshibaFlashAir_isEnabled()); - eeprom_update_byte((uint8_t*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY, card.ToshibaFlashAir_isEnabled()); + card.ToshibaFlashAir_enable(! card.ToshibaFlashAir_isEnabled()); + eeprom_update_byte((uint8_t*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY, card.ToshibaFlashAir_isEnabled()); } void lcd_v2_calibration() { - if (mmu_enabled) - { - const uint8_t filament = choose_menu_P(_i("Select PLA filament:"),_T(MSG_FILAMENT),_i("Cancel")); ////c=20 r=1 ////c=19 r=1 - if (filament < 5) - { - lcd_commands_step = 20 + filament; - lcd_commands_type = LCD_COMMAND_V2_CAL; - } - } - else - { - bool loaded = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is PLA filament loaded?"), false, true);////MSG_PLA_FILAMENT_LOADED c=20 r=2 - if (loaded) { - lcd_commands_type = LCD_COMMAND_V2_CAL; - } - else { - lcd_display_message_fullscreen_P(_i("Please load PLA filament first."));////MSG_PLEASE_LOAD_PLA c=20 r=4 - for (int i = 0; i < 20; i++) { //wait max. 2s - delay_keep_alive(100); - if (lcd_clicked()) { - break; - } - } - } - } - lcd_return_to_status(); - lcd_update_enable(true); + if (mmu_enabled) + { + const uint8_t filament = choose_menu_P(_i("Select PLA filament:"),_T(MSG_FILAMENT),_i("Cancel")); ////c=20 r=1 ////c=19 r=1 + if (filament < 5) + { + lcd_commands_step = 20 + filament; + lcd_commands_type = LCD_COMMAND_V2_CAL; + } + } + else + { + bool loaded = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is PLA filament loaded?"), false, true);////MSG_PLA_FILAMENT_LOADED c=20 r=2 + if (loaded) { + lcd_commands_type = LCD_COMMAND_V2_CAL; + } + else { + lcd_display_message_fullscreen_P(_i("Please load PLA filament first."));////MSG_PLEASE_LOAD_PLA c=20 r=4 + for (int i = 0; i < 20; i++) { //wait max. 2s + delay_keep_alive(100); + if (lcd_clicked()) { + break; + } + } + } + } + lcd_return_to_status(); + lcd_update_enable(true); } void lcd_wizard() { - bool result = true; - if (calibration_status() != CALIBRATION_STATUS_ASSEMBLED) { - result = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Running Wizard will delete current calibration results and start from the beginning. Continue?"), false, false);////MSG_WIZARD_RERUN c=20 r=7 - } - if (result) { - calibration_status_store(CALIBRATION_STATUS_ASSEMBLED); - lcd_wizard(WizState::Run); - } - else { - lcd_return_to_status(); - lcd_update_enable(true); - lcd_update(2); - } + bool result = true; + if (calibration_status() != CALIBRATION_STATUS_ASSEMBLED) { + result = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Running Wizard will delete current calibration results and start from the beginning. Continue?"), false, false);////MSG_WIZARD_RERUN c=20 r=7 + } + if (result) { + calibration_status_store(CALIBRATION_STATUS_ASSEMBLED); + lcd_wizard(WizState::Run); + } + else { + lcd_return_to_status(); + lcd_update_enable(true); + lcd_update(2); + } } void lcd_language() { - lcd_update_enable(true); - lcd_clear(); - menu_goto(lcd_language_menu, 0, true, true); - lcd_timeoutToStatus.stop(); //infinite timeout - lcd_draw_update = 2; - while ((menu_menu != lcd_status_screen) && (!lang_is_selected())) - { - delay(50); - lcd_update(0); - manage_heater(); - manage_inactivity(true); - } - if (lang_is_selected()) - lcd_return_to_status(); - else - lang_select(LANG_ID_PRI); + lcd_update_enable(true); + lcd_clear(); + menu_goto(lcd_language_menu, 0, true, true); + lcd_timeoutToStatus.stop(); //infinite timeout + lcd_draw_update = 2; + while ((menu_menu != lcd_status_screen) && (!lang_is_selected())) + { + delay(50); + lcd_update(0); + manage_heater(); + manage_inactivity(true); + } + if (lang_is_selected()) + lcd_return_to_status(); + else + lang_select(LANG_ID_PRI); } static void wait_preheat() @@ -4363,58 +4392,58 @@ static void wait_preheat() 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); delay_keep_alive(2000); lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING)); - lcd_set_custom_characters(); - while (abs(degHotend(0) - degTargetHotend(0)) > 3) { + lcd_set_custom_characters(); + while (abs(degHotend(0) - degTargetHotend(0)) > 3) { lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING)); lcd_set_cursor(0, 4); - //Print the hotend temperature (9 chars total) - lcdui_print_temp(LCD_STR_THERMOMETER[0], (int)(degHotend(0) + 0.5), (int)(degTargetHotend(0) + 0.5)); + //Print the hotend temperature (9 chars total) + lcdui_print_temp(LCD_STR_THERMOMETER[0], (int)(degHotend(0) + 0.5), (int)(degTargetHotend(0) + 0.5)); delay_keep_alive(1000); } - + } static void lcd_wizard_unload() { - if(mmu_enabled) - { - int8_t unload = lcd_show_multiscreen_message_two_choices_and_wait_P( - _i("Use unload to remove filament 1 if it protrudes outside of the rear MMU tube. Use eject if it is hidden in tube.") - ,false, true, _i("Unload"), _i("Eject")); - if (unload) - { - extr_unload_0(); - } - else - { - mmu_eject_fil_0(); - } - } - else - { - unload_filament(); - } + if(mmu_enabled) + { + int8_t unload = lcd_show_multiscreen_message_two_choices_and_wait_P( + _i("Use unload to remove filament 1 if it protrudes outside of the rear MMU tube. Use eject if it is hidden in tube.") + ,false, true, _i("Unload"), _i("Eject")); + if (unload) + { + extr_unload_0(); + } + else + { + mmu_eject_fil_0(); + } + } + else + { + unload_filament(); + } } static void lcd_wizard_load() { - if (mmu_enabled) - { - lcd_show_fullscreen_message_and_wait_P(_i("Please insert PLA filament to the first tube of MMU, then press the knob to load it."));////c=20 r=8 - } - else - { - lcd_show_fullscreen_message_and_wait_P(_i("Please insert PLA filament to the extruder, then press knob to load it."));////MSG_WIZARD_LOAD_FILAMENT c=20 r=8 - } - lcd_update_enable(false); - lcd_clear(); - lcd_puts_at_P(0, 2, _T(MSG_LOADING_FILAMENT)); + if (mmu_enabled) + { + lcd_show_fullscreen_message_and_wait_P(_i("Please insert PLA filament to the first tube of MMU, then press the knob to load it."));////c=20 r=8 + } + else + { + lcd_show_fullscreen_message_and_wait_P(_i("Please insert PLA filament to the extruder, then press knob to load it."));////MSG_WIZARD_LOAD_FILAMENT c=20 r=8 + } + lcd_update_enable(false); + lcd_clear(); + lcd_puts_at_P(0, 2, _T(MSG_LOADING_FILAMENT)); #ifdef SNMM - change_extr(0); + change_extr(0); #endif - loading_flag = true; - gcode_M701(); + loading_flag = true; + gcode_M701(); } bool lcd_autoDepleteEnabled() @@ -4452,190 +4481,204 @@ bool lcd_autoDepleteEnabled() void lcd_wizard(WizState state) { using S = WizState; - bool end = false; - int wizard_event; - const char *msg = NULL; - while (!end) { - printf_P(PSTR("Wizard state: %d"), state); - switch (state) { - case S::Run: //Run wizard? - wizard_active = true; - wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?"), false, true);////MSG_WIZARD_WELCOME c=20 r=7 - if (wizard_event) { - state = S::Restore; - eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); - } - else { - eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); - end = true; - } - break; - case S::Restore: // restore calibration status - switch (calibration_status()) { - case CALIBRATION_STATUS_ASSEMBLED: state = S::Selftest; break; //run selftest - case CALIBRATION_STATUS_XYZ_CALIBRATION: state = S::Xyz; break; //run xyz cal. - case CALIBRATION_STATUS_Z_CALIBRATION: state = S::Z; break; //run z cal. - case CALIBRATION_STATUS_LIVE_ADJUST: state = S::IsFil; break; //run live adjust - case CALIBRATION_STATUS_CALIBRATED: end = true; eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); break; - default: state = S::Selftest; break; //if calibration status is unknown, run wizard from the beginning - } - break; - case S::Selftest: - lcd_show_fullscreen_message_and_wait_P(_i("First, I will run the selftest to check most common assembly problems."));////MSG_WIZARD_SELFTEST c=20 r=8 - wizard_event = lcd_selftest(); - if (wizard_event) { - calibration_status_store(CALIBRATION_STATUS_XYZ_CALIBRATION); - state = S::Xyz; - } - else end = true; - break; - case S::Xyz: //xyz calibration - lcd_show_fullscreen_message_and_wait_P(_i("I will run xyz calibration now. It will take approx. 12 mins."));////MSG_WIZARD_XYZ_CAL c=20 r=8 - wizard_event = gcode_M45(false, 0); - if (wizard_event) state = S::IsFil; - else end = true; - break; - case S::Z: //z calibration - lcd_show_fullscreen_message_and_wait_P(_i("Please remove shipping helpers first.")); - lcd_show_fullscreen_message_and_wait_P(_i("Now remove the test print from steel sheet.")); - lcd_show_fullscreen_message_and_wait_P(_i("I will run z calibration now."));////MSG_WIZARD_Z_CAL c=20 r=8 - wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false); - if (!wizard_event) lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET)); - wizard_event = gcode_M45(true, 0); - if (wizard_event) { - //current filament needs to be unloaded and then new filament should be loaded - //start to preheat nozzle for unloading remaining PLA filament - setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0); - lcd_display_message_fullscreen_P(_i("Now I will preheat nozzle for PLA.")); - wait_preheat(); - //unload current filament - lcd_wizard_unload(); - //load filament - lcd_wizard_load(); - setTargetHotend(0, 0); //we are finished, cooldown nozzle - state = S::Finish; //shipped, no need to set first layer, go to final message directly - } - else end = true; - break; - case S::IsFil: //is filament loaded? - //start to preheat nozzle and bed to save some time later - setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0); - setTargetBed(PLA_PREHEAT_HPB_TEMP); - if (mmu_enabled) - { - wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament 1 loaded?"), false);////c=20 r=2 - } else - { - wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), false);////MSG_WIZARD_FILAMENT_LOADED c=20 r=2 - } - if (wizard_event) state = S::IsPla; - else - { - if(mmu_enabled) state = S::LoadFil; - else state = S::PreheatPla; - } - break; - case S::PreheatPla: + bool end = false; + int wizard_event; + const char *msg = NULL; + while (!end) { + printf_P(PSTR("Wizard state: %d"), state); + switch (state) { + case S::Run: //Run wizard? + wizard_active = true; + wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?"), false, true);////MSG_WIZARD_WELCOME c=20 r=7 + if (wizard_event) { + state = S::Restore; + eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1); + } + else { + eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); + end = true; + } + break; + case S::Restore: // restore calibration status + switch (calibration_status()) { + case CALIBRATION_STATUS_ASSEMBLED: + state = S::Selftest; + break; //run selftest + case CALIBRATION_STATUS_XYZ_CALIBRATION: + state = S::Xyz; + break; //run xyz cal. + case CALIBRATION_STATUS_Z_CALIBRATION: + state = S::Z; + break; //run z cal. + case CALIBRATION_STATUS_LIVE_ADJUST: + state = S::IsFil; + break; //run live adjust + case CALIBRATION_STATUS_CALIBRATED: + end = true; + eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); + break; + default: + state = S::Selftest; + break; //if calibration status is unknown, run wizard from the beginning + } + break; + case S::Selftest: + lcd_show_fullscreen_message_and_wait_P(_i("First, I will run the selftest to check most common assembly problems."));////MSG_WIZARD_SELFTEST c=20 r=8 + wizard_event = lcd_selftest(); + if (wizard_event) { + calibration_status_store(CALIBRATION_STATUS_XYZ_CALIBRATION); + state = S::Xyz; + } + else end = true; + break; + case S::Xyz: //xyz calibration + lcd_show_fullscreen_message_and_wait_P(_i("I will run xyz calibration now. It will take approx. 12 mins."));////MSG_WIZARD_XYZ_CAL c=20 r=8 + wizard_event = gcode_M45(false, 0); + if (wizard_event) state = S::IsFil; + else end = true; + break; + case S::Z: //z calibration + lcd_show_fullscreen_message_and_wait_P(_i("Please remove shipping helpers first.")); + lcd_show_fullscreen_message_and_wait_P(_i("Now remove the test print from steel sheet.")); + lcd_show_fullscreen_message_and_wait_P(_i("I will run z calibration now."));////MSG_WIZARD_Z_CAL c=20 r=8 + wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false); + if (!wizard_event) lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET)); + wizard_event = gcode_M45(true, 0); + if (wizard_event) { + //current filament needs to be unloaded and then new filament should be loaded + //start to preheat nozzle for unloading remaining PLA filament + setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0); + lcd_display_message_fullscreen_P(_i("Now I will preheat nozzle for PLA.")); + wait_preheat(); + //unload current filament + lcd_wizard_unload(); + //load filament + lcd_wizard_load(); + setTargetHotend(0, 0); //we are finished, cooldown nozzle + state = S::Finish; //shipped, no need to set first layer, go to final message directly + } + else end = true; + break; + case S::IsFil: //is filament loaded? + //start to preheat nozzle and bed to save some time later + setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0); + setTargetBed(PLA_PREHEAT_HPB_TEMP); + if (mmu_enabled) + { + wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament 1 loaded?"), false);////c=20 r=2 + } else + { + wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), false);////MSG_WIZARD_FILAMENT_LOADED c=20 r=2 + } + if (wizard_event) state = S::IsPla; + else + { + if(mmu_enabled) state = S::LoadFil; + else state = S::PreheatPla; + } + break; + case S::PreheatPla: #ifndef SNMM - lcd_display_message_fullscreen_P(_i("Now I will preheat nozzle for PLA."));////MSG_WIZARD_WILL_PREHEAT c=20 r=4 - wait_preheat(); + lcd_display_message_fullscreen_P(_i("Now I will preheat nozzle for PLA."));////MSG_WIZARD_WILL_PREHEAT c=20 r=4 + wait_preheat(); #endif //not SNMM - state = S::LoadFil; - break; - case S::Preheat: - menu_goto(lcd_preheat_menu,0,false,true); - lcd_show_fullscreen_message_and_wait_P(_i("Select nozzle preheat temperature which matches your material.")); - end = true; // Leave wizard temporarily for lcd_preheat_menu - break; - case S::Unload: - wait_preheat(); - lcd_wizard_unload(); state = S::LoadFil; break; - case S::LoadFil: //load filament - lcd_wizard_load(); - state = S::Lay1Cal; - break; - case S::IsPla: - wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is it PLA filament?"), false, true);////MSG_WIZARD_PLA_FILAMENT c=20 r=2 - if (wizard_event) state = S::Lay1Cal; - else state = S::Preheat; - break; - case S::Lay1Cal: - lcd_show_fullscreen_message_and_wait_P(_i("Now I will calibrate distance between tip of the nozzle and heatbed surface."));////MSG_WIZARD_V2_CAL c=20 r=8 - lcd_show_fullscreen_message_and_wait_P(_i("I will start to print line and you will gradually lower the nozzle by rotating the knob, until you reach optimal height. Check the pictures in our handbook in chapter Calibration."));////MSG_WIZARD_V2_CAL_2 c=20 r=12 - lcd_commands_type = LCD_COMMAND_V2_CAL; - lcd_return_to_status(); - end = true; - break; - case S::RepeatLay1Cal: //repeat first layer cal.? - wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Do you want to repeat last step to readjust distance between nozzle and heatbed?"), false);////MSG_WIZARD_REPEAT_V2_CAL c=20 r=7 - if (wizard_event) { - lcd_show_fullscreen_message_and_wait_P(_i("Please clean heatbed and then press the knob."));////MSG_WIZARD_CLEAN_HEATBED c=20 r=8 - state = S::Lay1Cal; - } - else { - state = S::Finish; - } - break; - case S::Finish: //we are finished - eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); - end = true; - break; + case S::Preheat: + menu_goto(lcd_preheat_menu,0,false,true); + lcd_show_fullscreen_message_and_wait_P(_i("Select nozzle preheat temperature which matches your material.")); + end = true; // Leave wizard temporarily for lcd_preheat_menu + break; + case S::Unload: + wait_preheat(); + lcd_wizard_unload(); + state = S::LoadFil; + break; + case S::LoadFil: //load filament + lcd_wizard_load(); + state = S::Lay1Cal; + break; + case S::IsPla: + wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is it PLA filament?"), false, true);////MSG_WIZARD_PLA_FILAMENT c=20 r=2 + if (wizard_event) state = S::Lay1Cal; + else state = S::Preheat; + break; + case S::Lay1Cal: + lcd_show_fullscreen_message_and_wait_P(_i("Now I will calibrate distance between tip of the nozzle and heatbed surface."));////MSG_WIZARD_V2_CAL c=20 r=8 + lcd_show_fullscreen_message_and_wait_P(_i("I will start to print line and you will gradually lower the nozzle by rotating the knob, until you reach optimal height. Check the pictures in our handbook in chapter Calibration."));////MSG_WIZARD_V2_CAL_2 c=20 r=12 + lcd_commands_type = LCD_COMMAND_V2_CAL; + lcd_return_to_status(); + end = true; + break; + case S::RepeatLay1Cal: //repeat first layer cal.? + wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Do you want to repeat last step to readjust distance between nozzle and heatbed?"), false);////MSG_WIZARD_REPEAT_V2_CAL c=20 r=7 + if (wizard_event) { + lcd_show_fullscreen_message_and_wait_P(_i("Please clean heatbed and then press the knob."));////MSG_WIZARD_CLEAN_HEATBED c=20 r=8 + state = S::Lay1Cal; + } + else { + state = S::Finish; + } + break; + case S::Finish: //we are finished + eeprom_write_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); + end = true; + break; - default: break; - } - } + default: + break; + } + } - printf_P(_N("Wizard end state: %d\n"), state); - switch (state) { //final message - case S::Restore: //printer was already calibrated - msg = _T(MSG_WIZARD_DONE); - break; - case S::Selftest: //selftest - case S::Xyz: //xyz cal. - case S::Z: //z cal. - msg = _T(MSG_WIZARD_CALIBRATION_FAILED); - break; - case S::Finish: //we are finished - - msg = _T(MSG_WIZARD_DONE); - lcd_reset_alert_level(); - lcd_setstatuspgm(_T(WELCOME_MSG)); - lcd_return_to_status(); - break; - - default: - msg = _T(MSG_WIZARD_QUIT); - break; + printf_P(_N("Wizard end state: %d\n"), state); + switch (state) { //final message + case S::Restore: //printer was already calibrated + msg = _T(MSG_WIZARD_DONE); + break; + case S::Selftest: //selftest + case S::Xyz: //xyz cal. + case S::Z: //z cal. + msg = _T(MSG_WIZARD_CALIBRATION_FAILED); + break; + case S::Finish: //we are finished - } - if (!((S::Lay1Cal == state) || (S::Preheat == state))) { - lcd_show_fullscreen_message_and_wait_P(msg); - wizard_active = false; - } - lcd_update_enable(true); - lcd_update(2); + msg = _T(MSG_WIZARD_DONE); + lcd_reset_alert_level(); + lcd_setstatuspgm(_T(WELCOME_MSG)); + lcd_return_to_status(); + break; + + default: + msg = _T(MSG_WIZARD_QUIT); + break; + + } + if (!((S::Lay1Cal == state) || (S::Preheat == state))) { + lcd_show_fullscreen_message_and_wait_P(msg); + wizard_active = false; + } + lcd_update_enable(true); + lcd_update(2); } #ifdef TMC2130 void lcd_settings_linearity_correction_menu(void) { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); #ifdef TMC2130_LINEARITY_CORRECTION_XYZ - //tmc2130_wave_fac[X_AXIS] + //tmc2130_wave_fac[X_AXIS] - MENU_ITEM_EDIT_int3_P(_i("X-correct"), &tmc2130_wave_fac[X_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 - MENU_ITEM_EDIT_int3_P(_i("Y-correct"), &tmc2130_wave_fac[Y_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 - MENU_ITEM_EDIT_int3_P(_i("Z-correct"), &tmc2130_wave_fac[Z_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 + MENU_ITEM_EDIT_int3_P(_i("X-correct"), &tmc2130_wave_fac[X_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 + MENU_ITEM_EDIT_int3_P(_i("Y-correct"), &tmc2130_wave_fac[Y_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 + MENU_ITEM_EDIT_int3_P(_i("Z-correct"), &tmc2130_wave_fac[Z_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 #endif //TMC2130_LINEARITY_CORRECTION_XYZ - MENU_ITEM_EDIT_int3_P(_i("E-correct"), &tmc2130_wave_fac[E_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 - MENU_END(); - if(menu_leaving) - { - lcd_settings_linearity_correction_menu_save(); - } + MENU_ITEM_EDIT_int3_P(_i("E-correct"), &tmc2130_wave_fac[E_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=9 r=0 + MENU_END(); + if(menu_leaving) + { + lcd_settings_linearity_correction_menu_save(); + } } #endif // TMC2130 @@ -4826,60 +4869,60 @@ while (0) static void lcd_settings_menu() { - EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu)); - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); + EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu)); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_SUBMENU_P(_i("Temperature"), lcd_control_temperature_menu);////MSG_TEMPERATURE c=0 r=0 - if (!homing_flag) - MENU_ITEM_SUBMENU_P(_i("Move axis"), lcd_move_menu_1mm);////MSG_MOVE_AXIS c=0 r=0 - if (!isPrintPaused) - MENU_ITEM_GCODE_P(_i("Disable steppers"), PSTR("M84"));////MSG_DISABLE_STEPPERS c=0 r=0 + MENU_ITEM_SUBMENU_P(_i("Temperature"), lcd_control_temperature_menu);////MSG_TEMPERATURE c=0 r=0 + if (!homing_flag) + MENU_ITEM_SUBMENU_P(_i("Move axis"), lcd_move_menu_1mm);////MSG_MOVE_AXIS c=0 r=0 + if (!isPrintPaused) + MENU_ITEM_GCODE_P(_i("Disable steppers"), PSTR("M84"));////MSG_DISABLE_STEPPERS c=0 r=0 - SETTINGS_FILAMENT_SENSOR; + SETTINGS_FILAMENT_SENSOR; - SETTINGS_AUTO_DEPLETE; + SETTINGS_AUTO_DEPLETE; - if (fans_check_enabled == true) - MENU_ITEM_FUNCTION_P(_i("Fans check [on]"), lcd_set_fan_check);////MSG_FANS_CHECK_ON c=17 r=1 - else - MENU_ITEM_FUNCTION_P(_i("Fans check [off]"), lcd_set_fan_check);////MSG_FANS_CHECK_OFF c=17 r=1 + if (fans_check_enabled == true) + MENU_ITEM_FUNCTION_P(_i("Fans check [on]"), lcd_set_fan_check);////MSG_FANS_CHECK_ON c=17 r=1 + else + MENU_ITEM_FUNCTION_P(_i("Fans check [off]"), lcd_set_fan_check);////MSG_FANS_CHECK_OFF c=17 r=1 - SETTINGS_SILENT_MODE; + SETTINGS_SILENT_MODE; #if defined (TMC2130) && defined (LINEARITY_CORRECTION) MENU_ITEM_SUBMENU_P(_i("Lin. correction"), lcd_settings_linearity_correction_menu); #endif //LINEARITY_CORRECTION && TMC2130 - if (temp_cal_active == false) - MENU_ITEM_FUNCTION_P(_i("Temp. cal. [off]"), lcd_temp_calibration_set);////MSG_TEMP_CALIBRATION_OFF c=20 r=1 - else - MENU_ITEM_FUNCTION_P(_i("Temp. cal. [on]"), lcd_temp_calibration_set);////MSG_TEMP_CALIBRATION_ON c=20 r=1 + if (temp_cal_active == false) + MENU_ITEM_FUNCTION_P(_i("Temp. cal. [off]"), lcd_temp_calibration_set);////MSG_TEMP_CALIBRATION_OFF c=20 r=1 + else + MENU_ITEM_FUNCTION_P(_i("Temp. cal. [on]"), lcd_temp_calibration_set);////MSG_TEMP_CALIBRATION_ON c=20 r=1 #ifdef HAS_SECOND_SERIAL_PORT - if (selectedSerialPort == 0) - MENU_ITEM_FUNCTION_P(_i("RPi port [off]"), lcd_second_serial_set);////MSG_SECOND_SERIAL_OFF c=17 r=1 - else - MENU_ITEM_FUNCTION_P(_i("RPi port [on]"), lcd_second_serial_set);////MSG_SECOND_SERIAL_ON c=17 r=1 + if (selectedSerialPort == 0) + MENU_ITEM_FUNCTION_P(_i("RPi port [off]"), lcd_second_serial_set);////MSG_SECOND_SERIAL_OFF c=17 r=1 + else + MENU_ITEM_FUNCTION_P(_i("RPi port [on]"), lcd_second_serial_set);////MSG_SECOND_SERIAL_ON c=17 r=1 #endif //HAS_SECOND_SERIAL - if (!isPrintPaused && !homing_flag) - MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z); + if (!isPrintPaused && !homing_flag) + MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z); #if (LANG_MODE != 0) - MENU_ITEM_SUBMENU_P(_i("Select language"), lcd_language_menu);////MSG_LANGUAGE_SELECT c=0 r=0 + MENU_ITEM_SUBMENU_P(_i("Select language"), lcd_language_menu);////MSG_LANGUAGE_SELECT c=0 r=0 #endif //(LANG_MODE != 0) - SETTINGS_SD; - SETTINGS_SOUND; + SETTINGS_SD; + SETTINGS_SOUND; - if (farm_mode) - { - MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no); - MENU_ITEM_FUNCTION_P(PSTR("Disable farm mode"), lcd_disable_farm_mode); - } + if (farm_mode) + { + MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no); + MENU_ITEM_FUNCTION_P(PSTR("Disable farm mode"), lcd_disable_farm_mode); + } - MENU_END(); + MENU_END(); } #ifdef TMC2130 @@ -4913,204 +4956,206 @@ static void lcd_settings_linearity_correction_menu_save() static void lcd_calibration_menu() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - if (!isPrintPaused) - { - MENU_ITEM_FUNCTION_P(_i("Wizard"), lcd_wizard);////MSG_WIZARD c=17 r=1 - MENU_ITEM_SUBMENU_P(_i("First layer cal."), lcd_v2_calibration);////MSG_V2_CALIBRATION c=17 r=1 - MENU_ITEM_GCODE_P(_T(MSG_AUTO_HOME), PSTR("G28 W")); - MENU_ITEM_FUNCTION_P(_i("Selftest "), lcd_selftest_v);////MSG_SELFTEST c=0 r=0 + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + if (!isPrintPaused) + { + MENU_ITEM_FUNCTION_P(_i("Wizard"), lcd_wizard);////MSG_WIZARD c=17 r=1 + MENU_ITEM_SUBMENU_P(_i("First layer cal."), lcd_v2_calibration);////MSG_V2_CALIBRATION c=17 r=1 + MENU_ITEM_GCODE_P(_T(MSG_AUTO_HOME), PSTR("G28 W")); + MENU_ITEM_FUNCTION_P(_i("Selftest "), lcd_selftest_v);////MSG_SELFTEST c=0 r=0 #ifdef MK1BP - // MK1 - // "Calibrate Z" - MENU_ITEM_GCODE_P(_T(MSG_HOMEYZ), PSTR("G28 Z")); + // MK1 + // "Calibrate Z" + MENU_ITEM_GCODE_P(_T(MSG_HOMEYZ), PSTR("G28 Z")); #else //MK1BP - // MK2 - MENU_ITEM_FUNCTION_P(_i("Calibrate XYZ"), lcd_mesh_calibration);////MSG_CALIBRATE_BED c=0 r=0 - // "Calibrate Z" with storing the reference values to EEPROM. - MENU_ITEM_SUBMENU_P(_T(MSG_HOMEYZ), lcd_mesh_calibration_z); + // MK2 + MENU_ITEM_FUNCTION_P(_i("Calibrate XYZ"), lcd_mesh_calibration);////MSG_CALIBRATE_BED c=0 r=0 + // "Calibrate Z" with storing the reference values to EEPROM. + MENU_ITEM_SUBMENU_P(_T(MSG_HOMEYZ), lcd_mesh_calibration_z); #ifndef SNMM - //MENU_ITEM_FUNCTION_P(_i("Calibrate E"), lcd_calibrate_extruder);////MSG_CALIBRATE_E c=20 r=1 + //MENU_ITEM_FUNCTION_P(_i("Calibrate E"), lcd_calibrate_extruder);////MSG_CALIBRATE_E c=20 r=1 #endif - // "Mesh Bed Leveling" - MENU_ITEM_SUBMENU_P(_i("Mesh Bed Leveling"), lcd_mesh_bedleveling);////MSG_MESH_BED_LEVELING c=0 r=0 - + // "Mesh Bed Leveling" + MENU_ITEM_SUBMENU_P(_i("Mesh Bed Leveling"), lcd_mesh_bedleveling);////MSG_MESH_BED_LEVELING c=0 r=0 + #endif //MK1BP - MENU_ITEM_SUBMENU_P(_i("Bed level correct"), lcd_adjust_bed);////MSG_BED_CORRECTION_MENU c=0 r=0 - MENU_ITEM_SUBMENU_P(_i("PID calibration"), pid_extruder);////MSG_PID_EXTRUDER c=17 r=1 + MENU_ITEM_SUBMENU_P(_i("Bed level correct"), lcd_adjust_bed);////MSG_BED_CORRECTION_MENU c=0 r=0 + MENU_ITEM_SUBMENU_P(_i("PID calibration"), pid_extruder);////MSG_PID_EXTRUDER c=17 r=1 #ifdef TMC2130 - MENU_ITEM_SUBMENU_P(_i("Show pinda state"), menu_show_pinda_state); + MENU_ITEM_SUBMENU_P(_i("Show pinda state"), menu_show_pinda_state); #else - MENU_ITEM_SUBMENU_P(_i("Show end stops"), menu_show_end_stops);////MSG_SHOW_END_STOPS c=17 r=1 + MENU_ITEM_SUBMENU_P(_i("Show end stops"), menu_show_end_stops);////MSG_SHOW_END_STOPS c=17 r=1 #endif #ifndef MK1BP - MENU_ITEM_GCODE_P(_i("Reset XYZ calibr."), PSTR("M44"));////MSG_CALIBRATE_BED_RESET c=0 r=0 + MENU_ITEM_GCODE_P(_i("Reset XYZ calibr."), PSTR("M44"));////MSG_CALIBRATE_BED_RESET c=0 r=0 #endif //MK1BP #ifndef SNMM - //MENU_ITEM_FUNCTION_P(MSG_RESET_CALIBRATE_E, lcd_extr_cal_reset); + //MENU_ITEM_FUNCTION_P(MSG_RESET_CALIBRATE_E, lcd_extr_cal_reset); #endif #ifndef MK1BP - MENU_ITEM_SUBMENU_P(_i("Temp. calibration"), lcd_pinda_calibration_menu);////MSG_CALIBRATION_PINDA_MENU c=17 r=1 + MENU_ITEM_SUBMENU_P(_i("Temp. calibration"), lcd_pinda_calibration_menu);////MSG_CALIBRATION_PINDA_MENU c=17 r=1 #endif //MK1BP - } - - MENU_END(); + } + + MENU_END(); } void bowden_menu() { - int enc_dif = lcd_encoder_diff; - int cursor_pos = 0; - lcd_clear(); - lcd_set_cursor(0, 0); - lcd_print(">"); - for (int i = 0; i < 4; i++) { - lcd_set_cursor(1, i); - lcd_print("Extruder "); - lcd_print(i); - lcd_print(": "); - EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); - lcd_print(bowden_length[i] - 48); + int enc_dif = lcd_encoder_diff; + int cursor_pos = 0; + lcd_clear(); + lcd_set_cursor(0, 0); + lcd_print(">"); + for (int i = 0; i < 4; i++) { + lcd_set_cursor(1, i); + lcd_print("Extruder "); + lcd_print(i); + lcd_print(": "); + EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); + lcd_print(bowden_length[i] - 48); - } - enc_dif = lcd_encoder_diff; + } + enc_dif = lcd_encoder_diff; - while (1) { + while (1) { - manage_heater(); - manage_inactivity(true); + manage_heater(); + manage_inactivity(true); - if (abs((enc_dif - lcd_encoder_diff)) > 2) { + if (abs((enc_dif - lcd_encoder_diff)) > 2) { - if (enc_dif > lcd_encoder_diff) { - cursor_pos--; - } + if (enc_dif > lcd_encoder_diff) { + cursor_pos--; + } - if (enc_dif < lcd_encoder_diff) { - cursor_pos++; - } + if (enc_dif < lcd_encoder_diff) { + cursor_pos++; + } - if (cursor_pos > 3) { - cursor_pos = 3; - } + if (cursor_pos > 3) { + cursor_pos = 3; + } - if (cursor_pos < 0) { - cursor_pos = 0; - } + if (cursor_pos < 0) { + cursor_pos = 0; + } - lcd_set_cursor(0, 0); - lcd_print(" "); - lcd_set_cursor(0, 1); - lcd_print(" "); - lcd_set_cursor(0, 2); - lcd_print(" "); - lcd_set_cursor(0, 3); - lcd_print(" "); - lcd_set_cursor(0, cursor_pos); - lcd_print(">"); - - enc_dif = lcd_encoder_diff; - delay(100); - } + lcd_set_cursor(0, 0); + lcd_print(" "); + lcd_set_cursor(0, 1); + lcd_print(" "); + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); + lcd_set_cursor(0, cursor_pos); + lcd_print(">"); - if (lcd_clicked()) { - - lcd_clear(); - while (1) { - - manage_heater(); - manage_inactivity(true); - - lcd_set_cursor(1, 1); - lcd_print("Extruder "); - lcd_print(cursor_pos); - lcd_print(": "); - lcd_set_cursor(13, 1); - lcd_print(bowden_length[cursor_pos] - 48); - - if (abs((enc_dif - lcd_encoder_diff)) > 2) { - if (enc_dif > lcd_encoder_diff) { - bowden_length[cursor_pos]--; - lcd_set_cursor(13, 1); - lcd_print(bowden_length[cursor_pos] - 48); - enc_dif = lcd_encoder_diff; - } - - if (enc_dif < lcd_encoder_diff) { - bowden_length[cursor_pos]++; - lcd_set_cursor(13, 1); - lcd_print(bowden_length[cursor_pos] - 48); - enc_dif = lcd_encoder_diff; - } - } - delay(100); - if (lcd_clicked()) { - EEPROM_save_B(EEPROM_BOWDEN_LENGTH + cursor_pos * 2, &bowden_length[cursor_pos]); - if (lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Continue with another bowden?"))) { - lcd_update_enable(true); - lcd_clear(); - enc_dif = lcd_encoder_diff; - lcd_set_cursor(0, cursor_pos); - lcd_print(">"); - for (int i = 0; i < 4; i++) { - lcd_set_cursor(1, i); - lcd_print("Extruder "); - lcd_print(i); - lcd_print(": "); - EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); - lcd_print(bowden_length[i] - 48); - - } - break; - } - else return; - } - } - } - } + enc_dif = lcd_encoder_diff; + delay(100); + } + + if (lcd_clicked()) { + + lcd_clear(); + while (1) { + + manage_heater(); + manage_inactivity(true); + + lcd_set_cursor(1, 1); + lcd_print("Extruder "); + lcd_print(cursor_pos); + lcd_print(": "); + lcd_set_cursor(13, 1); + lcd_print(bowden_length[cursor_pos] - 48); + + if (abs((enc_dif - lcd_encoder_diff)) > 2) { + if (enc_dif > lcd_encoder_diff) { + bowden_length[cursor_pos]--; + lcd_set_cursor(13, 1); + lcd_print(bowden_length[cursor_pos] - 48); + enc_dif = lcd_encoder_diff; + } + + if (enc_dif < lcd_encoder_diff) { + bowden_length[cursor_pos]++; + lcd_set_cursor(13, 1); + lcd_print(bowden_length[cursor_pos] - 48); + enc_dif = lcd_encoder_diff; + } + } + delay(100); + if (lcd_clicked()) { + EEPROM_save_B(EEPROM_BOWDEN_LENGTH + cursor_pos * 2, &bowden_length[cursor_pos]); + if (lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Continue with another bowden?"))) { + lcd_update_enable(true); + lcd_clear(); + enc_dif = lcd_encoder_diff; + lcd_set_cursor(0, cursor_pos); + lcd_print(">"); + for (int i = 0; i < 4; i++) { + lcd_set_cursor(1, i); + lcd_print("Extruder "); + lcd_print(i); + lcd_print(": "); + EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]); + lcd_print(bowden_length[i] - 48); + + } + break; + } + else return; + } + } + } + } } //#ifdef SNMM static char snmm_stop_print_menu() { //menu for choosing which filaments will be unloaded in stop print - lcd_clear(); - lcd_puts_at_P(0,0,_T(MSG_UNLOAD_FILAMENT)); lcd_print(":"); - lcd_set_cursor(0, 1); lcd_print(">"); - lcd_puts_at_P(1,2,_i("Used during print"));////MSG_USED c=19 r=1 - lcd_puts_at_P(1,3,_i("Current"));////MSG_CURRENT c=19 r=1 - char cursor_pos = 1; - int enc_dif = 0; - KEEPALIVE_STATE(PAUSED_FOR_USER); - while (1) { - manage_heater(); - manage_inactivity(true); - if (abs((enc_dif - lcd_encoder_diff)) > 4) { - - if ((abs(enc_dif - lcd_encoder_diff)) > 1) { - if (enc_dif > lcd_encoder_diff) cursor_pos--; - if (enc_dif < lcd_encoder_diff) cursor_pos++; - if (cursor_pos > 3) cursor_pos = 3; - if (cursor_pos < 1) cursor_pos = 1; - - lcd_set_cursor(0, 1); - lcd_print(" "); - lcd_set_cursor(0, 2); - lcd_print(" "); - lcd_set_cursor(0, 3); - lcd_print(" "); - lcd_set_cursor(0, cursor_pos); - lcd_print(">"); - enc_dif = lcd_encoder_diff; - delay(100); - } - } - if (lcd_clicked()) { - KEEPALIVE_STATE(IN_HANDLER); - return(cursor_pos - 1); - } - } - + lcd_clear(); + lcd_puts_at_P(0,0,_T(MSG_UNLOAD_FILAMENT)); + lcd_print(":"); + lcd_set_cursor(0, 1); + lcd_print(">"); + lcd_puts_at_P(1,2,_i("Used during print"));////MSG_USED c=19 r=1 + lcd_puts_at_P(1,3,_i("Current"));////MSG_CURRENT c=19 r=1 + char cursor_pos = 1; + int enc_dif = 0; + KEEPALIVE_STATE(PAUSED_FOR_USER); + while (1) { + manage_heater(); + manage_inactivity(true); + if (abs((enc_dif - lcd_encoder_diff)) > 4) { + + if ((abs(enc_dif - lcd_encoder_diff)) > 1) { + if (enc_dif > lcd_encoder_diff) cursor_pos--; + if (enc_dif < lcd_encoder_diff) cursor_pos++; + if (cursor_pos > 3) cursor_pos = 3; + if (cursor_pos < 1) cursor_pos = 1; + + lcd_set_cursor(0, 1); + lcd_print(" "); + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); + lcd_set_cursor(0, cursor_pos); + lcd_print(">"); + enc_dif = lcd_encoder_diff; + delay(100); + } + } + if (lcd_clicked()) { + KEEPALIVE_STATE(IN_HANDLER); + return(cursor_pos - 1); + } + } + } //! @brief Select one of numbered items @@ -5130,20 +5175,20 @@ uint8_t choose_menu_P(const char *header, const char *item, const char *last_ite //following code should handle 3 to 127 number of items well const int8_t items_no = last_item?(mmu_enabled?6:5):(mmu_enabled?5:4); const uint8_t item_len = item?strlen_P(item):0; - int8_t first = 0; - int8_t enc_dif = lcd_encoder_diff; - int8_t cursor_pos = 1; - - lcd_clear(); - - KEEPALIVE_STATE(PAUSED_FOR_USER); - while (1) - { - manage_heater(); - manage_inactivity(true); + int8_t first = 0; + int8_t enc_dif = lcd_encoder_diff; + int8_t cursor_pos = 1; + + lcd_clear(); + + KEEPALIVE_STATE(PAUSED_FOR_USER); + while (1) + { + manage_heater(); + manage_inactivity(true); - if (abs((enc_dif - lcd_encoder_diff)) > 4) - { + if (abs((enc_dif - lcd_encoder_diff)) > 4) + { if (enc_dif > lcd_encoder_diff) { cursor_pos--; @@ -5154,10 +5199,10 @@ uint8_t choose_menu_P(const char *header, const char *item, const char *last_ite cursor_pos++; } enc_dif = lcd_encoder_diff; - } + } - if (cursor_pos > 3) - { + if (cursor_pos > 3) + { cursor_pos = 3; if (first < items_no - 3) { @@ -5205,450 +5250,476 @@ uint8_t choose_menu_P(const char *header, const char *item, const char *last_ite delay(100); - if (lcd_clicked()) - { - KEEPALIVE_STATE(IN_HANDLER); - lcd_encoder_diff = 0; - return(cursor_pos + first - 1); - } - } + if (lcd_clicked()) + { + KEEPALIVE_STATE(IN_HANDLER); + lcd_encoder_diff = 0; + return(cursor_pos + first - 1); + } + } } char reset_menu() { #ifdef SNMM - int items_no = 5; + int items_no = 5; #else - int items_no = 4; + int items_no = 4; #endif - static int first = 0; - int enc_dif = 0; - char cursor_pos = 0; - const char *item [items_no]; - - item[0] = "Language"; - item[1] = "Statistics"; - item[2] = "Shipping prep"; - item[3] = "All Data"; + static int first = 0; + int enc_dif = 0; + char cursor_pos = 0; + const char *item [items_no]; + + item[0] = "Language"; + item[1] = "Statistics"; + item[2] = "Shipping prep"; + item[3] = "All Data"; #ifdef SNMM - item[4] = "Bowden length"; + item[4] = "Bowden length"; #endif // SNMM - enc_dif = lcd_encoder_diff; - lcd_clear(); - lcd_set_cursor(0, 0); - lcd_print(">"); + enc_dif = lcd_encoder_diff; + lcd_clear(); + lcd_set_cursor(0, 0); + lcd_print(">"); - while (1) { + while (1) { - for (int i = 0; i < 4; i++) { - lcd_set_cursor(1, i); - lcd_print(item[first + i]); - } + for (int i = 0; i < 4; i++) { + lcd_set_cursor(1, i); + lcd_print(item[first + i]); + } - manage_heater(); - manage_inactivity(true); + manage_heater(); + manage_inactivity(true); - if (abs((enc_dif - lcd_encoder_diff)) > 4) { + if (abs((enc_dif - lcd_encoder_diff)) > 4) { - if ((abs(enc_dif - lcd_encoder_diff)) > 1) { - if (enc_dif > lcd_encoder_diff) { - cursor_pos--; - } + if ((abs(enc_dif - lcd_encoder_diff)) > 1) { + if (enc_dif > lcd_encoder_diff) { + cursor_pos--; + } - if (enc_dif < lcd_encoder_diff) { - cursor_pos++; - } + if (enc_dif < lcd_encoder_diff) { + cursor_pos++; + } - if (cursor_pos > 3) { - cursor_pos = 3; - if (first < items_no - 4) { - first++; - lcd_clear(); - } - } + if (cursor_pos > 3) { + cursor_pos = 3; + if (first < items_no - 4) { + first++; + lcd_clear(); + } + } - if (cursor_pos < 0) { - cursor_pos = 0; - if (first > 0) { - first--; - lcd_clear(); - } - } - lcd_set_cursor(0, 0); - lcd_print(" "); - lcd_set_cursor(0, 1); - lcd_print(" "); - lcd_set_cursor(0, 2); - lcd_print(" "); - lcd_set_cursor(0, 3); - lcd_print(" "); - lcd_set_cursor(0, cursor_pos); - lcd_print(">"); - enc_dif = lcd_encoder_diff; - delay(100); - } + if (cursor_pos < 0) { + cursor_pos = 0; + if (first > 0) { + first--; + lcd_clear(); + } + } + lcd_set_cursor(0, 0); + lcd_print(" "); + lcd_set_cursor(0, 1); + lcd_print(" "); + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); + lcd_set_cursor(0, cursor_pos); + lcd_print(">"); + enc_dif = lcd_encoder_diff; + delay(100); + } - } + } - if (lcd_clicked()) { - return(cursor_pos + first); - } + if (lcd_clicked()) { + return(cursor_pos + first); + } - } + } } static void lcd_disable_farm_mode() { - int8_t disable = lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Disable farm mode?"), true, false); //allow timeouting, default no - if (disable) - { - enquecommand_P(PSTR("G99")); - lcd_return_to_status(); - } - lcd_update_enable(true); - lcd_draw_update = 2; - + int8_t disable = lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Disable farm mode?"), true, false); //allow timeouting, default no + if (disable) + { + enquecommand_P(PSTR("G99")); + lcd_return_to_status(); + } + lcd_update_enable(true); + lcd_draw_update = 2; + } static void fil_load_menu() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_FUNCTION_P(_i("Load all"), load_all);////MSG_LOAD_ALL c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Load filament 1"), extr_adj_0);////MSG_LOAD_FILAMENT_1 c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Load filament 2"), extr_adj_1);////MSG_LOAD_FILAMENT_2 c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Load filament 3"), extr_adj_2);////MSG_LOAD_FILAMENT_3 c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Load filament 4"), extr_adj_3);////MSG_LOAD_FILAMENT_4 c=17 r=0 + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_ITEM_FUNCTION_P(_i("Load all"), load_all);////MSG_LOAD_ALL c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Load filament 1"), extr_adj_0);////MSG_LOAD_FILAMENT_1 c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Load filament 2"), extr_adj_1);////MSG_LOAD_FILAMENT_2 c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Load filament 3"), extr_adj_2);////MSG_LOAD_FILAMENT_3 c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Load filament 4"), extr_adj_3);////MSG_LOAD_FILAMENT_4 c=17 r=0 - if (mmu_enabled) - MENU_ITEM_FUNCTION_P(_i("Load filament 5"), extr_adj_4); + if (mmu_enabled) + MENU_ITEM_FUNCTION_P(_i("Load filament 5"), extr_adj_4); - MENU_END(); + MENU_END(); } static void mmu_load_to_nozzle_menu() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_FUNCTION_P(_i("Load filament 1"), mmu_load_to_nozzle_0); - MENU_ITEM_FUNCTION_P(_i("Load filament 2"), mmu_load_to_nozzle_1); - MENU_ITEM_FUNCTION_P(_i("Load filament 3"), mmu_load_to_nozzle_2); - MENU_ITEM_FUNCTION_P(_i("Load filament 4"), mmu_load_to_nozzle_3); - MENU_ITEM_FUNCTION_P(_i("Load filament 5"), mmu_load_to_nozzle_4); - MENU_END(); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_ITEM_FUNCTION_P(_i("Load filament 1"), mmu_load_to_nozzle_0); + MENU_ITEM_FUNCTION_P(_i("Load filament 2"), mmu_load_to_nozzle_1); + MENU_ITEM_FUNCTION_P(_i("Load filament 3"), mmu_load_to_nozzle_2); + MENU_ITEM_FUNCTION_P(_i("Load filament 4"), mmu_load_to_nozzle_3); + MENU_ITEM_FUNCTION_P(_i("Load filament 5"), mmu_load_to_nozzle_4); + MENU_END(); } static void mmu_fil_eject_menu() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_FUNCTION_P(_i("Eject filament 1"), mmu_eject_fil_0); - MENU_ITEM_FUNCTION_P(_i("Eject filament 2"), mmu_eject_fil_1); - MENU_ITEM_FUNCTION_P(_i("Eject filament 3"), mmu_eject_fil_2); - MENU_ITEM_FUNCTION_P(_i("Eject filament 4"), mmu_eject_fil_3); - MENU_ITEM_FUNCTION_P(_i("Eject filament 5"), mmu_eject_fil_4); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_ITEM_FUNCTION_P(_i("Eject filament 1"), mmu_eject_fil_0); + MENU_ITEM_FUNCTION_P(_i("Eject filament 2"), mmu_eject_fil_1); + MENU_ITEM_FUNCTION_P(_i("Eject filament 3"), mmu_eject_fil_2); + MENU_ITEM_FUNCTION_P(_i("Eject filament 4"), mmu_eject_fil_3); + MENU_ITEM_FUNCTION_P(_i("Eject filament 5"), mmu_eject_fil_4); - MENU_END(); + MENU_END(); } #ifdef SNMM static void fil_unload_menu() { - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_FUNCTION_P(_i("Unload all"), extr_unload_all);////MSG_UNLOAD_ALL c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Unload filament 1"), extr_unload_0);////MSG_UNLOAD_FILAMENT_1 c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Unload filament 2"), extr_unload_1);////MSG_UNLOAD_FILAMENT_2 c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Unload filament 3"), extr_unload_2);////MSG_UNLOAD_FILAMENT_3 c=17 r=0 - MENU_ITEM_FUNCTION_P(_i("Unload filament 4"), extr_unload_3);////MSG_UNLOAD_FILAMENT_4 c=17 r=0 + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_ITEM_FUNCTION_P(_i("Unload all"), extr_unload_all);////MSG_UNLOAD_ALL c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Unload filament 1"), extr_unload_0);////MSG_UNLOAD_FILAMENT_1 c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Unload filament 2"), extr_unload_1);////MSG_UNLOAD_FILAMENT_2 c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Unload filament 3"), extr_unload_2);////MSG_UNLOAD_FILAMENT_3 c=17 r=0 + MENU_ITEM_FUNCTION_P(_i("Unload filament 4"), extr_unload_3);////MSG_UNLOAD_FILAMENT_4 c=17 r=0 - if (mmu_enabled) - MENU_ITEM_FUNCTION_P(_i("Unload filament 5"), extr_unload_4);////MSG_UNLOAD_FILAMENT_5 c=17 r=0 + if (mmu_enabled) + MENU_ITEM_FUNCTION_P(_i("Unload filament 5"), extr_unload_4);////MSG_UNLOAD_FILAMENT_5 c=17 r=0 - MENU_END(); + MENU_END(); } -static void change_extr_menu(){ - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - MENU_ITEM_FUNCTION_P(_i("Extruder 1"), extr_change_0);////MSG_EXTRUDER_1 c=17 r=1 - MENU_ITEM_FUNCTION_P(_i("Extruder 2"), extr_change_1);////MSG_EXTRUDER_2 c=17 r=1 - MENU_ITEM_FUNCTION_P(_i("Extruder 3"), extr_change_2);////MSG_EXTRUDER_3 c=17 r=1 - MENU_ITEM_FUNCTION_P(_i("Extruder 4"), extr_change_3);////MSG_EXTRUDER_4 c=17 r=1 +static void change_extr_menu() { + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + MENU_ITEM_FUNCTION_P(_i("Extruder 1"), extr_change_0);////MSG_EXTRUDER_1 c=17 r=1 + MENU_ITEM_FUNCTION_P(_i("Extruder 2"), extr_change_1);////MSG_EXTRUDER_2 c=17 r=1 + MENU_ITEM_FUNCTION_P(_i("Extruder 3"), extr_change_2);////MSG_EXTRUDER_3 c=17 r=1 + MENU_ITEM_FUNCTION_P(_i("Extruder 4"), extr_change_3);////MSG_EXTRUDER_4 c=17 r=1 - MENU_END(); + MENU_END(); } #endif //SNMM //unload filament for single material printer (used in M702 gcode) void unload_filament() { - custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; - lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT)); - - // extr_unload2(); - - current_position[E_AXIS] -= 45; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5200 / 60, active_extruder); - st_synchronize(); - current_position[E_AXIS] -= 15; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder); - st_synchronize(); - current_position[E_AXIS] -= 20; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder); - st_synchronize(); - - lcd_display_message_fullscreen_P(_T(MSG_PULL_OUT_FILAMENT)); - - //disable extruder steppers so filament can be removed - disable_e0(); - disable_e1(); - disable_e2(); - delay(100); - - Sound_MakeSound(e_SOUND_TYPE_StandardPrompt); - uint8_t counterBeep = 0; - while (!lcd_clicked() && (counterBeep < 50)) { - delay_keep_alive(100); - counterBeep++; - } - st_synchronize(); - while (lcd_clicked()) delay_keep_alive(100); + custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; + lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT)); + + // extr_unload2(); + + current_position[E_AXIS] -= 45; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 5200 / 60, active_extruder); + st_synchronize(); + current_position[E_AXIS] -= 15; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder); + st_synchronize(); + current_position[E_AXIS] -= 20; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 1000 / 60, active_extruder); + st_synchronize(); + + lcd_display_message_fullscreen_P(_T(MSG_PULL_OUT_FILAMENT)); + + //disable extruder steppers so filament can be removed + disable_e0(); + disable_e1(); + disable_e2(); + delay(100); + + Sound_MakeSound(e_SOUND_TYPE_StandardPrompt); + uint8_t counterBeep = 0; + while (!lcd_clicked() && (counterBeep < 50)) { + delay_keep_alive(100); + counterBeep++; + } + st_synchronize(); + while (lcd_clicked()) delay_keep_alive(100); - lcd_update_enable(true); + lcd_update_enable(true); - lcd_setstatuspgm(_T(WELCOME_MSG)); - custom_message_type = CUSTOM_MSG_TYPE_STATUS; + lcd_setstatuspgm(_T(WELCOME_MSG)); + custom_message_type = CUSTOM_MSG_TYPE_STATUS; } static void lcd_farm_no() { - char step = 0; - int enc_dif = 0; - int _farmno = farm_no; - int _ret = 0; - lcd_clear(); + char step = 0; + int enc_dif = 0; + int _farmno = farm_no; + int _ret = 0; + lcd_clear(); - lcd_set_cursor(0, 0); - lcd_print("Farm no"); + lcd_set_cursor(0, 0); + lcd_print("Farm no"); - do - { + do + { - if (abs((enc_dif - lcd_encoder_diff)) > 2) { - if (enc_dif > lcd_encoder_diff) { - switch (step) { - case(0): if (_farmno >= 100) _farmno -= 100; break; - case(1): if (_farmno % 100 >= 10) _farmno -= 10; break; - case(2): if (_farmno % 10 >= 1) _farmno--; break; - default: break; - } - } + if (abs((enc_dif - lcd_encoder_diff)) > 2) { + if (enc_dif > lcd_encoder_diff) { + switch (step) { + case(0): + if (_farmno >= 100) _farmno -= 100; + break; + case(1): + if (_farmno % 100 >= 10) _farmno -= 10; + break; + case(2): + if (_farmno % 10 >= 1) _farmno--; + break; + default: + break; + } + } - if (enc_dif < lcd_encoder_diff) { - switch (step) { - case(0): if (_farmno < 900) _farmno += 100; break; - case(1): if (_farmno % 100 < 90) _farmno += 10; break; - case(2): if (_farmno % 10 <= 8)_farmno++; break; - default: break; - } - } - enc_dif = 0; - lcd_encoder_diff = 0; - } + if (enc_dif < lcd_encoder_diff) { + switch (step) { + case(0): + if (_farmno < 900) _farmno += 100; + break; + case(1): + if (_farmno % 100 < 90) _farmno += 10; + break; + case(2): + if (_farmno % 10 <= 8)_farmno++; + break; + default: + break; + } + } + enc_dif = 0; + lcd_encoder_diff = 0; + } - lcd_set_cursor(0, 2); - if (_farmno < 100) lcd_print("0"); - if (_farmno < 10) lcd_print("0"); - lcd_print(_farmno); - lcd_print(" "); - lcd_set_cursor(0, 3); - lcd_print(" "); - - - lcd_set_cursor(step, 3); - lcd_print("^"); - delay(100); - - if (lcd_clicked()) - { - delay(200); - step++; - if(step == 3) { - _ret = 1; - farm_no = _farmno; - EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no); - prusa_statistics(20); - lcd_return_to_status(); - } - } + lcd_set_cursor(0, 2); + if (_farmno < 100) lcd_print("0"); + if (_farmno < 10) lcd_print("0"); + lcd_print(_farmno); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); - manage_heater(); - } while (_ret == 0); + + lcd_set_cursor(step, 3); + lcd_print("^"); + delay(100); + + if (lcd_clicked()) + { + delay(200); + step++; + if(step == 3) { + _ret = 1; + farm_no = _farmno; + EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no); + prusa_statistics(20); + lcd_return_to_status(); + } + } + + manage_heater(); + } while (_ret == 0); } unsigned char lcd_choose_color() { - //function returns index of currently chosen item - //following part can be modified from 2 to 255 items: - //----------------------------------------------------- - unsigned char items_no = 2; - const char *item[items_no]; - item[0] = "Orange"; - item[1] = "Black"; - //----------------------------------------------------- - unsigned char active_rows; - static int first = 0; - int enc_dif = 0; - unsigned char cursor_pos = 1; - enc_dif = lcd_encoder_diff; - lcd_clear(); - lcd_set_cursor(0, 1); - lcd_print(">"); - - active_rows = items_no < 3 ? items_no : 3; - - while (1) { - lcd_puts_at_P(0, 0, PSTR("Choose color:")); - for (int i = 0; i < active_rows; i++) { - lcd_set_cursor(1, i+1); - lcd_print(item[first + i]); - } + //function returns index of currently chosen item + //following part can be modified from 2 to 255 items: + //----------------------------------------------------- + unsigned char items_no = 2; + const char *item[items_no]; + item[0] = "Orange"; + item[1] = "Black"; + //----------------------------------------------------- + unsigned char active_rows; + static int first = 0; + int enc_dif = 0; + unsigned char cursor_pos = 1; + enc_dif = lcd_encoder_diff; + lcd_clear(); + lcd_set_cursor(0, 1); + lcd_print(">"); - manage_heater(); - manage_inactivity(true); - proc_commands(); - if (abs((enc_dif - lcd_encoder_diff)) > 12) { - - if (enc_dif > lcd_encoder_diff) { - cursor_pos--; - } + active_rows = items_no < 3 ? items_no : 3; - if (enc_dif < lcd_encoder_diff) { - cursor_pos++; - } - - if (cursor_pos > active_rows) { - cursor_pos = active_rows; - if (first < items_no - active_rows) { - first++; - lcd_clear(); - } - } + while (1) { + lcd_puts_at_P(0, 0, PSTR("Choose color:")); + for (int i = 0; i < active_rows; i++) { + lcd_set_cursor(1, i+1); + lcd_print(item[first + i]); + } - if (cursor_pos < 1) { - cursor_pos = 1; - if (first > 0) { - first--; - lcd_clear(); - } - } - lcd_set_cursor(0, 1); - lcd_print(" "); - lcd_set_cursor(0, 2); - lcd_print(" "); - lcd_set_cursor(0, 3); - lcd_print(" "); - lcd_set_cursor(0, cursor_pos); - lcd_print(">"); - enc_dif = lcd_encoder_diff; - delay(100); + manage_heater(); + manage_inactivity(true); + proc_commands(); + if (abs((enc_dif - lcd_encoder_diff)) > 12) { - } + if (enc_dif > lcd_encoder_diff) { + cursor_pos--; + } - if (lcd_clicked()) { - switch(cursor_pos + first - 1) { - case 0: return 1; break; - case 1: return 0; break; - default: return 99; break; - } - } + if (enc_dif < lcd_encoder_diff) { + cursor_pos++; + } - } + if (cursor_pos > active_rows) { + cursor_pos = active_rows; + if (first < items_no - active_rows) { + first++; + lcd_clear(); + } + } + + if (cursor_pos < 1) { + cursor_pos = 1; + if (first > 0) { + first--; + lcd_clear(); + } + } + lcd_set_cursor(0, 1); + lcd_print(" "); + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); + lcd_set_cursor(0, cursor_pos); + lcd_print(">"); + enc_dif = lcd_encoder_diff; + delay(100); + + } + + if (lcd_clicked()) { + switch(cursor_pos + first - 1) { + case 0: + return 1; + break; + case 1: + return 0; + break; + default: + return 99; + break; + } + } + + } } void lcd_confirm_print() { - uint8_t filament_type; - int enc_dif = 0; - int cursor_pos = 1; - int _ret = 0; - int _t = 0; + uint8_t filament_type; + int enc_dif = 0; + int cursor_pos = 1; + int _ret = 0; + int _t = 0; - enc_dif = lcd_encoder_diff; - lcd_clear(); + enc_dif = lcd_encoder_diff; + lcd_clear(); - lcd_set_cursor(0, 0); - lcd_print("Print ok ?"); + lcd_set_cursor(0, 0); + lcd_print("Print ok ?"); - do - { - if (abs(enc_dif - lcd_encoder_diff) > 12) { - if (enc_dif > lcd_encoder_diff) { - cursor_pos--; - } + do + { + if (abs(enc_dif - lcd_encoder_diff) > 12) { + if (enc_dif > lcd_encoder_diff) { + cursor_pos--; + } - if (enc_dif < lcd_encoder_diff) { - cursor_pos++; - } - enc_dif = lcd_encoder_diff; - } + if (enc_dif < lcd_encoder_diff) { + cursor_pos++; + } + enc_dif = lcd_encoder_diff; + } - if (cursor_pos > 2) { cursor_pos = 2; } - if (cursor_pos < 1) { cursor_pos = 1; } - - lcd_set_cursor(0, 2); lcd_print(" "); - lcd_set_cursor(0, 3); lcd_print(" "); - lcd_set_cursor(2, 2); - lcd_puts_P(_T(MSG_YES)); - lcd_set_cursor(2, 3); - lcd_puts_P(_T(MSG_NO)); - lcd_set_cursor(0, 1 + cursor_pos); - lcd_print(">"); - delay(100); - - _t = _t + 1; - if (_t>100) - { - prusa_statistics(99); - _t = 0; - } - if (lcd_clicked()) - { - if (cursor_pos == 1) - { - _ret = 1; - filament_type = lcd_choose_color(); - prusa_statistics(4, filament_type); - no_response = true; //we need confirmation by recieving PRUSA thx - important_status = 4; - saved_filament_type = filament_type; - NcTime = millis(); - } - if (cursor_pos == 2) - { - _ret = 2; - filament_type = lcd_choose_color(); - prusa_statistics(5, filament_type); - no_response = true; //we need confirmation by recieving PRUSA thx - important_status = 5; - saved_filament_type = filament_type; - NcTime = millis(); - } - } + if (cursor_pos > 2) { + cursor_pos = 2; + } + if (cursor_pos < 1) { + cursor_pos = 1; + } - manage_heater(); - manage_inactivity(); - proc_commands(); + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); + lcd_set_cursor(2, 2); + lcd_puts_P(_T(MSG_YES)); + lcd_set_cursor(2, 3); + lcd_puts_P(_T(MSG_NO)); + lcd_set_cursor(0, 1 + cursor_pos); + lcd_print(">"); + delay(100); - } while (_ret == 0); + _t = _t + 1; + if (_t>100) + { + prusa_statistics(99); + _t = 0; + } + if (lcd_clicked()) + { + if (cursor_pos == 1) + { + _ret = 1; + filament_type = lcd_choose_color(); + prusa_statistics(4, filament_type); + no_response = true; //we need confirmation by recieving PRUSA thx + important_status = 4; + saved_filament_type = filament_type; + NcTime = millis(); + } + if (cursor_pos == 2) + { + _ret = 2; + filament_type = lcd_choose_color(); + prusa_statistics(5, filament_type); + no_response = true; //we need confirmation by recieving PRUSA thx + important_status = 5; + saved_filament_type = filament_type; + NcTime = millis(); + } + } + + manage_heater(); + manage_inactivity(); + proc_commands(); + + } while (_ret == 0); } @@ -5657,10 +5728,10 @@ void lcd_confirm_print() #ifdef LCD_TEST static void lcd_test_menu() { - W25X20CL_SPI_ENTER(); - w25x20cl_enable_wr(); - w25x20cl_chip_erase(); - w25x20cl_disable_wr(); + W25X20CL_SPI_ENTER(); + w25x20cl_enable_wr(); + w25x20cl_chip_erase(); + w25x20cl_disable_wr(); } #endif //LCD_TEST @@ -5681,192 +5752,192 @@ void lcd_resume_print() static void lcd_main_menu() { - MENU_BEGIN(); + MENU_BEGIN(); - // Majkl superawesome menu + // Majkl superawesome menu - MENU_ITEM_BACK_P(_T(MSG_WATCH)); + MENU_ITEM_BACK_P(_T(MSG_WATCH)); -#ifdef RESUME_DEBUG - if (!saved_printing) - MENU_ITEM_FUNCTION_P(PSTR("tst - Save"), lcd_menu_test_save); - else - MENU_ITEM_FUNCTION_P(PSTR("tst - Restore"), lcd_menu_test_restore); +#ifdef RESUME_DEBUG + if (!saved_printing) + MENU_ITEM_FUNCTION_P(PSTR("tst - Save"), lcd_menu_test_save); + else + MENU_ITEM_FUNCTION_P(PSTR("tst - Restore"), lcd_menu_test_restore); #endif //RESUME_DEBUG #ifdef TMC2130_DEBUG - MENU_ITEM_FUNCTION_P(PSTR("recover print"), recover_print); - MENU_ITEM_FUNCTION_P(PSTR("power panic"), uvlo_); + MENU_ITEM_FUNCTION_P(PSTR("recover print"), recover_print); + MENU_ITEM_FUNCTION_P(PSTR("power panic"), uvlo_); #endif //TMC2130_DEBUG - /* if (farm_mode && !IS_SD_PRINTING ) - { - - int tempScrool = 0; - if (lcd_draw_update == 0 && LCD_CLICKED == 0) - //delay(100); - return; // nothing to do (so don't thrash the SD card) - uint16_t fileCnt = card.getnrfilenames(); - - card.getWorkDirName(); - if (card.filename[0] == '/') + /* if (farm_mode && !IS_SD_PRINTING ) + { + + int tempScrool = 0; + if (lcd_draw_update == 0 && LCD_CLICKED == 0) + //delay(100); + return; // nothing to do (so don't thrash the SD card) + uint16_t fileCnt = card.getnrfilenames(); + + card.getWorkDirName(); + if (card.filename[0] == '/') + { + #if SDCARDDETECT == -1 + MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh); + #endif + } else { + MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir); + } + + for (uint16_t i = 0; i < fileCnt; i++) + { + if (menu_item == menu_line) + { + #ifndef SDCARD_RATHERRECENTFIRST + card.getfilename(i); + #else + card.getfilename(fileCnt - 1 - i); + #endif + if (card.filenameIsDir) + { + MENU_ITEM_SDDIR(_T(MSG_CARD_MENU), card.filename, card.longFilename); + } else { + + MENU_ITEM_SDFILE(_T(MSG_CARD_MENU), card.filename, card.longFilename); + + + + + } + } else { + MENU_ITEM_DUMMY(); + } + } + + MENU_ITEM_BACK_P(PSTR("- - - - - - - - -")); + + + }*/ + + if ( ( IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag) + { + MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z);//8 + } + + + if ( moves_planned() || IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) + { + MENU_ITEM_SUBMENU_P(_i("Tune"), lcd_tune_menu);////MSG_TUNE c=0 r=0 + } else + { + MENU_ITEM_SUBMENU_P(_i("Preheat"), lcd_preheat_menu);////MSG_PREHEAT c=0 r=0 + } + +#ifdef SDSUPPORT + if (card.cardOK || lcd_commands_type == LCD_COMMAND_V2_CAL) + { + if (card.isFileOpen()) { -#if SDCARDDETECT == -1 - MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh); -#endif - } else { - MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir); + if (mesh_bed_leveling_flag == false && homing_flag == false) { + if (card.sdprinting) + { + MENU_ITEM_FUNCTION_P(_i("Pause print"), lcd_pause_print);////MSG_PAUSE_PRINT c=0 r=0 + } + else + { + MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT c=0 r=0 + } + MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop); + } } - - for (uint16_t i = 0; i < fileCnt; i++) + else if (lcd_commands_type == LCD_COMMAND_V2_CAL && mesh_bed_leveling_flag == false && homing_flag == false) { + //MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop); + } + else { - if (menu_item == menu_line) + if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL)) { -#ifndef SDCARD_RATHERRECENTFIRST - card.getfilename(i); -#else - card.getfilename(fileCnt - 1 - i); -#endif - if (card.filenameIsDir) - { - MENU_ITEM_SDDIR(_T(MSG_CARD_MENU), card.filename, card.longFilename); - } else { - - MENU_ITEM_SDFILE(_T(MSG_CARD_MENU), card.filename, card.longFilename); - - - - - } - } else { - MENU_ITEM_DUMMY(); + //if (farm_mode) MENU_ITEM_SUBMENU_P(MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu); + /*else*/ MENU_ITEM_SUBMENU_P(_T(MSG_CARD_MENU), lcd_sdcard_menu); } +#if SDCARDDETECT < 1 + MENU_ITEM_GCODE_P(_i("Change SD card"), PSTR("M21")); // SD-card changed by user////MSG_CNG_SDCARD c=0 r=0 +#endif } - - MENU_ITEM_BACK_P(PSTR("- - - - - - - - -")); - - - }*/ - - if ( ( IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag) - { - MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z);//8 - } - - - if ( moves_planned() || IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) - { - MENU_ITEM_SUBMENU_P(_i("Tune"), lcd_tune_menu);////MSG_TUNE c=0 r=0 - } else - { - MENU_ITEM_SUBMENU_P(_i("Preheat"), lcd_preheat_menu);////MSG_PREHEAT c=0 r=0 - } -#ifdef SDSUPPORT - if (card.cardOK || lcd_commands_type == LCD_COMMAND_V2_CAL) - { - if (card.isFileOpen()) - { - if (mesh_bed_leveling_flag == false && homing_flag == false) { - if (card.sdprinting) - { - MENU_ITEM_FUNCTION_P(_i("Pause print"), lcd_pause_print);////MSG_PAUSE_PRINT c=0 r=0 - } - else - { - MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT c=0 r=0 - } - MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop); - } - } - else if (lcd_commands_type == LCD_COMMAND_V2_CAL && mesh_bed_leveling_flag == false && homing_flag == false) { - //MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop); - } - else - { - if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL)) - { - //if (farm_mode) MENU_ITEM_SUBMENU_P(MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu); - /*else*/ MENU_ITEM_SUBMENU_P(_T(MSG_CARD_MENU), lcd_sdcard_menu); - } + } else + { + MENU_ITEM_SUBMENU_P(_i("No SD card"), lcd_sdcard_menu);////MSG_NO_CARD c=0 r=0 #if SDCARDDETECT < 1 - MENU_ITEM_GCODE_P(_i("Change SD card"), PSTR("M21")); // SD-card changed by user////MSG_CNG_SDCARD c=0 r=0 + MENU_ITEM_GCODE_P(_i("Init. SD card"), PSTR("M21")); // Manually initialize the SD-card via user interface////MSG_INIT_SDCARD c=0 r=0 #endif } - - } else - { - MENU_ITEM_SUBMENU_P(_i("No SD card"), lcd_sdcard_menu);////MSG_NO_CARD c=0 r=0 -#if SDCARDDETECT < 1 - MENU_ITEM_GCODE_P(_i("Init. SD card"), PSTR("M21")); // Manually initialize the SD-card via user interface////MSG_INIT_SDCARD c=0 r=0 -#endif - } #endif - if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) - { - if (farm_mode) - { - MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no); - } - } - else - { - if (mmu_enabled) - { - MENU_ITEM_SUBMENU_P(_T(MSG_LOAD_FILAMENT), fil_load_menu); - MENU_ITEM_SUBMENU_P(_i("Load to nozzle"), mmu_load_to_nozzle_menu); - MENU_ITEM_SUBMENU_P(_i("Eject filament"), mmu_fil_eject_menu); - MENU_ITEM_GCODE_P(_T(MSG_UNLOAD_FILAMENT), PSTR("M702 C")); - } - else - { + if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) + { + if (farm_mode) + { + MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no); + } + } + else + { + if (mmu_enabled) + { + MENU_ITEM_SUBMENU_P(_T(MSG_LOAD_FILAMENT), fil_load_menu); + MENU_ITEM_SUBMENU_P(_i("Load to nozzle"), mmu_load_to_nozzle_menu); + MENU_ITEM_SUBMENU_P(_i("Eject filament"), mmu_fil_eject_menu); + MENU_ITEM_GCODE_P(_T(MSG_UNLOAD_FILAMENT), PSTR("M702 C")); + } + else + { #ifdef SNMM - MENU_ITEM_SUBMENU_P(_T(MSG_UNLOAD_FILAMENT), fil_unload_menu); - MENU_ITEM_SUBMENU_P(_i("Change extruder"), change_extr_menu);////MSG_CHANGE_EXTR c=20 r=1 + MENU_ITEM_SUBMENU_P(_T(MSG_UNLOAD_FILAMENT), fil_unload_menu); + MENU_ITEM_SUBMENU_P(_i("Change extruder"), change_extr_menu);////MSG_CHANGE_EXTR c=20 r=1 #endif #ifdef FILAMENT_SENSOR - if ((fsensor_autoload_enabled == true) && (fsensor_enabled == true) && (mmu_enabled == false)) - MENU_ITEM_SUBMENU_P(_i("AutoLoad filament"), lcd_menu_AutoLoadFilament);////MSG_AUTOLOAD_FILAMENT c=17 r=0 - else + if ((fsensor_autoload_enabled == true) && (fsensor_enabled == true) && (mmu_enabled == false)) + MENU_ITEM_SUBMENU_P(_i("AutoLoad filament"), lcd_menu_AutoLoadFilament);////MSG_AUTOLOAD_FILAMENT c=17 r=0 + else #endif //FILAMENT_SENSOR - MENU_ITEM_FUNCTION_P(_T(MSG_LOAD_FILAMENT), lcd_LoadFilament); - MENU_ITEM_SUBMENU_P(_T(MSG_UNLOAD_FILAMENT), lcd_unLoadFilament); - } - MENU_ITEM_SUBMENU_P(_T(MSG_SETTINGS), lcd_settings_menu); - if(!isPrintPaused) MENU_ITEM_SUBMENU_P(_T(MSG_MENU_CALIBRATION), lcd_calibration_menu); + MENU_ITEM_FUNCTION_P(_T(MSG_LOAD_FILAMENT), lcd_LoadFilament); + MENU_ITEM_SUBMENU_P(_T(MSG_UNLOAD_FILAMENT), lcd_unLoadFilament); + } + MENU_ITEM_SUBMENU_P(_T(MSG_SETTINGS), lcd_settings_menu); + if(!isPrintPaused) MENU_ITEM_SUBMENU_P(_T(MSG_MENU_CALIBRATION), lcd_calibration_menu); - } + } + + if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL)) + { + MENU_ITEM_SUBMENU_P(_i("Statistics "), lcd_menu_statistics);////MSG_STATISTICS c=0 r=0 + } - if (!is_usb_printing && (lcd_commands_type != LCD_COMMAND_V2_CAL)) - { - MENU_ITEM_SUBMENU_P(_i("Statistics "), lcd_menu_statistics);////MSG_STATISTICS c=0 r=0 - } - #if defined(TMC2130) || defined(FILAMENT_SENSOR) - MENU_ITEM_SUBMENU_P(PSTR("Fail stats"), lcd_menu_fails_stats); + MENU_ITEM_SUBMENU_P(PSTR("Fail stats"), lcd_menu_fails_stats); #endif - MENU_ITEM_SUBMENU_P(_i("Support"), lcd_support_menu);////MSG_SUPPORT c=0 r=0 + MENU_ITEM_SUBMENU_P(_i("Support"), lcd_support_menu);////MSG_SUPPORT c=0 r=0 #ifdef LCD_TEST MENU_ITEM_SUBMENU_P(_i("W25x20CL init"), lcd_test_menu);////MSG_SUPPORT c=0 r=0 #endif //LCD_TEST - MENU_END(); + MENU_END(); } void stack_error() { - SET_OUTPUT(BEEPER); -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) - WRITE(BEEPER, HIGH); - delay(1000); - WRITE(BEEPER, LOW); - lcd_display_message_fullscreen_P(_i("Error - static memory has been overwritten"));////MSG_STACK_ERROR c=20 r=4 - //err_triggered = 1; - while (1) delay_keep_alive(1000); + SET_OUTPUT(BEEPER); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)||(eSoundMode==e_SOUND_MODE_SILENT)) + WRITE(BEEPER, HIGH); + delay(1000); + WRITE(BEEPER, LOW); + lcd_display_message_fullscreen_P(_i("Error - static memory has been overwritten"));////MSG_STACK_ERROR c=20 r=4 + //err_triggered = 1; + while (1) delay_keep_alive(1000); } #ifdef DEBUG_STEPPER_TIMER_MISSED @@ -5875,610 +5946,631 @@ uint16_t stepper_timer_overflow_max = 0; uint16_t stepper_timer_overflow_last = 0; uint16_t stepper_timer_overflow_cnt = 0; void stepper_timer_overflow() { - char msg[28]; - sprintf_P(msg, PSTR("#%d %d max %d"), ++ stepper_timer_overflow_cnt, stepper_timer_overflow_last >> 1, stepper_timer_overflow_max >> 1); - lcd_setstatus(msg); - stepper_timer_overflow_state = false; - if (stepper_timer_overflow_last > stepper_timer_overflow_max) - stepper_timer_overflow_max = stepper_timer_overflow_last; - SERIAL_ECHOPGM("Stepper timer overflow: "); - MYSERIAL.print(msg); - SERIAL_ECHOLNPGM(""); - - WRITE(BEEPER, LOW); + char msg[28]; + sprintf_P(msg, PSTR("#%d %d max %d"), ++ stepper_timer_overflow_cnt, stepper_timer_overflow_last >> 1, stepper_timer_overflow_max >> 1); + lcd_setstatus(msg); + stepper_timer_overflow_state = false; + if (stepper_timer_overflow_last > stepper_timer_overflow_max) + stepper_timer_overflow_max = stepper_timer_overflow_last; + SERIAL_ECHOPGM("Stepper timer overflow: "); + MYSERIAL.print(msg); + SERIAL_ECHOLNPGM(""); + + WRITE(BEEPER, LOW); } #endif /* DEBUG_STEPPER_TIMER_MISSED */ static void lcd_colorprint_change() { - - enquecommand_P(PSTR("M600")); - - custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; //just print status message - lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS)); - lcd_return_to_status(); - lcd_draw_update = 3; + + enquecommand_P(PSTR("M600")); + + custom_message_type = CUSTOM_MSG_TYPE_F_LOAD; //just print status message + lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS)); + lcd_return_to_status(); + lcd_draw_update = 3; } static void lcd_tune_menu() { - typedef struct - { - menu_data_edit_t reserved; //!< reserved for number editing functions - int8_t status; //!< To recognize, whether the menu has been just initialized. - //! Backup of extrudemultiply, to recognize, that the value has been changed and - //! it needs to be applied. - int16_t extrudemultiply; - } _menu_data_t; - static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data"); - _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); - if (_md->status == 0) - { - // Menu was entered. Mark the menu as entered and save the current extrudemultiply value. - _md->status = 1; - _md->extrudemultiply = extrudemultiply; - } - else if (_md->extrudemultiply != extrudemultiply) - { - // extrudemultiply has been changed from the child menu. Apply the new value. - _md->extrudemultiply = extrudemultiply; - calculate_extruder_multipliers(); - } + typedef struct + { + menu_data_edit_t reserved; //!< reserved for number editing functions + int8_t status; //!< To recognize, whether the menu has been just initialized. + //! Backup of extrudemultiply, to recognize, that the value has been changed and + //! it needs to be applied. + int16_t extrudemultiply; + } _menu_data_t; + static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data"); + _menu_data_t* _md = (_menu_data_t*)&(menu_data[0]); + if (_md->status == 0) + { + // Menu was entered. Mark the menu as entered and save the current extrudemultiply value. + _md->status = 1; + _md->extrudemultiply = extrudemultiply; + } + else if (_md->extrudemultiply != extrudemultiply) + { + // extrudemultiply has been changed from the child menu. Apply the new value. + _md->extrudemultiply = extrudemultiply; + calculate_extruder_multipliers(); + } - EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu)); + EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu)); - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); //1 - MENU_ITEM_EDIT_int3_P(_i("Speed"), &feedmultiply, 10, 999);//2////MSG_SPEED c=0 r=0 + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); //1 + MENU_ITEM_EDIT_int3_P(_i("Speed"), &feedmultiply, 10, 999);//2////MSG_SPEED c=0 r=0 - MENU_ITEM_EDIT_int3_P(_T(MSG_NOZZLE), &target_temperature[0], 0, HEATER_0_MAXTEMP - 10);//3 - MENU_ITEM_EDIT_int3_P(_T(MSG_BED), &target_temperature_bed, 0, BED_MAXTEMP - 10);//4 + MENU_ITEM_EDIT_int3_P(_T(MSG_NOZZLE), &target_temperature[0], 0, HEATER_0_MAXTEMP - 10);//3 + MENU_ITEM_EDIT_int3_P(_T(MSG_BED), &target_temperature_bed, 0, BED_MAXTEMP - 10);//4 - MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255);//5 - MENU_ITEM_EDIT_int3_P(_i("Flow"), &extrudemultiply, 10, 999);//6////MSG_FLOW c=0 r=0 + MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255);//5 + MENU_ITEM_EDIT_int3_P(_i("Flow"), &extrudemultiply, 10, 999);//6////MSG_FLOW c=0 r=0 #ifdef FILAMENTCHANGEENABLE - MENU_ITEM_FUNCTION_P(_T(MSG_FILAMENTCHANGE), lcd_colorprint_change);//7 + MENU_ITEM_FUNCTION_P(_T(MSG_FILAMENTCHANGE), lcd_colorprint_change);//7 #endif #ifdef FILAMENT_SENSOR - if (FSensorStateMenu == 0) { - MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_OFF), lcd_fsensor_state_set); - } - else { - MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_ON), lcd_fsensor_state_set); - } + if (FSensorStateMenu == 0) { + MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_OFF), lcd_fsensor_state_set); + } + else { + MENU_ITEM_FUNCTION_P(_T(MSG_FSENSOR_ON), lcd_fsensor_state_set); + } #endif //FILAMENT_SENSOR - SETTINGS_AUTO_DEPLETE; + SETTINGS_AUTO_DEPLETE; #ifdef TMC2130 - if(!farm_mode) - { - if (SilentModeMenu == SILENT_MODE_NORMAL) MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_OFF), lcd_silent_mode_set); - else MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_ON), lcd_silent_mode_set); - - if (SilentModeMenu == SILENT_MODE_NORMAL) - { - if (CrashDetectMenu == 0) MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_OFF), lcd_crash_mode_set); - else MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_ON), lcd_crash_mode_set); - } - else MENU_ITEM_SUBMENU_P(_T(MSG_CRASHDETECT_NA), lcd_crash_mode_info); - } + if(!farm_mode) + { + if (SilentModeMenu == SILENT_MODE_NORMAL) MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_OFF), lcd_silent_mode_set); + else MENU_ITEM_FUNCTION_P(_T(MSG_STEALTH_MODE_ON), lcd_silent_mode_set); + + if (SilentModeMenu == SILENT_MODE_NORMAL) + { + if (CrashDetectMenu == 0) MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_OFF), lcd_crash_mode_set); + else MENU_ITEM_FUNCTION_P(_T(MSG_CRASHDETECT_ON), lcd_crash_mode_set); + } + else MENU_ITEM_SUBMENU_P(_T(MSG_CRASHDETECT_NA), lcd_crash_mode_info); + } #else //TMC2130 - if (!farm_mode) { //dont show in menu if we are in farm mode - switch (SilentModeMenu) { - case SILENT_MODE_POWER: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); break; - case SILENT_MODE_SILENT: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_ON), lcd_silent_mode_set); break; - case SILENT_MODE_AUTO: MENU_ITEM_FUNCTION_P(_T(MSG_AUTO_MODE_ON), lcd_silent_mode_set); break; - default: MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); break; // (probably) not needed - } - } + if (!farm_mode) { //dont show in menu if we are in farm mode + switch (SilentModeMenu) { + case SILENT_MODE_POWER: + MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); + break; + case SILENT_MODE_SILENT: + MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_ON), lcd_silent_mode_set); + break; + case SILENT_MODE_AUTO: + MENU_ITEM_FUNCTION_P(_T(MSG_AUTO_MODE_ON), lcd_silent_mode_set); + break; + default: + MENU_ITEM_FUNCTION_P(_T(MSG_SILENT_MODE_OFF), lcd_silent_mode_set); + break; // (probably) not needed + } + } #endif //TMC2130 - switch(eSoundMode) - { - case e_SOUND_MODE_LOUD: - MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set); - break; - case e_SOUND_MODE_ONCE: - MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_ONCE),lcd_sound_state_set); - break; - case e_SOUND_MODE_SILENT: - MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_SILENT),lcd_sound_state_set); - break; - case e_SOUND_MODE_MUTE: - MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_MUTE),lcd_sound_state_set); - break; - default: - MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set); - } - - MENU_END(); + switch(eSoundMode) + { + case e_SOUND_MODE_LOUD: + MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set); + break; + case e_SOUND_MODE_ONCE: + MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_ONCE),lcd_sound_state_set); + break; + case e_SOUND_MODE_SILENT: + MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_SILENT),lcd_sound_state_set); + break; + case e_SOUND_MODE_MUTE: + MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_MUTE),lcd_sound_state_set); + break; + default: + MENU_ITEM_FUNCTION_P(_i(MSG_SOUND_MODE_LOUD),lcd_sound_state_set); + } + + MENU_END(); } static void lcd_control_temperature_menu() { #ifdef PIDTEMP - // set up temp variables - undo the default scaling + // set up temp variables - undo the default scaling // raw_Ki = unscalePID_i(Ki); // raw_Kd = unscalePID_d(Kd); #endif - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); #if TEMP_SENSOR_0 != 0 - MENU_ITEM_EDIT_int3_P(_T(MSG_NOZZLE), &target_temperature[0], 0, HEATER_0_MAXTEMP - 10); + MENU_ITEM_EDIT_int3_P(_T(MSG_NOZZLE), &target_temperature[0], 0, HEATER_0_MAXTEMP - 10); #endif #if TEMP_SENSOR_1 != 0 - MENU_ITEM_EDIT_int3_P(_i("Nozzle2"), &target_temperature[1], 0, HEATER_1_MAXTEMP - 10);////MSG_NOZZLE1 c=0 r=0 + MENU_ITEM_EDIT_int3_P(_i("Nozzle2"), &target_temperature[1], 0, HEATER_1_MAXTEMP - 10);////MSG_NOZZLE1 c=0 r=0 #endif #if TEMP_SENSOR_2 != 0 - MENU_ITEM_EDIT_int3_P(_i("Nozzle3"), &target_temperature[2], 0, HEATER_2_MAXTEMP - 10);////MSG_NOZZLE2 c=0 r=0 + MENU_ITEM_EDIT_int3_P(_i("Nozzle3"), &target_temperature[2], 0, HEATER_2_MAXTEMP - 10);////MSG_NOZZLE2 c=0 r=0 #endif #if TEMP_SENSOR_BED != 0 - MENU_ITEM_EDIT_int3_P(_T(MSG_BED), &target_temperature_bed, 0, BED_MAXTEMP - 3); + MENU_ITEM_EDIT_int3_P(_T(MSG_BED), &target_temperature_bed, 0, BED_MAXTEMP - 3); #endif - MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255); + MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255); #if defined AUTOTEMP && (TEMP_SENSOR_0 != 0) //MENU_ITEM_EDIT removed, following code must be redesigned if AUTOTEMP enabled - MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &autotemp_enabled); - MENU_ITEM_EDIT(float3, _i(" \002 Min"), &autotemp_min, 0, HEATER_0_MAXTEMP - 10);////MSG_MIN c=0 r=0 - MENU_ITEM_EDIT(float3, _i(" \002 Max"), &autotemp_max, 0, HEATER_0_MAXTEMP - 10);////MSG_MAX c=0 r=0 - MENU_ITEM_EDIT(float32, _i(" \002 Fact"), &autotemp_factor, 0.0, 1.0);////MSG_FACTOR c=0 r=0 + MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &autotemp_enabled); + MENU_ITEM_EDIT(float3, _i(" \002 Min"), &autotemp_min, 0, HEATER_0_MAXTEMP - 10);////MSG_MIN c=0 r=0 + MENU_ITEM_EDIT(float3, _i(" \002 Max"), &autotemp_max, 0, HEATER_0_MAXTEMP - 10);////MSG_MAX c=0 r=0 + MENU_ITEM_EDIT(float32, _i(" \002 Fact"), &autotemp_factor, 0.0, 1.0);////MSG_FACTOR c=0 r=0 #endif - MENU_END(); + MENU_END(); } #if SDCARDDETECT == -1 static void lcd_sd_refresh() { - card.initsd(); - menu_top = 0; + card.initsd(); + menu_top = 0; } #endif static void lcd_sd_updir() { - card.updir(); - menu_top = 0; + card.updir(); + menu_top = 0; } void lcd_print_stop() { - cancel_heatup = true; + cancel_heatup = true; #ifdef MESH_BED_LEVELING - mbl.active = false; + mbl.active = false; #endif - // Stop the stoppers, update the position from the stoppers. - if (mesh_bed_leveling_flag == false && homing_flag == false) - { - planner_abort_hard(); - // Because the planner_abort_hard() initialized current_position[Z] from the stepper, - // Z baystep is no more applied. Reset it. - babystep_reset(); - } - // Clean the input command queue. - cmdqueue_reset(); - lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); - card.sdprinting = false; - card.closefile(); - stoptime = millis(); - unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s - pause_time = 0; - save_statistics(total_filament_used, t); - lcd_return_to_status(); - lcd_ignore_click(true); - lcd_commands_step = 0; - lcd_commands_type = LCD_COMMAND_STOP_PRINT; - // Turn off the print fan - SET_OUTPUT(FAN_PIN); - WRITE(FAN_PIN, 0); - fanSpeed = 0; + // Stop the stoppers, update the position from the stoppers. + if (mesh_bed_leveling_flag == false && homing_flag == false) + { + planner_abort_hard(); + // Because the planner_abort_hard() initialized current_position[Z] from the stepper, + // Z baystep is no more applied. Reset it. + babystep_reset(); + } + // Clean the input command queue. + cmdqueue_reset(); + lcd_setstatuspgm(_T(MSG_PRINT_ABORTED)); + card.sdprinting = false; + card.closefile(); + stoptime = millis(); + unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s + pause_time = 0; + save_statistics(total_filament_used, t); + lcd_return_to_status(); + lcd_ignore_click(true); + lcd_commands_step = 0; + lcd_commands_type = LCD_COMMAND_STOP_PRINT; + // Turn off the print fan + SET_OUTPUT(FAN_PIN); + WRITE(FAN_PIN, 0); + fanSpeed = 0; } void lcd_sdcard_stop() { - - lcd_set_cursor(0, 0); - lcd_puts_P(_T(MSG_STOP_PRINT)); - lcd_set_cursor(2, 2); - lcd_puts_P(_T(MSG_NO)); - lcd_set_cursor(2, 3); - lcd_puts_P(_T(MSG_YES)); - lcd_set_cursor(0, 2); lcd_print(" "); - lcd_set_cursor(0, 3); lcd_print(" "); - - if ((int32_t)lcd_encoder > 2) { lcd_encoder = 2; } - if ((int32_t)lcd_encoder < 1) { lcd_encoder = 1; } - - lcd_set_cursor(0, 1 + lcd_encoder); - lcd_print(">"); - - if (lcd_clicked()) - { - if ((int32_t)lcd_encoder == 1) - { - lcd_return_to_status(); - } - if ((int32_t)lcd_encoder == 2) - { - lcd_print_stop(); - } - } + + lcd_set_cursor(0, 0); + lcd_puts_P(_T(MSG_STOP_PRINT)); + lcd_set_cursor(2, 2); + lcd_puts_P(_T(MSG_NO)); + lcd_set_cursor(2, 3); + lcd_puts_P(_T(MSG_YES)); + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(0, 3); + lcd_print(" "); + + if ((int32_t)lcd_encoder > 2) { + lcd_encoder = 2; + } + if ((int32_t)lcd_encoder < 1) { + lcd_encoder = 1; + } + + lcd_set_cursor(0, 1 + lcd_encoder); + lcd_print(">"); + + if (lcd_clicked()) + { + if ((int32_t)lcd_encoder == 1) + { + lcd_return_to_status(); + } + if ((int32_t)lcd_encoder == 2) + { + lcd_print_stop(); + } + } } void lcd_sdcard_menu() { - uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT); + uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT); - if (presort_flag == true) { - presort_flag = false; - card.presort(); - } - if (lcd_draw_update == 0 && LCD_CLICKED == 0) - //delay(100); - return; // nothing to do (so don't thrash the SD card) - uint16_t fileCnt = card.getnrfilenames(); + if (presort_flag == true) { + presort_flag = false; + card.presort(); + } + if (lcd_draw_update == 0 && LCD_CLICKED == 0) + //delay(100); + return; // nothing to do (so don't thrash the SD card) + uint16_t fileCnt = card.getnrfilenames(); - MENU_BEGIN(); - MENU_ITEM_BACK_P(_T(MSG_MAIN)); - card.getWorkDirName(); - if (card.filename[0] == '/') - { + MENU_BEGIN(); + MENU_ITEM_BACK_P(_T(MSG_MAIN)); + card.getWorkDirName(); + if (card.filename[0] == '/') + { #if SDCARDDETECT == -1 - MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh); + MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh); #endif - } else { - MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir); - } + } else { + MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir); + } - for (uint16_t i = 0; i < fileCnt; i++) - { - if (menu_item == menu_line) + for (uint16_t i = 0; i < fileCnt; i++) { - const uint16_t nr = ((sdSort == SD_SORT_NONE) || farm_mode || (sdSort == SD_SORT_TIME)) ? (fileCnt - 1 - i) : i; - /*#ifdef SDCARD_RATHERRECENTFIRST - #ifndef SDCARD_SORT_ALPHA - fileCnt - 1 - - #endif - #endif - i;*/ - #ifdef SDCARD_SORT_ALPHA - if (sdSort == SD_SORT_NONE) card.getfilename(nr); - else card.getfilename_sorted(nr); - #else - card.getfilename(nr); - #endif - - if (card.filenameIsDir) - MENU_ITEM_SDDIR(card.filename, card.longFilename); - else - MENU_ITEM_SDFILE(_T(MSG_CARD_MENU), card.filename, card.longFilename); - } else { - MENU_ITEM_DUMMY(); + if (menu_item == menu_line) + { + const uint16_t nr = ((sdSort == SD_SORT_NONE) || farm_mode || (sdSort == SD_SORT_TIME)) ? (fileCnt - 1 - i) : i; + /*#ifdef SDCARD_RATHERRECENTFIRST + #ifndef SDCARD_SORT_ALPHA + fileCnt - 1 - + #endif + #endif + i;*/ +#ifdef SDCARD_SORT_ALPHA + if (sdSort == SD_SORT_NONE) card.getfilename(nr); + else card.getfilename_sorted(nr); +#else + card.getfilename(nr); +#endif + + if (card.filenameIsDir) + MENU_ITEM_SDDIR(card.filename, card.longFilename); + else + MENU_ITEM_SDFILE(_T(MSG_CARD_MENU), card.filename, card.longFilename); + } else { + MENU_ITEM_DUMMY(); + } } - } - MENU_END(); + MENU_END(); } static void lcd_selftest_v() { - (void)lcd_selftest(); + (void)lcd_selftest(); } bool lcd_selftest() { - int _progress = 0; - bool _result = true; - lcd_wait_for_cool_down(); - lcd_clear(); - lcd_set_cursor(0, 0); lcd_puts_P(_i("Self test start "));////MSG_SELFTEST_START c=20 r=0 - #ifdef TMC2130 - FORCE_HIGH_POWER_START; - #endif // TMC2130 - delay(2000); - KEEPALIVE_STATE(IN_HANDLER); - - _progress = lcd_selftest_screen(-1, _progress, 3, true, 2000); -#if (defined(FANCHECK) && defined(TACH_0)) - _result = lcd_selftest_fan_dialog(0); + int _progress = 0; + bool _result = true; + lcd_wait_for_cool_down(); + lcd_clear(); + lcd_set_cursor(0, 0); + lcd_puts_P(_i("Self test start "));////MSG_SELFTEST_START c=20 r=0 +#ifdef TMC2130 + FORCE_HIGH_POWER_START; +#endif // TMC2130 + delay(2000); + KEEPALIVE_STATE(IN_HANDLER); + + _progress = lcd_selftest_screen(-1, _progress, 3, true, 2000); +#if (defined(FANCHECK) && defined(TACH_0)) + _result = lcd_selftest_fan_dialog(0); #else //defined(TACH_0) - _result = lcd_selftest_manual_fan_check(0, false); - if (!_result) - { - const char *_err; - lcd_selftest_error(7, _err, _err); //extruder fan not spinning - } + _result = lcd_selftest_manual_fan_check(0, false); + if (!_result) + { + const char *_err; + lcd_selftest_error(7, _err, _err); //extruder fan not spinning + } #endif //defined(TACH_0) - - if (_result) - { - _progress = lcd_selftest_screen(0, _progress, 3, true, 2000); -#if (defined(FANCHECK) && defined(TACH_1)) - _result = lcd_selftest_fan_dialog(1); + + if (_result) + { + _progress = lcd_selftest_screen(0, _progress, 3, true, 2000); +#if (defined(FANCHECK) && defined(TACH_1)) + _result = lcd_selftest_fan_dialog(1); #else //defined(TACH_1) - _result = lcd_selftest_manual_fan_check(1, false); - if (!_result) - { - const char *_err; - lcd_selftest_error(6, _err, _err); //print fan not spinning - } + _result = lcd_selftest_manual_fan_check(1, false); + if (!_result) + { + const char *_err; + lcd_selftest_error(6, _err, _err); //print fan not spinning + } #endif //defined(TACH_1) - } + } - if (_result) - { - _progress = lcd_selftest_screen(1, _progress, 3, true, 2000); + if (_result) + { + _progress = lcd_selftest_screen(1, _progress, 3, true, 2000); #ifndef TMC2130 - _result = lcd_selfcheck_endstops(); + _result = lcd_selfcheck_endstops(); #else - _result = true; + _result = true; #endif - } - - if (_result) - { - _progress = lcd_selftest_screen(3, _progress, 3, true, 1000); - _result = lcd_selfcheck_check_heater(false); - } + } + + if (_result) + { + _progress = lcd_selftest_screen(3, _progress, 3, true, 1000); + _result = lcd_selfcheck_check_heater(false); + } - if (_result) - { - //current_position[Z_AXIS] += 15; //move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed - _progress = lcd_selftest_screen(4, _progress, 3, true, 2000); + if (_result) + { + //current_position[Z_AXIS] += 15; //move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed + _progress = lcd_selftest_screen(4, _progress, 3, true, 2000); #ifdef TMC2130 - _result = lcd_selfcheck_axis_sg(X_AXIS); + _result = lcd_selfcheck_axis_sg(X_AXIS); #else - _result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS); + _result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS); #endif //TMC2130 - } + } - if (_result) - { - _progress = lcd_selftest_screen(4, _progress, 3, true, 0); + if (_result) + { + _progress = lcd_selftest_screen(4, _progress, 3, true, 0); #ifndef TMC2130 - _result = lcd_selfcheck_pulleys(X_AXIS); + _result = lcd_selfcheck_pulleys(X_AXIS); #endif - } + } - if (_result) - { - _progress = lcd_selftest_screen(5, _progress, 3, true, 1500); + if (_result) + { + _progress = lcd_selftest_screen(5, _progress, 3, true, 1500); #ifdef TMC2130 - _result = lcd_selfcheck_axis_sg(Y_AXIS); + _result = lcd_selfcheck_axis_sg(Y_AXIS); #else - _result = lcd_selfcheck_axis(Y_AXIS, Y_MAX_POS); + _result = lcd_selfcheck_axis(Y_AXIS, Y_MAX_POS); #endif // TMC2130 - } + } - if (_result) - { - _progress = lcd_selftest_screen(5, _progress, 3, true, 0); + if (_result) + { + _progress = lcd_selftest_screen(5, _progress, 3, true, 0); #ifndef TMC2130 - _result = lcd_selfcheck_pulleys(Y_AXIS); + _result = lcd_selfcheck_pulleys(Y_AXIS); #endif // TMC2130 - } + } - if (_result) - { + if (_result) + { #ifdef TMC2130 - tmc2130_home_exit(); - enable_endstops(false); - current_position[X_AXIS] = current_position[X_AXIS] + 14; - current_position[Y_AXIS] = current_position[Y_AXIS] + 12; + tmc2130_home_exit(); + enable_endstops(false); + current_position[X_AXIS] = current_position[X_AXIS] + 14; + current_position[Y_AXIS] = current_position[Y_AXIS] + 12; #endif - //homeaxis(X_AXIS); - //homeaxis(Y_AXIS); - current_position[Z_AXIS] = current_position[Z_AXIS] + 10; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); - _progress = lcd_selftest_screen(6, _progress, 3, true, 1500); - _result = lcd_selfcheck_axis(2, Z_MAX_POS); - if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) { - enquecommand_P(PSTR("G28 W")); - enquecommand_P(PSTR("G1 Z15 F1000")); - } - } + //homeaxis(X_AXIS); + //homeaxis(Y_AXIS); + current_position[Z_AXIS] = current_position[Z_AXIS] + 10; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); + _progress = lcd_selftest_screen(6, _progress, 3, true, 1500); + _result = lcd_selfcheck_axis(2, Z_MAX_POS); + if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) { + enquecommand_P(PSTR("G28 W")); + enquecommand_P(PSTR("G1 Z15 F1000")); + } + } #ifdef TMC2130 - if (_result) - { - current_position[Z_AXIS] = current_position[Z_AXIS] + 10; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); - _progress = lcd_selftest_screen(13, 0, 2, true, 0); - bool bres = tmc2130_home_calibrate(X_AXIS); - _progress = lcd_selftest_screen(13, 1, 2, true, 0); - bres &= tmc2130_home_calibrate(Y_AXIS); - _progress = lcd_selftest_screen(13, 2, 2, true, 0); - if (bres) - eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_ENABLED, 1); - _result = bres; - } + if (_result) + { + current_position[Z_AXIS] = current_position[Z_AXIS] + 10; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); + _progress = lcd_selftest_screen(13, 0, 2, true, 0); + bool bres = tmc2130_home_calibrate(X_AXIS); + _progress = lcd_selftest_screen(13, 1, 2, true, 0); + bres &= tmc2130_home_calibrate(Y_AXIS); + _progress = lcd_selftest_screen(13, 2, 2, true, 0); + if (bres) + eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_ENABLED, 1); + _result = bres; + } #endif //TMC2130 - if (_result) - { - _progress = lcd_selftest_screen(7, _progress, 3, true, 2000); //check bed - _result = lcd_selfcheck_check_heater(true); - } - if (_result) - { - _progress = lcd_selftest_screen(8, _progress, 3, true, 2000); //bed ok + if (_result) + { + _progress = lcd_selftest_screen(7, _progress, 3, true, 2000); //check bed + _result = lcd_selfcheck_check_heater(true); + } + if (_result) + { + _progress = lcd_selftest_screen(8, _progress, 3, true, 2000); //bed ok #ifdef FILAMENT_SENSOR - if (mmu_enabled == false) { - _progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor - _result = lcd_selftest_fsensor(); - } + if (mmu_enabled == false) { + _progress = lcd_selftest_screen(9, _progress, 3, true, 2000); //check filaments sensor + _result = lcd_selftest_fsensor(); + } #endif // FILAMENT_SENSOR - } - if (_result) - { + } + if (_result) + { #ifdef FILAMENT_SENSOR - if (mmu_enabled == false) - { - _progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK - } + if (mmu_enabled == false) + { + _progress = lcd_selftest_screen(10, _progress, 3, true, 2000); //fil sensor OK + } #endif // FILAMENT_SENSOR - _progress = lcd_selftest_screen(11, _progress, 3, true, 5000); //all correct - } - else - { - _progress = lcd_selftest_screen(12, _progress, 3, true, 5000); - } - lcd_reset_alert_level(); - enquecommand_P(PSTR("M84")); - lcd_update_enable(true); - - if (_result) - { - LCD_ALERTMESSAGERPGM(_i("Self test OK"));////MSG_SELFTEST_OK c=0 r=0 - } - else - { - LCD_ALERTMESSAGERPGM(_T(MSG_SELFTEST_FAILED)); - } - #ifdef TMC2130 - FORCE_HIGH_POWER_END; - #endif // TMC2130 - KEEPALIVE_STATE(NOT_BUSY); - return(_result); + _progress = lcd_selftest_screen(11, _progress, 3, true, 5000); //all correct + } + else + { + _progress = lcd_selftest_screen(12, _progress, 3, true, 5000); + } + lcd_reset_alert_level(); + enquecommand_P(PSTR("M84")); + lcd_update_enable(true); + + if (_result) + { + LCD_ALERTMESSAGERPGM(_i("Self test OK"));////MSG_SELFTEST_OK c=0 r=0 + } + else + { + LCD_ALERTMESSAGERPGM(_T(MSG_SELFTEST_FAILED)); + } +#ifdef TMC2130 + FORCE_HIGH_POWER_END; +#endif // TMC2130 + KEEPALIVE_STATE(NOT_BUSY); + return(_result); } #ifdef TMC2130 static void reset_crash_det(unsigned char axis) { - current_position[axis] += 10; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); - if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET)) tmc2130_sg_stop_on_crash = true; + current_position[axis] += 10; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); + if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET)) tmc2130_sg_stop_on_crash = true; } static bool lcd_selfcheck_axis_sg(unsigned char axis) { -// each axis length is measured twice - float axis_length, current_position_init, current_position_final; - float measured_axis_length[2]; - float margin = 60; - float max_error_mm = 5; - switch (axis) { - case 0: axis_length = X_MAX_POS; break; - case 1: axis_length = Y_MAX_POS + 8; break; - default: axis_length = 210; break; - } +// each axis length is measured twice + float axis_length, current_position_init, current_position_final; + float measured_axis_length[2]; + float margin = 60; + float max_error_mm = 5; + switch (axis) { + case 0: + axis_length = X_MAX_POS; + break; + case 1: + axis_length = Y_MAX_POS + 8; + break; + default: + axis_length = 210; + break; + } - tmc2130_sg_stop_on_crash = false; - tmc2130_home_exit(); - enable_endstops(true); + tmc2130_sg_stop_on_crash = false; + tmc2130_home_exit(); + enable_endstops(true); - if (axis == X_AXIS) { //there is collision between cables and PSU cover in X axis if Z coordinate is too low - - current_position[Z_AXIS] += 17; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - tmc2130_home_enter(Z_AXIS_MASK); - st_synchronize(); - tmc2130_home_exit(); - } + if (axis == X_AXIS) { //there is collision between cables and PSU cover in X axis if Z coordinate is too low + + current_position[Z_AXIS] += 17; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + tmc2130_home_enter(Z_AXIS_MASK); + st_synchronize(); + tmc2130_home_exit(); + } + +// first axis length measurement begin + + current_position[axis] -= (axis_length + margin); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); -// first axis length measurement begin - - current_position[axis] -= (axis_length + margin); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - - st_synchronize(); + st_synchronize(); - tmc2130_sg_meassure_start(axis); + tmc2130_sg_meassure_start(axis); - current_position_init = st_get_position_mm(axis); + current_position_init = st_get_position_mm(axis); - current_position[axis] += 2 * margin; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); + current_position[axis] += 2 * margin; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); - current_position[axis] += axis_length; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + current_position[axis] += axis_length; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); + st_synchronize(); - uint16_t sg1 = tmc2130_sg_meassure_stop(); - printf_P(PSTR("%c AXIS SG1=%d\n"), 'X'+axis, sg1); - eeprom_write_word(((uint16_t*)((axis == X_AXIS)?EEPROM_BELTSTATUS_X:EEPROM_BELTSTATUS_Y)), sg1); + uint16_t sg1 = tmc2130_sg_meassure_stop(); + printf_P(PSTR("%c AXIS SG1=%d\n"), 'X'+axis, sg1); + eeprom_write_word(((uint16_t*)((axis == X_AXIS)?EEPROM_BELTSTATUS_X:EEPROM_BELTSTATUS_Y)), sg1); - current_position_final = st_get_position_mm(axis); - measured_axis_length[0] = abs(current_position_final - current_position_init); + current_position_final = st_get_position_mm(axis); + measured_axis_length[0] = abs(current_position_final - current_position_init); -// first measurement end and second measurement begin +// first measurement end and second measurement begin - current_position[axis] -= margin; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); + current_position[axis] -= margin; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); - current_position[axis] -= (axis_length + margin); - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - - st_synchronize(); + current_position[axis] -= (axis_length + margin); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - current_position_init = st_get_position_mm(axis); + st_synchronize(); - measured_axis_length[1] = abs(current_position_final - current_position_init); + current_position_init = st_get_position_mm(axis); + + measured_axis_length[1] = abs(current_position_final - current_position_init); //end of second measurement, now check for possible errors: - for(int i = 0; i < 2; i++){ //check if measured axis length corresponds to expected length - printf_P(_N("Measured axis length:%.3f\n"), measured_axis_length[i]); - if (abs(measured_axis_length[i] - axis_length) > max_error_mm) { - enable_endstops(false); + for(int i = 0; i < 2; i++) { //check if measured axis length corresponds to expected length + printf_P(_N("Measured axis length:%.3f\n"), measured_axis_length[i]); + if (abs(measured_axis_length[i] - axis_length) > max_error_mm) { + enable_endstops(false); - const char *_error_1; + const char *_error_1; - if (axis == X_AXIS) _error_1 = "X"; - if (axis == Y_AXIS) _error_1 = "Y"; - if (axis == Z_AXIS) _error_1 = "Z"; + if (axis == X_AXIS) _error_1 = "X"; + if (axis == Y_AXIS) _error_1 = "Y"; + if (axis == Z_AXIS) _error_1 = "Z"; - lcd_selftest_error(9, _error_1, NULL); - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - reset_crash_det(axis); - return false; - } - } + lcd_selftest_error(9, _error_1, NULL); + current_position[axis] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + reset_crash_det(axis); + return false; + } + } - printf_P(_N("Axis length difference:%.3f\n"), abs(measured_axis_length[0] - measured_axis_length[1])); - - if (abs(measured_axis_length[0] - measured_axis_length[1]) > 1) { //check if difference between first and second measurement is low - //loose pulleys - const char *_error_1; + printf_P(_N("Axis length difference:%.3f\n"), abs(measured_axis_length[0] - measured_axis_length[1])); - if (axis == X_AXIS) _error_1 = "X"; - if (axis == Y_AXIS) _error_1 = "Y"; - if (axis == Z_AXIS) _error_1 = "Z"; + if (abs(measured_axis_length[0] - measured_axis_length[1]) > 1) { //check if difference between first and second measurement is low + //loose pulleys + const char *_error_1; - lcd_selftest_error(8, _error_1, NULL); - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - reset_crash_det(axis); + if (axis == X_AXIS) _error_1 = "X"; + if (axis == Y_AXIS) _error_1 = "Y"; + if (axis == Z_AXIS) _error_1 = "Z"; - return false; - } - current_position[axis] = 0; - plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); - reset_crash_det(axis); - return true; + lcd_selftest_error(8, _error_1, NULL); + current_position[axis] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + reset_crash_det(axis); + + return false; + } + current_position[axis] = 0; + plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); + reset_crash_det(axis); + return true; } #endif //TMC2130 @@ -6487,559 +6579,572 @@ static bool lcd_selfcheck_axis_sg(unsigned char axis) { static bool lcd_selfcheck_axis(int _axis, int _travel) { // printf_P(PSTR("lcd_selfcheck_axis %d, %d\n"), _axis, _travel); - bool _stepdone = false; - bool _stepresult = false; - int _progress = 0; - int _travel_done = 0; - int _err_endstop = 0; - int _lcd_refresh = 0; - _travel = _travel + (_travel / 10); - - if (_axis == X_AXIS) { - current_position[Z_AXIS] += 17; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - } + bool _stepdone = false; + bool _stepresult = false; + int _progress = 0; + int _travel_done = 0; + int _err_endstop = 0; + int _lcd_refresh = 0; + _travel = _travel + (_travel / 10); + + if (_axis == X_AXIS) { + current_position[Z_AXIS] += 17; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + } - do { - current_position[_axis] = current_position[_axis] - 1; + do { + current_position[_axis] = current_position[_axis] - 1; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); #ifdef TMC2130 - if ((READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING)) + if ((READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING)) #else //TMC2130 - if ((READ(X_MIN_PIN) ^ (bool)X_MIN_ENDSTOP_INVERTING) || - (READ(Y_MIN_PIN) ^ (bool)Y_MIN_ENDSTOP_INVERTING) || - (READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING)) + if ((READ(X_MIN_PIN) ^ (bool)X_MIN_ENDSTOP_INVERTING) || + (READ(Y_MIN_PIN) ^ (bool)Y_MIN_ENDSTOP_INVERTING) || + (READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING)) #endif //TMC2130 - { - if (_axis == 0) - { - _stepresult = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? true : false; - _err_endstop = ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ? 1 : 2; + { + if (_axis == 0) + { + _stepresult = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? true : false; + _err_endstop = ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ? 1 : 2; - } - if (_axis == 1) - { - _stepresult = ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ? true : false; - _err_endstop = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? 0 : 2; + } + if (_axis == 1) + { + _stepresult = ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ? true : false; + _err_endstop = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? 0 : 2; - } - if (_axis == 2) - { - _stepresult = ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) ? true : false; - _err_endstop = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? 0 : 1; - printf_P(PSTR("lcd_selfcheck_axis %d, %d\n"), _stepresult, _err_endstop); - /*disable_x(); - disable_y(); - disable_z();*/ - } - _stepdone = true; - } + } + if (_axis == 2) + { + _stepresult = ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) ? true : false; + _err_endstop = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? 0 : 1; + printf_P(PSTR("lcd_selfcheck_axis %d, %d\n"), _stepresult, _err_endstop); + /*disable_x(); + disable_y(); + disable_z();*/ + } + _stepdone = true; + } - if (_lcd_refresh < 6) - { - _lcd_refresh++; - } - else - { - _progress = lcd_selftest_screen(4 + _axis, _progress, 3, false, 0); - _lcd_refresh = 0; - } + if (_lcd_refresh < 6) + { + _lcd_refresh++; + } + else + { + _progress = lcd_selftest_screen(4 + _axis, _progress, 3, false, 0); + _lcd_refresh = 0; + } - manage_heater(); - manage_inactivity(true); + manage_heater(); + manage_inactivity(true); - //delay(100); - (_travel_done <= _travel) ? _travel_done++ : _stepdone = true; + //delay(100); + (_travel_done <= _travel) ? _travel_done++ : _stepdone = true; - } while (!_stepdone); + } while (!_stepdone); - //current_position[_axis] = current_position[_axis] + 15; - //plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + //current_position[_axis] = current_position[_axis] + 15; + //plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - if (!_stepresult) - { - const char *_error_1; - const char *_error_2; + if (!_stepresult) + { + const char *_error_1; + const char *_error_2; - if (_axis == X_AXIS) _error_1 = "X"; - if (_axis == Y_AXIS) _error_1 = "Y"; - if (_axis == Z_AXIS) _error_1 = "Z"; + if (_axis == X_AXIS) _error_1 = "X"; + if (_axis == Y_AXIS) _error_1 = "Y"; + if (_axis == Z_AXIS) _error_1 = "Z"; - if (_err_endstop == 0) _error_2 = "X"; - if (_err_endstop == 1) _error_2 = "Y"; - if (_err_endstop == 2) _error_2 = "Z"; + if (_err_endstop == 0) _error_2 = "X"; + if (_err_endstop == 1) _error_2 = "Y"; + if (_err_endstop == 2) _error_2 = "Z"; - if (_travel_done >= _travel) - { - lcd_selftest_error(5, _error_1, _error_2); - } - else - { - lcd_selftest_error(4, _error_1, _error_2); - } - } + if (_travel_done >= _travel) + { + lcd_selftest_error(5, _error_1, _error_2); + } + else + { + lcd_selftest_error(4, _error_1, _error_2); + } + } - return _stepresult; + return _stepresult; } #ifndef TMC2130 static bool lcd_selfcheck_pulleys(int axis) -{ - float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; - float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT; - float current_position_init; - float move; - bool endstop_triggered = false; - int i; - unsigned long timeout_counter; - refresh_cmd_timeout(); - manage_inactivity(true); - - if (axis == 0) move = 50; //X_AXIS - else move = 50; //Y_AXIS - - current_position_init = current_position[axis]; - - current_position[axis] += 2; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - for (i = 0; i < 5; i++) { - refresh_cmd_timeout(); - current_position[axis] = current_position[axis] + move; - st_current_set(0, 850); //set motor current higher - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 200, active_extruder); - st_synchronize(); - if (SilentModeMenu != SILENT_MODE_OFF) st_current_set(0, tmp_motor[0]); //set back to normal operation currents - else st_current_set(0, tmp_motor_loud[0]); //set motor current back - current_position[axis] = current_position[axis] - move; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 50, active_extruder); - st_synchronize(); - if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || - ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1)) { - lcd_selftest_error(8, (axis == 0) ? "X" : "Y", ""); - return(false); - } - } - timeout_counter = millis() + 2500; - endstop_triggered = false; - manage_inactivity(true); - while (!endstop_triggered) { - if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || - ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1)) { - endstop_triggered = true; - if (current_position_init - 1 <= current_position[axis] && current_position_init + 1 >= current_position[axis]) { - current_position[axis] += (axis == X_AXIS) ? 13 : 9; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); - return(true); - } - else { - lcd_selftest_error(8, (axis == 0) ? "X" : "Y", ""); - return(false); - } - } - else { - current_position[axis] -= 1; - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); - st_synchronize(); - if (millis() > timeout_counter) { - lcd_selftest_error(8, (axis == 0) ? "X" : "Y", ""); - return(false); - } - } - } - return(true); +{ + float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD; + float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT; + float current_position_init; + float move; + bool endstop_triggered = false; + int i; + unsigned long timeout_counter; + refresh_cmd_timeout(); + manage_inactivity(true); + + if (axis == 0) move = 50; //X_AXIS + else move = 50; //Y_AXIS + + current_position_init = current_position[axis]; + + current_position[axis] += 2; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + for (i = 0; i < 5; i++) { + refresh_cmd_timeout(); + current_position[axis] = current_position[axis] + move; + st_current_set(0, 850); //set motor current higher + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 200, active_extruder); + st_synchronize(); + if (SilentModeMenu != SILENT_MODE_OFF) st_current_set(0, tmp_motor[0]); //set back to normal operation currents + else st_current_set(0, tmp_motor_loud[0]); //set motor current back + current_position[axis] = current_position[axis] - move; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], 50, active_extruder); + st_synchronize(); + if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || + ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1)) { + lcd_selftest_error(8, (axis == 0) ? "X" : "Y", ""); + return(false); + } + } + timeout_counter = millis() + 2500; + endstop_triggered = false; + manage_inactivity(true); + while (!endstop_triggered) { + if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || + ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1)) { + endstop_triggered = true; + if (current_position_init - 1 <= current_position[axis] && current_position_init + 1 >= current_position[axis]) { + current_position[axis] += (axis == X_AXIS) ? 13 : 9; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); + return(true); + } + else { + lcd_selftest_error(8, (axis == 0) ? "X" : "Y", ""); + return(false); + } + } + else { + current_position[axis] -= 1; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[3], manual_feedrate[0] / 60, active_extruder); + st_synchronize(); + if (millis() > timeout_counter) { + lcd_selftest_error(8, (axis == 0) ? "X" : "Y", ""); + return(false); + } + } + } + return(true); } static bool lcd_selfcheck_endstops() { - bool _result = true; + bool _result = true; - if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || - ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) || - ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1)) - { - if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) current_position[0] += 10; - if ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) current_position[1] += 10; - if ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) current_position[2] += 10; - } - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[0] / 60, active_extruder); - delay(500); + if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || + ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) || + ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1)) + { + if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) current_position[0] += 10; + if ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) current_position[1] += 10; + if ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) current_position[2] += 10; + } + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[0] / 60, active_extruder); + delay(500); - if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || - ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) || - ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1)) - { - _result = false; - char _error[4] = ""; - if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "X"); - if ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Y"); - if ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Z"); - lcd_selftest_error(3, _error, ""); - } - manage_heater(); - manage_inactivity(true); - return _result; + if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) || + ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) || + ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1)) + { + _result = false; + char _error[4] = ""; + if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "X"); + if ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Y"); + if ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Z"); + lcd_selftest_error(3, _error, ""); + } + manage_heater(); + manage_inactivity(true); + return _result; } #endif //not defined TMC2130 static bool lcd_selfcheck_check_heater(bool _isbed) { - int _counter = 0; - int _progress = 0; - bool _stepresult = false; - bool _docycle = true; - - int _checked_snapshot = (_isbed) ? degBed() : degHotend(0); - int _opposite_snapshot = (_isbed) ? degHotend(0) : degBed(); - int _cycles = (_isbed) ? 180 : 60; //~ 90s / 30s - - target_temperature[0] = (_isbed) ? 0 : 200; - target_temperature_bed = (_isbed) ? 100 : 0; - manage_heater(); - manage_inactivity(true); - KEEPALIVE_STATE(NOT_BUSY); //we are sending temperatures on serial line, so no need to send host keepalive messages - - do { - _counter++; - _docycle = (_counter < _cycles) ? true : false; - - manage_heater(); - manage_inactivity(true); - _progress = (_isbed) ? lcd_selftest_screen(7, _progress, 2, false, 400) : lcd_selftest_screen(3, _progress, 2, false, 400); - /*if (_isbed) { - MYSERIAL.print("Bed temp:"); - MYSERIAL.println(degBed()); - } - else { - MYSERIAL.print("Hotend temp:"); - MYSERIAL.println(degHotend(0)); - }*/ - if(_counter%5 == 0) serialecho_temperatures(); //show temperatures once in two seconds - - } while (_docycle); - - target_temperature[0] = 0; - target_temperature_bed = 0; - manage_heater(); - - int _checked_result = (_isbed) ? degBed() - _checked_snapshot : degHotend(0) - _checked_snapshot; - int _opposite_result = (_isbed) ? degHotend(0) - _opposite_snapshot : degBed() - _opposite_snapshot; - /* - MYSERIAL.println(""); - MYSERIAL.print("Checked result:"); - MYSERIAL.println(_checked_result); - MYSERIAL.print("Opposite result:"); - MYSERIAL.println(_opposite_result); - */ - if (_opposite_result < ((_isbed) ? 10 : 3)) - { - if (_checked_result >= ((_isbed) ? 3 : 10)) - { - _stepresult = true; - } - else - { - lcd_selftest_error(1, "", ""); - } - } - else - { - lcd_selftest_error(2, "", ""); - } + int _counter = 0; + int _progress = 0; + bool _stepresult = false; + bool _docycle = true; + + int _checked_snapshot = (_isbed) ? degBed() : degHotend(0); + int _opposite_snapshot = (_isbed) ? degHotend(0) : degBed(); + int _cycles = (_isbed) ? 180 : 60; //~ 90s / 30s - manage_heater(); - manage_inactivity(true); - KEEPALIVE_STATE(IN_HANDLER); - return _stepresult; + target_temperature[0] = (_isbed) ? 0 : 200; + target_temperature_bed = (_isbed) ? 100 : 0; + manage_heater(); + manage_inactivity(true); + KEEPALIVE_STATE(NOT_BUSY); //we are sending temperatures on serial line, so no need to send host keepalive messages + + do { + _counter++; + _docycle = (_counter < _cycles) ? true : false; + + manage_heater(); + manage_inactivity(true); + _progress = (_isbed) ? lcd_selftest_screen(7, _progress, 2, false, 400) : lcd_selftest_screen(3, _progress, 2, false, 400); + /*if (_isbed) { + MYSERIAL.print("Bed temp:"); + MYSERIAL.println(degBed()); + } + else { + MYSERIAL.print("Hotend temp:"); + MYSERIAL.println(degHotend(0)); + }*/ + if(_counter%5 == 0) serialecho_temperatures(); //show temperatures once in two seconds + + } while (_docycle); + + target_temperature[0] = 0; + target_temperature_bed = 0; + manage_heater(); + + int _checked_result = (_isbed) ? degBed() - _checked_snapshot : degHotend(0) - _checked_snapshot; + int _opposite_result = (_isbed) ? degHotend(0) - _opposite_snapshot : degBed() - _opposite_snapshot; + /* + MYSERIAL.println(""); + MYSERIAL.print("Checked result:"); + MYSERIAL.println(_checked_result); + MYSERIAL.print("Opposite result:"); + MYSERIAL.println(_opposite_result); + */ + if (_opposite_result < ((_isbed) ? 10 : 3)) + { + if (_checked_result >= ((_isbed) ? 3 : 10)) + { + _stepresult = true; + } + else + { + lcd_selftest_error(1, "", ""); + } + } + else + { + lcd_selftest_error(2, "", ""); + } + + manage_heater(); + manage_inactivity(true); + KEEPALIVE_STATE(IN_HANDLER); + return _stepresult; } static void lcd_selftest_error(int _error_no, const char *_error_1, const char *_error_2) { - lcd_beeper_quick_feedback(); + lcd_beeper_quick_feedback(); - target_temperature[0] = 0; - target_temperature_bed = 0; - manage_heater(); - manage_inactivity(); + target_temperature[0] = 0; + target_temperature_bed = 0; + manage_heater(); + manage_inactivity(); - lcd_clear(); + lcd_clear(); - lcd_set_cursor(0, 0); - lcd_puts_P(_i("Selftest error !"));////MSG_SELFTEST_ERROR c=0 r=0 - lcd_set_cursor(0, 1); - lcd_puts_P(_i("Please check :"));////MSG_SELFTEST_PLEASECHECK c=0 r=0 + lcd_set_cursor(0, 0); + lcd_puts_P(_i("Selftest error !"));////MSG_SELFTEST_ERROR c=0 r=0 + lcd_set_cursor(0, 1); + lcd_puts_P(_i("Please check :"));////MSG_SELFTEST_PLEASECHECK c=0 r=0 - switch (_error_no) - { - case 1: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Heater/Thermistor"));////MSG_SELFTEST_HEATERTHERMISTOR c=0 r=0 - lcd_set_cursor(0, 3); - lcd_puts_P(_i("Not connected"));////MSG_SELFTEST_NOTCONNECTED c=0 r=0 - break; - case 2: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Bed / Heater"));////MSG_SELFTEST_BEDHEATER c=0 r=0 - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); - break; - case 3: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Endstops"));////MSG_SELFTEST_ENDSTOPS c=0 r=0 - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); - lcd_set_cursor(17, 3); - lcd_print(_error_1); - break; - case 4: - lcd_set_cursor(0, 2); - lcd_puts_P(_T(MSG_SELFTEST_MOTOR)); - lcd_set_cursor(18, 2); - lcd_print(_error_1); - lcd_set_cursor(0, 3); - lcd_puts_P(_i("Endstop"));////MSG_SELFTEST_ENDSTOP c=0 r=0 - lcd_set_cursor(18, 3); - lcd_print(_error_2); - break; - case 5: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Endstop not hit"));////MSG_SELFTEST_ENDSTOP_NOTHIT c=20 r=1 - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_SELFTEST_MOTOR)); - lcd_set_cursor(18, 3); - lcd_print(_error_1); - break; - case 6: - lcd_set_cursor(0, 2); - lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN)); - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); - lcd_set_cursor(18, 3); - lcd_print(_error_1); - break; - case 7: - lcd_set_cursor(0, 2); - lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN)); - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); - lcd_set_cursor(18, 3); - lcd_print(_error_1); - break; - case 8: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Loose pulley"));////MSG_LOOSE_PULLEY c=20 r=1 - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_SELFTEST_MOTOR)); - lcd_set_cursor(18, 3); - lcd_print(_error_1); - break; - case 9: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Axis length"));////MSG_SELFTEST_AXIS_LENGTH c=0 r=0 - lcd_set_cursor(0, 3); - lcd_puts_P(_i("Axis"));////MSG_SELFTEST_AXIS c=0 r=0 - lcd_set_cursor(18, 3); - lcd_print(_error_1); - break; - case 10: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Front/left fans"));////MSG_SELFTEST_FANS c=0 r=0 - lcd_set_cursor(0, 3); - lcd_puts_P(_i("Swapped"));////MSG_SELFTEST_SWAPPED c=0 r=0 - lcd_set_cursor(18, 3); - lcd_print(_error_1); - break; - case 11: - lcd_set_cursor(0, 2); - lcd_puts_P(_i("Filament sensor"));////MSG_FILAMENT_SENSOR c=20 r=0 - lcd_set_cursor(0, 3); - lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); - break; - } + switch (_error_no) + { + case 1: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Heater/Thermistor"));////MSG_SELFTEST_HEATERTHERMISTOR c=0 r=0 + lcd_set_cursor(0, 3); + lcd_puts_P(_i("Not connected"));////MSG_SELFTEST_NOTCONNECTED c=0 r=0 + break; + case 2: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Bed / Heater"));////MSG_SELFTEST_BEDHEATER c=0 r=0 + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); + break; + case 3: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Endstops"));////MSG_SELFTEST_ENDSTOPS c=0 r=0 + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); + lcd_set_cursor(17, 3); + lcd_print(_error_1); + break; + case 4: + lcd_set_cursor(0, 2); + lcd_puts_P(_T(MSG_SELFTEST_MOTOR)); + lcd_set_cursor(18, 2); + lcd_print(_error_1); + lcd_set_cursor(0, 3); + lcd_puts_P(_i("Endstop"));////MSG_SELFTEST_ENDSTOP c=0 r=0 + lcd_set_cursor(18, 3); + lcd_print(_error_2); + break; + case 5: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Endstop not hit"));////MSG_SELFTEST_ENDSTOP_NOTHIT c=20 r=1 + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_SELFTEST_MOTOR)); + lcd_set_cursor(18, 3); + lcd_print(_error_1); + break; + case 6: + lcd_set_cursor(0, 2); + lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN)); + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); + lcd_set_cursor(18, 3); + lcd_print(_error_1); + break; + case 7: + lcd_set_cursor(0, 2); + lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN)); + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); + lcd_set_cursor(18, 3); + lcd_print(_error_1); + break; + case 8: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Loose pulley"));////MSG_LOOSE_PULLEY c=20 r=1 + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_SELFTEST_MOTOR)); + lcd_set_cursor(18, 3); + lcd_print(_error_1); + break; + case 9: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Axis length"));////MSG_SELFTEST_AXIS_LENGTH c=0 r=0 + lcd_set_cursor(0, 3); + lcd_puts_P(_i("Axis"));////MSG_SELFTEST_AXIS c=0 r=0 + lcd_set_cursor(18, 3); + lcd_print(_error_1); + break; + case 10: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Front/left fans"));////MSG_SELFTEST_FANS c=0 r=0 + lcd_set_cursor(0, 3); + lcd_puts_P(_i("Swapped"));////MSG_SELFTEST_SWAPPED c=0 r=0 + lcd_set_cursor(18, 3); + lcd_print(_error_1); + break; + case 11: + lcd_set_cursor(0, 2); + lcd_puts_P(_i("Filament sensor"));////MSG_FILAMENT_SENSOR c=20 r=0 + lcd_set_cursor(0, 3); + lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR)); + break; + } - delay(1000); - lcd_beeper_quick_feedback(); + delay(1000); + lcd_beeper_quick_feedback(); - do { - delay(100); - manage_heater(); - manage_inactivity(); - } while (!lcd_clicked()); + do { + delay(100); + manage_heater(); + manage_inactivity(); + } while (!lcd_clicked()); - LCD_ALERTMESSAGERPGM(_T(MSG_SELFTEST_FAILED)); - lcd_return_to_status(); + LCD_ALERTMESSAGERPGM(_T(MSG_SELFTEST_FAILED)); + lcd_return_to_status(); } #ifdef FILAMENT_SENSOR static bool lcd_selftest_fsensor(void) { - fsensor_init(); - if (fsensor_not_responding) - { - lcd_selftest_error(11, NULL, NULL); - } - return (!fsensor_not_responding); + fsensor_init(); + if (fsensor_not_responding) + { + lcd_selftest_error(11, NULL, NULL); + } + return (!fsensor_not_responding); } #endif //FILAMENT_SENSOR static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite) { - bool _result = check_opposite; - lcd_clear(); + bool _result = check_opposite; + lcd_clear(); - lcd_set_cursor(0, 0); lcd_puts_P(_T(MSG_SELFTEST_FAN)); - - switch (_fan) - { - case 0: - // extruder cooling fan - lcd_set_cursor(0, 1); - if(check_opposite == true) lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN)); - else lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN)); - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); - break; - case 1: - // object cooling fan - lcd_set_cursor(0, 1); - if (check_opposite == true) lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN)); - else lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN)); - SET_OUTPUT(FAN_PIN); - analogWrite(FAN_PIN, 255); - break; - } - delay(500); + lcd_set_cursor(0, 0); + lcd_puts_P(_T(MSG_SELFTEST_FAN)); - lcd_set_cursor(1, 2); lcd_puts_P(_T(MSG_SELFTEST_FAN_YES)); - lcd_set_cursor(0, 3); lcd_print(">"); - lcd_set_cursor(1, 3); lcd_puts_P(_T(MSG_SELFTEST_FAN_NO)); + switch (_fan) + { + case 0: + // extruder cooling fan + lcd_set_cursor(0, 1); + if(check_opposite == true) lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN)); + else lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN)); + SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); + WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); + break; + case 1: + // object cooling fan + lcd_set_cursor(0, 1); + if (check_opposite == true) lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN)); + else lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN)); + SET_OUTPUT(FAN_PIN); + analogWrite(FAN_PIN, 255); + break; + } + delay(500); - int8_t enc_dif = 0; - KEEPALIVE_STATE(PAUSED_FOR_USER); + lcd_set_cursor(1, 2); + lcd_puts_P(_T(MSG_SELFTEST_FAN_YES)); + lcd_set_cursor(0, 3); + lcd_print(">"); + lcd_set_cursor(1, 3); + lcd_puts_P(_T(MSG_SELFTEST_FAN_NO)); - lcd_button_pressed = false; - do - { - switch (_fan) - { - case 0: - // extruder cooling fan - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); - break; - case 1: - // object cooling fan - SET_OUTPUT(FAN_PIN); - analogWrite(FAN_PIN, 255); - break; - } + int8_t enc_dif = 0; + KEEPALIVE_STATE(PAUSED_FOR_USER); - if (abs((enc_dif - lcd_encoder_diff)) > 2) { - if (enc_dif > lcd_encoder_diff) { - _result = !check_opposite; - lcd_set_cursor(0, 2); lcd_print(">"); - lcd_set_cursor(1, 2); lcd_puts_P(_T(MSG_SELFTEST_FAN_YES)); - lcd_set_cursor(0, 3); lcd_print(" "); - lcd_set_cursor(1, 3); lcd_puts_P(_T(MSG_SELFTEST_FAN_NO)); - } + lcd_button_pressed = false; + do + { + switch (_fan) + { + case 0: + // extruder cooling fan + SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); + WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); + break; + case 1: + // object cooling fan + SET_OUTPUT(FAN_PIN); + analogWrite(FAN_PIN, 255); + break; + } - if (enc_dif < lcd_encoder_diff) { - _result = check_opposite; - lcd_set_cursor(0, 2); lcd_print(" "); - lcd_set_cursor(1, 2); lcd_puts_P(_T(MSG_SELFTEST_FAN_YES)); - lcd_set_cursor(0, 3); lcd_print(">"); - lcd_set_cursor(1, 3); lcd_puts_P(_T(MSG_SELFTEST_FAN_NO)); - } - enc_dif = 0; - lcd_encoder_diff = 0; - } + if (abs((enc_dif - lcd_encoder_diff)) > 2) { + if (enc_dif > lcd_encoder_diff) { + _result = !check_opposite; + lcd_set_cursor(0, 2); + lcd_print(">"); + lcd_set_cursor(1, 2); + lcd_puts_P(_T(MSG_SELFTEST_FAN_YES)); + lcd_set_cursor(0, 3); + lcd_print(" "); + lcd_set_cursor(1, 3); + lcd_puts_P(_T(MSG_SELFTEST_FAN_NO)); + } + + if (enc_dif < lcd_encoder_diff) { + _result = check_opposite; + lcd_set_cursor(0, 2); + lcd_print(" "); + lcd_set_cursor(1, 2); + lcd_puts_P(_T(MSG_SELFTEST_FAN_YES)); + lcd_set_cursor(0, 3); + lcd_print(">"); + lcd_set_cursor(1, 3); + lcd_puts_P(_T(MSG_SELFTEST_FAN_NO)); + } + enc_dif = 0; + lcd_encoder_diff = 0; + } - manage_heater(); - delay(100); + manage_heater(); + delay(100); - } while (!lcd_clicked()); - KEEPALIVE_STATE(IN_HANDLER); - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 0); - SET_OUTPUT(FAN_PIN); - analogWrite(FAN_PIN, 0); + } while (!lcd_clicked()); + KEEPALIVE_STATE(IN_HANDLER); + SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); + WRITE(EXTRUDER_0_AUTO_FAN_PIN, 0); + SET_OUTPUT(FAN_PIN); + analogWrite(FAN_PIN, 0); - fanSpeed = 0; - manage_heater(); + fanSpeed = 0; + manage_heater(); - return _result; + return _result; } static bool lcd_selftest_fan_dialog(int _fan) { - bool _result = true; - int _errno = 7; - - switch (_fan) { - case 0: - fanSpeed = 0; - manage_heater(); //turn off fan - setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //extruder fan - delay(2000); //delay_keep_alive would turn off extruder fan, because temerature is too low - manage_heater(); //count average fan speed from 2s delay and turn off fans - if (!fan_speed[0]) _result = false; - //SERIAL_ECHOPGM("Extruder fan speed: "); - //MYSERIAL.println(fan_speed[0]); - //SERIAL_ECHOPGM("Print fan speed: "); - //MYSERIAL.print(fan_speed[1]); - break; - - case 1: - //will it work with Thotend > 50 C ? - fanSpeed = 150; //print fan - for (uint8_t i = 0; i < 5; i++) { - delay_keep_alive(1000); - lcd_set_cursor(18, 3); - lcd_print("-"); - delay_keep_alive(1000); - lcd_set_cursor(18, 3); - lcd_print("|"); - } - fanSpeed = 0; - manage_heater(); //turn off fan - manage_inactivity(true); //to turn off print fan - if (!fan_speed[1]) { - _result = false; _errno = 6; //print fan not spinning - } - else if (fan_speed[1] < 34) { //fan is spinning, but measured RPM are too low for print fan, it must be left extruder fan - //check fans manually + bool _result = true; + int _errno = 7; + + switch (_fan) { + case 0: + fanSpeed = 0; + manage_heater(); //turn off fan + setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //extruder fan + delay(2000); //delay_keep_alive would turn off extruder fan, because temerature is too low + manage_heater(); //count average fan speed from 2s delay and turn off fans + if (!fan_speed[0]) _result = false; + //SERIAL_ECHOPGM("Extruder fan speed: "); + //MYSERIAL.println(fan_speed[0]); + //SERIAL_ECHOPGM("Print fan speed: "); + //MYSERIAL.print(fan_speed[1]); + break; - _result = lcd_selftest_manual_fan_check(1, true); //turn on print fan and check that left extruder fan is not spinning - if (_result) { - _result = lcd_selftest_manual_fan_check(1, false); //print fan is stil turned on; check that it is spinning - if (!_result) _errno = 6; //print fan not spinning - } - else { - _errno = 10; //swapped fans - } - } + case 1: + //will it work with Thotend > 50 C ? + fanSpeed = 150; //print fan + for (uint8_t i = 0; i < 5; i++) { + delay_keep_alive(1000); + lcd_set_cursor(18, 3); + lcd_print("-"); + delay_keep_alive(1000); + lcd_set_cursor(18, 3); + lcd_print("|"); + } + fanSpeed = 0; + manage_heater(); //turn off fan + manage_inactivity(true); //to turn off print fan + if (!fan_speed[1]) { + _result = false; + _errno = 6; //print fan not spinning + } + else if (fan_speed[1] < 34) { //fan is spinning, but measured RPM are too low for print fan, it must be left extruder fan + //check fans manually - //SERIAL_ECHOPGM("Extruder fan speed: "); - //MYSERIAL.println(fan_speed[0]); - //SERIAL_ECHOPGM("Print fan speed: "); - //MYSERIAL.println(fan_speed[1]); - break; - } - if (!_result) - { - lcd_selftest_error(_errno, NULL, NULL); - } - return _result; + _result = lcd_selftest_manual_fan_check(1, true); //turn on print fan and check that left extruder fan is not spinning + if (_result) { + _result = lcd_selftest_manual_fan_check(1, false); //print fan is stil turned on; check that it is spinning + if (!_result) _errno = 6; //print fan not spinning + } + else { + _errno = 10; //swapped fans + } + } + + //SERIAL_ECHOPGM("Extruder fan speed: "); + //MYSERIAL.println(fan_speed[0]); + //SERIAL_ECHOPGM("Print fan speed: "); + //MYSERIAL.println(fan_speed[1]); + break; + } + if (!_result) + { + lcd_selftest_error(_errno, NULL, NULL); + } + return _result; } static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bool _clear, int _delay) @@ -7047,96 +7152,96 @@ static int lcd_selftest_screen(int _step, int _progress, int _progress_scale, bo lcd_update_enable(false); - int _step_block = 0; - const char *_indicator = (_progress > _progress_scale) ? "-" : "|"; - - if (_clear) lcd_clear(); - - - lcd_set_cursor(0, 0); - - if (_step == -1) lcd_puts_P(_T(MSG_SELFTEST_FAN)); - if (_step == 0) lcd_puts_P(_T(MSG_SELFTEST_FAN)); - if (_step == 1) lcd_puts_P(_T(MSG_SELFTEST_FAN)); - if (_step == 2) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20 r=0 - if (_step == 3) lcd_puts_P(_i("Checking hotend "));////MSG_SELFTEST_CHECK_HOTEND c=20 r=0 - if (_step == 4) lcd_puts_P(_i("Checking X axis "));////MSG_SELFTEST_CHECK_X c=20 r=0 - if (_step == 5) lcd_puts_P(_i("Checking Y axis "));////MSG_SELFTEST_CHECK_Y c=20 r=0 - if (_step == 6) lcd_puts_P(_i("Checking Z axis "));////MSG_SELFTEST_CHECK_Z c=20 r=0 - if (_step == 7) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); - if (_step == 8) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); - if (_step == 9) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR)); - if (_step == 10) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR)); - if (_step == 11) lcd_puts_P(_i("All correct "));////MSG_SELFTEST_CHECK_ALLCORRECT c=20 r=0 - if (_step == 12) lcd_puts_P(_T(MSG_SELFTEST_FAILED)); - if (_step == 13) lcd_puts_P(PSTR("Calibrating home")); - - lcd_set_cursor(0, 1); - lcd_puts_P(separator); - if ((_step >= -1) && (_step <= 1)) - { - //SERIAL_ECHOLNPGM("Fan test"); - lcd_puts_at_P(0, 2, _i("Extruder fan:"));////MSG_SELFTEST_EXTRUDER_FAN_SPEED c=18 r=0 - lcd_set_cursor(18, 2); - (_step < 0) ? lcd_print(_indicator) : lcd_print("OK"); - lcd_puts_at_P(0, 3, _i("Print fan:"));////MSG_SELFTEST_PRINT_FAN_SPEED c=18 r=0 - lcd_set_cursor(18, 3); - (_step < 1) ? lcd_print(_indicator) : lcd_print("OK"); - } - else if (_step >= 9 && _step <= 10) - { - lcd_puts_at_P(0, 2, _i("Filament sensor:"));////MSG_SELFTEST_FILAMENT_SENSOR c=18 r=0 - lcd_set_cursor(18, 2); - (_step == 9) ? lcd_print(_indicator) : lcd_print("OK"); - } - else if (_step < 9) - { - //SERIAL_ECHOLNPGM("Other tests"); - _step_block = 3; - lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator); + int _step_block = 0; + const char *_indicator = (_progress > _progress_scale) ? "-" : "|"; - _step_block = 4; - lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator); + if (_clear) lcd_clear(); - _step_block = 5; - lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator); - _step_block = 6; - lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator); + lcd_set_cursor(0, 0); - _step_block = 7; - lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator); - } + if (_step == -1) lcd_puts_P(_T(MSG_SELFTEST_FAN)); + if (_step == 0) lcd_puts_P(_T(MSG_SELFTEST_FAN)); + if (_step == 1) lcd_puts_P(_T(MSG_SELFTEST_FAN)); + if (_step == 2) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20 r=0 + if (_step == 3) lcd_puts_P(_i("Checking hotend "));////MSG_SELFTEST_CHECK_HOTEND c=20 r=0 + if (_step == 4) lcd_puts_P(_i("Checking X axis "));////MSG_SELFTEST_CHECK_X c=20 r=0 + if (_step == 5) lcd_puts_P(_i("Checking Y axis "));////MSG_SELFTEST_CHECK_Y c=20 r=0 + if (_step == 6) lcd_puts_P(_i("Checking Z axis "));////MSG_SELFTEST_CHECK_Z c=20 r=0 + if (_step == 7) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); + if (_step == 8) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED)); + if (_step == 9) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR)); + if (_step == 10) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR)); + if (_step == 11) lcd_puts_P(_i("All correct "));////MSG_SELFTEST_CHECK_ALLCORRECT c=20 r=0 + if (_step == 12) lcd_puts_P(_T(MSG_SELFTEST_FAILED)); + if (_step == 13) lcd_puts_P(PSTR("Calibrating home")); + + lcd_set_cursor(0, 1); + lcd_puts_P(separator); + if ((_step >= -1) && (_step <= 1)) + { + //SERIAL_ECHOLNPGM("Fan test"); + lcd_puts_at_P(0, 2, _i("Extruder fan:"));////MSG_SELFTEST_EXTRUDER_FAN_SPEED c=18 r=0 + lcd_set_cursor(18, 2); + (_step < 0) ? lcd_print(_indicator) : lcd_print("OK"); + lcd_puts_at_P(0, 3, _i("Print fan:"));////MSG_SELFTEST_PRINT_FAN_SPEED c=18 r=0 + lcd_set_cursor(18, 3); + (_step < 1) ? lcd_print(_indicator) : lcd_print("OK"); + } + else if (_step >= 9 && _step <= 10) + { + lcd_puts_at_P(0, 2, _i("Filament sensor:"));////MSG_SELFTEST_FILAMENT_SENSOR c=18 r=0 + lcd_set_cursor(18, 2); + (_step == 9) ? lcd_print(_indicator) : lcd_print("OK"); + } + else if (_step < 9) + { + //SERIAL_ECHOLNPGM("Other tests"); + _step_block = 3; + lcd_selftest_screen_step(3, 9, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Hotend", _indicator); + + _step_block = 4; + lcd_selftest_screen_step(2, 2, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "X", _indicator); + + _step_block = 5; + lcd_selftest_screen_step(2, 8, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Y", _indicator); - if (_delay > 0) delay_keep_alive(_delay); - _progress++; + _step_block = 6; + lcd_selftest_screen_step(2, 14, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Z", _indicator); - return (_progress > _progress_scale * 2) ? 0 : _progress; + _step_block = 7; + lcd_selftest_screen_step(3, 0, ((_step == _step_block) ? 1 : (_step < _step_block) ? 0 : 2), "Bed", _indicator); + } + + if (_delay > 0) delay_keep_alive(_delay); + _progress++; + + return (_progress > _progress_scale * 2) ? 0 : _progress; } static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator) { - lcd_set_cursor(_col, _row); + lcd_set_cursor(_col, _row); - switch (_state) - { - case 1: - lcd_print(_name); - lcd_set_cursor(_col + strlen(_name), _row); - lcd_print(":"); - lcd_set_cursor(_col + strlen(_name) + 1, _row); - lcd_print(_indicator); - break; - case 2: - lcd_print(_name); - lcd_set_cursor(_col + strlen(_name), _row); - lcd_print(":"); - lcd_set_cursor(_col + strlen(_name) + 1, _row); - lcd_print("OK"); - break; - default: - lcd_print(_name); - } + switch (_state) + { + case 1: + lcd_print(_name); + lcd_set_cursor(_col + strlen(_name), _row); + lcd_print(":"); + lcd_set_cursor(_col + strlen(_name) + 1, _row); + lcd_print(_indicator); + break; + case 2: + lcd_print(_name); + lcd_set_cursor(_col + strlen(_name), _row); + lcd_print(":"); + lcd_set_cursor(_col + strlen(_name) + 1, _row); + lcd_print("OK"); + break; + default: + lcd_print(_name); + } } @@ -7145,82 +7250,82 @@ static void lcd_selftest_screen_step(int _row, int _col, int _state, const char /** Menu action functions **/ static bool check_file(const char* filename) { - if (farm_mode) return true; - bool result = false; - uint32_t filesize; - card.openFile((char*)filename, true); - filesize = card.getFileSize(); - if (filesize > END_FILE_SECTION) { - card.setIndex(filesize - END_FILE_SECTION); - - } - - while (!card.eof() && !result) { - card.sdprinting = true; - get_command(); - result = check_commands(); - - } - card.printingHasFinished(); - strncpy_P(lcd_status_message, _T(WELCOME_MSG), LCD_WIDTH); - lcd_finishstatus(); - return result; - + if (farm_mode) return true; + bool result = false; + uint32_t filesize; + card.openFile((char*)filename, true); + filesize = card.getFileSize(); + if (filesize > END_FILE_SECTION) { + card.setIndex(filesize - END_FILE_SECTION); + + } + + while (!card.eof() && !result) { + card.sdprinting = true; + get_command(); + result = check_commands(); + + } + card.printingHasFinished(); + strncpy_P(lcd_status_message, _T(WELCOME_MSG), LCD_WIDTH); + lcd_finishstatus(); + return result; + } static void menu_action_sdfile(const char* filename) { - loading_flag = false; - char cmd[30]; - char* c; - bool result = true; - sprintf_P(cmd, PSTR("M23 %s"), filename); - for (c = &cmd[4]; *c; c++) - *c = tolower(*c); - - const char end[5] = ".gco"; - - //we are storing just first 8 characters of 8.3 filename assuming that extension is always ".gco" - for (int i = 0; i < 8; i++) { - if (strcmp((cmd + i + 4), end) == 0) { - //filename is shorter then 8.3, store '\0' character on position where ".gco" string was found to terminate stored string properly - eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, '\0'); - break; - } - else { - eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, cmd[i + 4]); - } - } - - uint8_t depth = (uint8_t)card.getWorkDirDepth(); - eeprom_write_byte((uint8_t*)EEPROM_DIR_DEPTH, depth); - - for (uint8_t i = 0; i < depth; i++) { - for (int j = 0; j < 8; j++) { - eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, dir_names[i][j]); - } - } - - if (!check_file(filename)) { - result = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("File incomplete. Continue anyway?"), false, false);////MSG_FILE_INCOMPLETE c=20 r=2 - lcd_update_enable(true); - } - if (result) { - enquecommand(cmd); - enquecommand_P(PSTR("M24")); - } + loading_flag = false; + char cmd[30]; + char* c; + bool result = true; + sprintf_P(cmd, PSTR("M23 %s"), filename); + for (c = &cmd[4]; *c; c++) + *c = tolower(*c); + + const char end[5] = ".gco"; + + //we are storing just first 8 characters of 8.3 filename assuming that extension is always ".gco" + for (int i = 0; i < 8; i++) { + if (strcmp((cmd + i + 4), end) == 0) { + //filename is shorter then 8.3, store '\0' character on position where ".gco" string was found to terminate stored string properly + eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, '\0'); + break; + } + else { + eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, cmd[i + 4]); + } + } - lcd_return_to_status(); + uint8_t depth = (uint8_t)card.getWorkDirDepth(); + eeprom_write_byte((uint8_t*)EEPROM_DIR_DEPTH, depth); + + for (uint8_t i = 0; i < depth; i++) { + for (int j = 0; j < 8; j++) { + eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, dir_names[i][j]); + } + } + + if (!check_file(filename)) { + result = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("File incomplete. Continue anyway?"), false, false);////MSG_FILE_INCOMPLETE c=20 r=2 + lcd_update_enable(true); + } + if (result) { + enquecommand(cmd); + enquecommand_P(PSTR("M24")); + } + + lcd_return_to_status(); } void menu_action_sddirectory(const char* filename) { - uint8_t depth = (uint8_t)card.getWorkDirDepth(); + uint8_t depth = (uint8_t)card.getWorkDirDepth(); - strcpy(dir_names[depth], filename); - MYSERIAL.println(dir_names[depth]); - card.chdir(filename); - lcd_encoder = 0; + strcpy(dir_names[depth], filename); + MYSERIAL.println(dir_names[depth]); + card.chdir(filename); + lcd_encoder = 0; } /** LCD API **/ @@ -7233,29 +7338,29 @@ void ultralcd_init() else lcd_autoDeplete = autoDepleteRaw; } - lcd_init(); - lcd_refresh(); - lcd_longpress_func = menu_lcd_longpress_func; - lcd_charsetup_func = menu_lcd_charsetup_func; - lcd_lcdupdate_func = menu_lcd_lcdupdate_func; - menu_menu = lcd_status_screen; - menu_lcd_charsetup_func(); - - SET_INPUT(BTN_EN1); - SET_INPUT(BTN_EN2); - WRITE(BTN_EN1, HIGH); - WRITE(BTN_EN2, HIGH); + lcd_init(); + lcd_refresh(); + lcd_longpress_func = menu_lcd_longpress_func; + lcd_charsetup_func = menu_lcd_charsetup_func; + lcd_lcdupdate_func = menu_lcd_lcdupdate_func; + menu_menu = lcd_status_screen; + menu_lcd_charsetup_func(); + + SET_INPUT(BTN_EN1); + SET_INPUT(BTN_EN2); + WRITE(BTN_EN1, HIGH); + WRITE(BTN_EN2, HIGH); #if BTN_ENC > 0 - SET_INPUT(BTN_ENC); - WRITE(BTN_ENC, HIGH); + SET_INPUT(BTN_ENC); + WRITE(BTN_ENC, HIGH); #endif #if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) - pinMode(SDCARDDETECT, INPUT); - WRITE(SDCARDDETECT, HIGH); - lcd_oldcardstatus = IS_SD_INSERTED; + pinMode(SDCARDDETECT, INPUT); + WRITE(SDCARDDETECT, HIGH); + lcd_oldcardstatus = IS_SD_INSERTED; #endif//(SDCARDDETECT > 0) - lcd_encoder_diff = 0; + lcd_encoder_diff = 0; } @@ -7263,135 +7368,135 @@ void ultralcd_init() void lcd_printer_connected() { - printer_connected = true; + printer_connected = true; } static void lcd_send_status() { - if (farm_mode && no_response && ((millis() - NcTime) > (NC_TIME * 1000))) { - //send important status messages periodicaly - prusa_statistics(important_status, saved_filament_type); - NcTime = millis(); + if (farm_mode && no_response && ((millis() - NcTime) > (NC_TIME * 1000))) { + //send important status messages periodicaly + prusa_statistics(important_status, saved_filament_type); + NcTime = millis(); #ifdef FARM_CONNECT_MESSAGE - lcd_connect_printer(); + lcd_connect_printer(); #endif //FARM_CONNECT_MESSAGE - } + } } #ifdef FARM_CONNECT_MESSAGE static void lcd_connect_printer() { - lcd_update_enable(false); - lcd_clear(); - - int i = 0; - int t = 0; - lcd_set_custom_characters_progress(); - lcd_puts_at_P(0, 0, _i("Connect printer to")); - lcd_puts_at_P(0, 1, _i("monitoring or hold")); - lcd_puts_at_P(0, 2, _i("the knob to continue")); - while (no_response) { - i++; - t++; - delay_keep_alive(100); - proc_commands(); - if (t == 10) { - prusa_statistics(important_status, saved_filament_type); - t = 0; - } - if (READ(BTN_ENC)) { //if button is not pressed - i = 0; - lcd_puts_at_P(0, 3, PSTR(" ")); - } - if (i!=0) lcd_puts_at_P((i * 20) / (NC_BUTTON_LONG_PRESS * 10), 3, "\x01"); - if (i == NC_BUTTON_LONG_PRESS * 10) { - no_response = false; - } - } - lcd_set_custom_characters_degree(); - lcd_update_enable(true); - lcd_update(2); + lcd_update_enable(false); + lcd_clear(); + + int i = 0; + int t = 0; + lcd_set_custom_characters_progress(); + lcd_puts_at_P(0, 0, _i("Connect printer to")); + lcd_puts_at_P(0, 1, _i("monitoring or hold")); + lcd_puts_at_P(0, 2, _i("the knob to continue")); + while (no_response) { + i++; + t++; + delay_keep_alive(100); + proc_commands(); + if (t == 10) { + prusa_statistics(important_status, saved_filament_type); + t = 0; + } + if (READ(BTN_ENC)) { //if button is not pressed + i = 0; + lcd_puts_at_P(0, 3, PSTR(" ")); + } + if (i!=0) lcd_puts_at_P((i * 20) / (NC_BUTTON_LONG_PRESS * 10), 3, "\x01"); + if (i == NC_BUTTON_LONG_PRESS * 10) { + no_response = false; + } + } + lcd_set_custom_characters_degree(); + lcd_update_enable(true); + lcd_update(2); } #endif //FARM_CONNECT_MESSAGE void lcd_ping() { //chceck if printer is connected to monitoring when in farm mode - if (farm_mode) { - bool empty = is_buffer_empty(); - if ((millis() - PingTime) * 0.001 > (empty ? PING_TIME : PING_TIME_LONG)) { //if commands buffer is empty use shorter time period - //if there are comamnds in buffer, some long gcodes can delay execution of ping command - //therefore longer period is used - printer_connected = false; - } - else { - lcd_printer_connected(); - } - } + if (farm_mode) { + bool empty = is_buffer_empty(); + if ((millis() - PingTime) * 0.001 > (empty ? PING_TIME : PING_TIME_LONG)) { //if commands buffer is empty use shorter time period + //if there are comamnds in buffer, some long gcodes can delay execution of ping command + //therefore longer period is used + printer_connected = false; + } + else { + lcd_printer_connected(); + } + } } void lcd_ignore_click(bool b) { - ignore_click = b; - wait_for_unclick = false; + ignore_click = b; + wait_for_unclick = false; } void lcd_finishstatus() { - int len = strlen(lcd_status_message); - if (len > 0) { - while (len < LCD_WIDTH) { - lcd_status_message[len++] = ' '; + int len = strlen(lcd_status_message); + if (len > 0) { + while (len < LCD_WIDTH) { + lcd_status_message[len++] = ' '; + } } - } - lcd_status_message[LCD_WIDTH] = '\0'; - lcd_draw_update = 2; + lcd_status_message[LCD_WIDTH] = '\0'; + lcd_draw_update = 2; } void lcd_setstatus(const char* message) { - if (lcd_status_message_level > 0) - return; - strncpy(lcd_status_message, message, LCD_WIDTH); - lcd_finishstatus(); + if (lcd_status_message_level > 0) + return; + strncpy(lcd_status_message, message, LCD_WIDTH); + lcd_finishstatus(); } void lcd_setstatuspgm(const char* message) { - if (lcd_status_message_level > 0) - return; - strncpy_P(lcd_status_message, message, LCD_WIDTH); - lcd_status_message[LCD_WIDTH] = 0; - lcd_finishstatus(); + if (lcd_status_message_level > 0) + return; + strncpy_P(lcd_status_message, message, LCD_WIDTH); + lcd_status_message[LCD_WIDTH] = 0; + lcd_finishstatus(); } void lcd_setalertstatuspgm(const char* message) { - lcd_setstatuspgm(message); - lcd_status_message_level = 1; - lcd_return_to_status(); + lcd_setstatuspgm(message); + lcd_status_message_level = 1; + lcd_return_to_status(); } void lcd_reset_alert_level() { - lcd_status_message_level = 0; + lcd_status_message_level = 0; } uint8_t get_message_level() { - return lcd_status_message_level; + return lcd_status_message_level; } void menu_lcd_longpress_func(void) { - move_menu_scale = 1.0; - menu_submenu(lcd_move_z); + move_menu_scale = 1.0; + menu_submenu(lcd_move_z); } void menu_lcd_charsetup_func(void) { - if (menu_menu == lcd_status_screen) - lcd_set_custom_characters_degree(); - else - lcd_set_custom_characters_arrows(); + if (menu_menu == lcd_status_screen) + lcd_set_custom_characters_degree(); + else + lcd_set_custom_characters_arrows(); } static inline bool z_menu_expired() { return (menu_menu == lcd_babystep_z - && lcd_timeoutToStatus.expired(LCD_TIMEOUT_TO_STATUS_BABYSTEP_Z)); + && lcd_timeoutToStatus.expired(LCD_TIMEOUT_TO_STATUS_BABYSTEP_Z)); } static inline bool other_menu_expired() { @@ -7402,7 +7507,7 @@ static inline bool other_menu_expired() static inline bool forced_menu_expire() { bool retval = (menu_menu != lcd_status_screen - && forceMenuExpire); + && forceMenuExpire); forceMenuExpire = false; return retval; } @@ -7410,60 +7515,60 @@ static inline bool forced_menu_expire() void menu_lcd_lcdupdate_func(void) { #if (SDCARDDETECT > 0) - if ((IS_SD_INSERTED != lcd_oldcardstatus)) - { - lcd_draw_update = 2; - lcd_oldcardstatus = IS_SD_INSERTED; - lcd_refresh(); // to maybe revive the LCD if static electricity killed it. - if (lcd_oldcardstatus) - { - card.initsd(); - LCD_MESSAGERPGM(_i("Card inserted"));////MSG_SD_INSERTED c=0 r=0 - //get_description(); - } - else - { - card.release(); - LCD_MESSAGERPGM(_i("Card removed"));////MSG_SD_REMOVED c=0 r=0 - } - } + if ((IS_SD_INSERTED != lcd_oldcardstatus)) + { + lcd_draw_update = 2; + lcd_oldcardstatus = IS_SD_INSERTED; + lcd_refresh(); // to maybe revive the LCD if static electricity killed it. + if (lcd_oldcardstatus) + { + card.initsd(); + LCD_MESSAGERPGM(_i("Card inserted"));////MSG_SD_INSERTED c=0 r=0 + //get_description(); + } + else + { + card.release(); + LCD_MESSAGERPGM(_i("Card removed"));////MSG_SD_REMOVED c=0 r=0 + } + } #endif//CARDINSERTED - if (lcd_next_update_millis < millis()) - { - if (abs(lcd_encoder_diff) >= ENCODER_PULSES_PER_STEP) - { - if (lcd_draw_update == 0) - lcd_draw_update = 1; - lcd_encoder += lcd_encoder_diff / ENCODER_PULSES_PER_STEP; - lcd_encoder_diff = 0; - lcd_timeoutToStatus.start(); - } + if (lcd_next_update_millis < millis()) + { + if (abs(lcd_encoder_diff) >= ENCODER_PULSES_PER_STEP) + { + if (lcd_draw_update == 0) + lcd_draw_update = 1; + lcd_encoder += lcd_encoder_diff / ENCODER_PULSES_PER_STEP; + lcd_encoder_diff = 0; + lcd_timeoutToStatus.start(); + } - if (LCD_CLICKED) lcd_timeoutToStatus.start(); + if (LCD_CLICKED) lcd_timeoutToStatus.start(); - (*menu_menu)(); + (*menu_menu)(); - if (z_menu_expired() || other_menu_expired() || forced_menu_expire()) - { - // Exiting a menu. Let's call the menu function the last time with menu_leaving flag set to true - // to give it a chance to save its state. - // This is useful for example, when the babystep value has to be written into EEPROM. - if (menu_menu != NULL) - { - menu_leaving = 1; - (*menu_menu)(); - menu_leaving = 0; - } - lcd_clear(); - lcd_return_to_status(); - lcd_draw_update = 2; - } - if (lcd_draw_update == 2) lcd_clear(); - if (lcd_draw_update) lcd_draw_update--; - lcd_next_update_millis = millis() + LCD_UPDATE_INTERVAL; - } - if (!SdFatUtil::test_stack_integrity()) stack_error(); - lcd_ping(); //check that we have received ping command if we are in farm mode - lcd_send_status(); - if (lcd_commands_type == LCD_COMMAND_V2_CAL) lcd_commands(); + if (z_menu_expired() || other_menu_expired() || forced_menu_expire()) + { + // Exiting a menu. Let's call the menu function the last time with menu_leaving flag set to true + // to give it a chance to save its state. + // This is useful for example, when the babystep value has to be written into EEPROM. + if (menu_menu != NULL) + { + menu_leaving = 1; + (*menu_menu)(); + menu_leaving = 0; + } + lcd_clear(); + lcd_return_to_status(); + lcd_draw_update = 2; + } + if (lcd_draw_update == 2) lcd_clear(); + if (lcd_draw_update) lcd_draw_update--; + lcd_next_update_millis = millis() + LCD_UPDATE_INTERVAL; + } + if (!SdFatUtil::test_stack_integrity()) stack_error(); + lcd_ping(); //check that we have received ping command if we are in farm mode + lcd_send_status(); + if (lcd_commands_type == LCD_COMMAND_V2_CAL) lcd_commands(); } diff --git a/Firmware/ultralcd.h b/Firmware/ultralcd.h index 44bbf390f5..2d11112264 100755 --- a/Firmware/ultralcd.h +++ b/Firmware/ultralcd.h @@ -43,7 +43,7 @@ void lcd_load_filament_color_check(); extern bool lcd_selftest(); -void lcd_menu_statistics(); +void lcd_menu_statistics(); extern const char* lcd_display_message_fullscreen_P(const char *msg, uint8_t &nlines); extern const char* lcd_display_message_fullscreen_P(const char *msg); @@ -65,7 +65,7 @@ extern bool lcd_calibrate_z_end_stop_manual(bool only_z); #endif // Show the result of the calibration process on the LCD screen. - extern void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask); +extern void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask); extern void lcd_diag_show_end_stops(); @@ -82,7 +82,7 @@ extern void lcd_diag_show_end_stops(); #define LCD_COMMAND_STOP_PRINT 2 #define LCD_COMMAND_FARM_MODE_CONFIRM 4 #define LCD_COMMAND_LONG_PAUSE 5 -#define LCD_COMMAND_PID_EXTRUDER 7 +#define LCD_COMMAND_PID_EXTRUDER 7 #define LCD_COMMAND_V2_CAL 8 extern int lcd_commands_type; @@ -128,7 +128,7 @@ void change_extr(int extr); void extr_adj(int extruder); #ifdef SNMM -void extr_unload_all(); +void extr_unload_all(); void extr_unload_used(); #endif //SNMM void extr_unload(); diff --git a/Firmware/uni_avr_rpi.h b/Firmware/uni_avr_rpi.h index 616a5662b8..f0bc4310ee 100755 --- a/Firmware/uni_avr_rpi.h +++ b/Firmware/uni_avr_rpi.h @@ -1,31 +1,37 @@ // unification for AVR and RPI #ifdef __AVR - //#include "Arduino.h" - #include "Marlin.h" - #define GPIO_INP(gpio) pinMode(gpio, INPUT) - #define GPIO_OUT(gpio) pinMode(gpio, OUTPUT) - #define GPIO_SET(gpio) digitalWrite(gpio, HIGH) - #define GPIO_CLR(gpio) digitalWrite(gpio, LOW) - #define GPIO_GET(gpio) (digitalRead(gpio) != LOW) - #define DELAY(delay) delayMicroseconds(delay) - #define PRINT MYSERIAL.print +//#include "Arduino.h" +#include "Marlin.h" +#define GPIO_INP(gpio) pinMode(gpio, INPUT) +#define GPIO_OUT(gpio) pinMode(gpio, OUTPUT) +#define GPIO_SET(gpio) digitalWrite(gpio, HIGH) +#define GPIO_CLR(gpio) digitalWrite(gpio, LOW) +#define GPIO_GET(gpio) (digitalRead(gpio) != LOW) +#define DELAY(delay) delayMicroseconds(delay) +#define PRINT MYSERIAL.print #endif //RC522_AVR #ifdef __RPI - #include - #define GPIO_INP(gpio) bcm2835_gpio_fsel(gpio, BCM2835_GPIO_FSEL_INPT) - #define GPIO_OUT(gpio) bcm2835_gpio_fsel(gpio, BCM2835_GPIO_FSEL_OUTP) - #define GPIO_SET(gpio) bcm2835_gpio_write(gpio, HIGH) - #define GPIO_CLR(gpio) bcm2835_gpio_write(gpio, LOW) - #define GPIO_GET(gpio) (bcm2835_gpio_lev(gpio) != LOW) - #include - #define DELAY(delay) usleep(delay) - #define PRINT(p) print(p) - #define DEC 10 - #define HEX 16 - void print(const char* pc) { printf("%s", pc); } - void print(int v) { printf("%d", v); } - void print(float v) { printf("%f", v); } +#include +#define GPIO_INP(gpio) bcm2835_gpio_fsel(gpio, BCM2835_GPIO_FSEL_INPT) +#define GPIO_OUT(gpio) bcm2835_gpio_fsel(gpio, BCM2835_GPIO_FSEL_OUTP) +#define GPIO_SET(gpio) bcm2835_gpio_write(gpio, HIGH) +#define GPIO_CLR(gpio) bcm2835_gpio_write(gpio, LOW) +#define GPIO_GET(gpio) (bcm2835_gpio_lev(gpio) != LOW) +#include +#define DELAY(delay) usleep(delay) +#define PRINT(p) print(p) +#define DEC 10 +#define HEX 16 +void print(const char* pc) { + printf("%s", pc); +} +void print(int v) { + printf("%d", v); +} +void print(float v) { + printf("%f", v); +} #endif //RC522_RPI diff --git a/Firmware/util.cpp b/Firmware/util.cpp index 15f3f4c5f8..7054d10953 100755 --- a/Firmware/util.cpp +++ b/Firmware/util.cpp @@ -43,7 +43,7 @@ inline bool is_digit(char c) // Parse a major.minor.revision version number. // Return true if valid. inline bool parse_version(const char *str, uint16_t version[4]) -{ +{ #if 0 SERIAL_ECHOPGM("Parsing version string "); SERIAL_ECHO(str); @@ -117,22 +117,22 @@ inline bool parse_version(const char *str, uint16_t version[4]) inline bool strncmp_PP(const char *p1, const char *p2, uint8_t n) { for (; n > 0; -- n, ++ p1, ++ p2) { - if (pgm_read_byte(p1) >= 65 && pgm_read_byte(p1) <= 92) //p1 is upper case (p2 is always lowercase) - { - if ((pgm_read_byte(p1)+32) < pgm_read_byte(p2)) - return -1; - if ((pgm_read_byte(p1)+32) > pgm_read_byte(p2)) - return 1; - } - else if (pgm_read_byte(p1) == 0) { - return 0; - } - else { //p1 is lowercase - if (pgm_read_byte(p1) < pgm_read_byte(p2)) - return -1; - if (pgm_read_byte(p1) > pgm_read_byte(p2)) - return 1; - } + if (pgm_read_byte(p1) >= 65 && pgm_read_byte(p1) <= 92) //p1 is upper case (p2 is always lowercase) + { + if ((pgm_read_byte(p1)+32) < pgm_read_byte(p2)) + return -1; + if ((pgm_read_byte(p1)+32) > pgm_read_byte(p2)) + return 1; + } + else if (pgm_read_byte(p1) == 0) { + return 0; + } + else { //p1 is lowercase + if (pgm_read_byte(p1) < pgm_read_byte(p2)) + return -1; + if (pgm_read_byte(p1) > pgm_read_byte(p2)) + return 1; + } } return 0; } @@ -140,7 +140,7 @@ inline bool strncmp_PP(const char *p1, const char *p2, uint8_t n) // Parse a major.minor.revision version number. // Return true if valid. inline bool parse_version_P(const char *str, uint16_t version[4]) -{ +{ #if 0 SERIAL_ECHOPGM("Parsing version string "); SERIAL_ECHORPGM(str); @@ -165,7 +165,8 @@ inline bool parse_version_P(const char *str, uint16_t version[4]) uint8_t n = minor - major - 1; if (n > 4) return false; - memcpy_P(buf, major, n); buf[n] = 0; + memcpy_P(buf, major, n); + buf[n] = 0; char *endptr = NULL; version[0] = strtol(buf, &endptr, 10); if (*endptr != 0) @@ -173,7 +174,8 @@ inline bool parse_version_P(const char *str, uint16_t version[4]) n = rev - minor - 1; if (n > 4) return false; - memcpy_P(buf, minor, n); buf[n] = 0; + memcpy_P(buf, minor, n); + buf[n] = 0; version[1] = strtol(buf, &endptr, 10); if (*endptr != 0) return false; @@ -242,30 +244,30 @@ inline int8_t is_provided_version_newer(const char *version_string) bool force_selftest_if_fw_version() { - //if fw version used before flashing new firmware (fw version currently stored in eeprom) is lower then 3.1.2-RC2, function returns true to force selftest + //if fw version used before flashing new firmware (fw version currently stored in eeprom) is lower then 3.1.2-RC2, function returns true to force selftest - uint16_t ver_eeprom[4]; - uint16_t ver_with_calibration[4] = {3, 1, 2, 4}; //hardcoded 3.1.2-RC2 version - bool force_selftest = false; + uint16_t ver_eeprom[4]; + uint16_t ver_with_calibration[4] = {3, 1, 2, 4}; //hardcoded 3.1.2-RC2 version + bool force_selftest = false; - ver_eeprom[0] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MAJOR); - ver_eeprom[1] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MINOR); - ver_eeprom[2] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_REVISION); - ver_eeprom[3] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_FLAVOR); + ver_eeprom[0] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MAJOR); + ver_eeprom[1] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_MINOR); + ver_eeprom[2] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_REVISION); + ver_eeprom[3] = eeprom_read_word((uint16_t*)EEPROM_FIRMWARE_VERSION_FLAVOR); + + for (uint8_t i = 0; i < 4; ++i) { + if (ver_with_calibration[i] > ver_eeprom[i]) { + force_selftest = true; + break; + } + else if (ver_with_calibration[i] < ver_eeprom[i]) + break; + } - for (uint8_t i = 0; i < 4; ++i) { - if (ver_with_calibration[i] > ver_eeprom[i]) { - force_selftest = true; - break; - } - else if (ver_with_calibration[i] < ver_eeprom[i]) - break; - } + //force selftest also in case that version used before flashing new firmware was 3.2.0-RC1 + if ((ver_eeprom[0] == 3) && (ver_eeprom[1] == 2) && (ver_eeprom[2] == 0) && (ver_eeprom[3] == 3)) force_selftest = true; - //force selftest also in case that version used before flashing new firmware was 3.2.0-RC1 - if ((ver_eeprom[0] == 3) && (ver_eeprom[1] == 2) && (ver_eeprom[2] == 0) && (ver_eeprom[3] == 3)) force_selftest = true; - - return force_selftest; + return force_selftest; } bool show_upgrade_dialog_if_version_newer(const char *version_string) @@ -295,13 +297,13 @@ bool show_upgrade_dialog_if_version_newer(const char *version_string) for (const char *c = version_string; ! is_whitespace_or_nl_or_eol(*c); ++ c) lcd_putc(*c); lcd_puts_at_P(0, 3, _i("Please upgrade."));////MSG_NEW_FIRMWARE_PLEASE_UPGRADE c=20 r=0 -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - tone(BEEPER, 1000); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + tone(BEEPER, 1000); delay_keep_alive(50); noTone(BEEPER); delay_keep_alive(500); -if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) - tone(BEEPER, 1000); + if((eSoundMode==e_SOUND_MODE_LOUD)||(eSoundMode==e_SOUND_MODE_ONCE)) + tone(BEEPER, 1000); delay_keep_alive(50); noTone(BEEPER); lcd_wait_for_click(); diff --git a/Firmware/util.h b/Firmware/util.h index 7cbcb027b6..c035ff9f4d 100755 --- a/Firmware/util.h +++ b/Firmware/util.h @@ -25,12 +25,12 @@ extern void update_current_firmware_version_to_eeprom(); inline int8_t eeprom_read_int8(unsigned char* addr) { - uint8_t v = eeprom_read_byte(addr); - return *reinterpret_cast(&v); + uint8_t v = eeprom_read_byte(addr); + return *reinterpret_cast(&v); } inline void eeprom_update_int8(unsigned char* addr, int8_t v) { - eeprom_update_byte(addr, *reinterpret_cast(&v)); + eeprom_update_byte(addr, *reinterpret_cast(&v)); } #endif /* UTIL_H */ diff --git a/Firmware/vector_3.cpp b/Firmware/vector_3.cpp index 5f1c294ed5..990823c977 100755 --- a/Firmware/vector_3.cpp +++ b/Firmware/vector_3.cpp @@ -28,93 +28,105 @@ 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) { - 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); + 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) +vector_3 vector_3::operator+(vector_3 v) { - return vector_3((x + v.x), (y + v.y), (z + v.z)); + return vector_3((x + v.x), (y + v.y), (z + v.z)); } -vector_3 vector_3::operator-(vector_3 v) +vector_3 vector_3::operator-(vector_3 v) { - return vector_3((x - v.x), (y - v.y), (z - v.z)); + return vector_3((x - v.x), (y - v.y), (z - v.z)); } -vector_3 vector_3::get_normal() +vector_3 vector_3::get_normal() { - vector_3 normalized = vector_3(x, y, z); - normalized.normalize(); - return normalized; + vector_3 normalized = vector_3(x, y, z); + normalized.normalize(); + return normalized; } -float vector_3::get_length() +float vector_3::get_length() { - float length = sqrt((x * x) + (y * y) + (z * z)); - return 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; + 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]; + 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; + 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"); + 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; + 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; + //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[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) @@ -123,44 +135,50 @@ matrix_3x3 matrix_3x3::create_look_at(vector_3 target) vector_3 x_row = vector_3(1, 0, -target.x/target.z).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"); + // x_row.debug("x_row"); + // y_row.debug("y_row"); + // z_row.debug("z_row"); + - - // create the matrix already correctly transposed + // create the matrix already correctly transposed matrix_3x3 rot = matrix_3x3::create_from_rows(x_row, y_row, z_row); - // rot.debug("rot"); +// rot.debug("rot"); return rot; } 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; + 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) { - 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"); - } + 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/Firmware/vector_3.h b/Firmware/vector_3.h index 0b9decafad..a63e57dfd6 100755 --- a/Firmware/vector_3.h +++ b/Firmware/vector_3.h @@ -24,35 +24,35 @@ class matrix_3x3; struct vector_3 { - float x, y, z; + float x, y, z; - vector_3(); - vector_3(float x, float y, float z); + vector_3(); + vector_3(float x, float y, float z); - static vector_3 cross(vector_3 a, vector_3 b); + 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(); + 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); + void debug(char* title); + + void apply_rotation(matrix_3x3 matrix); }; struct matrix_3x3 { - float matrix[9]; + 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); - static matrix_3x3 transpose(matrix_3x3 original); + 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); + static matrix_3x3 transpose(matrix_3x3 original); - void set_to_identity(); + void set_to_identity(); - void debug(char* title); + void debug(char* title); }; diff --git a/Firmware/w25x20cl.c b/Firmware/w25x20cl.c index 79467cb6dc..25e6852376 100755 --- a/Firmware/w25x20cl.c +++ b/Firmware/w25x20cl.c @@ -45,140 +45,140 @@ int w25x20cl_mfrid_devid(void); int8_t w25x20cl_init(void) { - PIN_OUT(W25X20CL_PIN_CS); - _CS_HIGH(); - W25X20CL_SPI_ENTER(); - if (!w25x20cl_mfrid_devid()) return 0; - return 1; + PIN_OUT(W25X20CL_PIN_CS); + _CS_HIGH(); + W25X20CL_SPI_ENTER(); + if (!w25x20cl_mfrid_devid()) return 0; + return 1; } void w25x20cl_enable_wr(void) { - _CS_LOW(); - _SPI_TX(_CMD_ENABLE_WR); // send command 0x06 - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_ENABLE_WR); // send command 0x06 + _CS_HIGH(); } void w25x20cl_disable_wr(void) { - _CS_LOW(); - _SPI_TX(_CMD_DISABLE_WR); // send command 0x04 - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_DISABLE_WR); // send command 0x04 + _CS_HIGH(); } uint8_t w25x20cl_rd_status_reg(void) { - _CS_LOW(); - _SPI_TX(_CMD_RD_STATUS_REG); // send command 0x90 - uint8_t val = _SPI_RX(); // receive value - _CS_HIGH(); - return val; + _CS_LOW(); + _SPI_TX(_CMD_RD_STATUS_REG); // send command 0x90 + uint8_t val = _SPI_RX(); // receive value + _CS_HIGH(); + return val; } void w25x20cl_wr_status_reg(uint8_t val) { - _CS_LOW(); - _SPI_TX(_CMD_WR_STATUS_REG); // send command 0x90 - _SPI_TX(val); // send value - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_WR_STATUS_REG); // send command 0x90 + _SPI_TX(val); // send value + _CS_HIGH(); } void w25x20cl_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt) { - _CS_LOW(); - _SPI_TX(_CMD_RD_DATA); // send command 0x03 - _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 - _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 - _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 - while (cnt--) // receive data - *(data++) = _SPI_RX(); - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_RD_DATA); // send command 0x03 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + while (cnt--) // receive data + *(data++) = _SPI_RX(); + _CS_HIGH(); } void w25x20cl_page_program(uint32_t addr, uint8_t* data, uint16_t cnt) { - _CS_LOW(); - _SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02 - _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 - _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 - _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 - while (cnt--) // send data - _SPI_TX(*(data++)); - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + while (cnt--) // send data + _SPI_TX(*(data++)); + _CS_HIGH(); } void w25x20cl_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt) { - _CS_LOW(); - _SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02 - _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 - _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 - _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 - while (cnt--) // send data - _SPI_TX(pgm_read_byte(data++)); - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + while (cnt--) // send data + _SPI_TX(pgm_read_byte(data++)); + _CS_HIGH(); } void w25x20cl_erase(uint8_t cmd, uint32_t addr) { - _CS_LOW(); - _SPI_TX(cmd); // send command 0x20 - _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 - _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 - _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(cmd); // send command 0x20 + _SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23 + _SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15 + _SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7 + _CS_HIGH(); } void w25x20cl_sector_erase(uint32_t addr) { - return w25x20cl_erase(_CMD_SECTOR_ERASE, addr); + return w25x20cl_erase(_CMD_SECTOR_ERASE, addr); } void w25x20cl_block32_erase(uint32_t addr) { - return w25x20cl_erase(_CMD_BLOCK32_ERASE, addr); + return w25x20cl_erase(_CMD_BLOCK32_ERASE, addr); } void w25x20cl_block64_erase(uint32_t addr) { - return w25x20cl_erase(_CMD_BLOCK64_ERASE, addr); + return w25x20cl_erase(_CMD_BLOCK64_ERASE, addr); } void w25x20cl_chip_erase(void) { - _CS_LOW(); - _SPI_TX(_CMD_CHIP_ERASE); // send command 0xc7 - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_CHIP_ERASE); // send command 0xc7 + _CS_HIGH(); } void w25x20cl_rd_uid(uint8_t* uid) { - _CS_LOW(); - _SPI_TX(_CMD_RD_UID); // send command 0x4b - uint8_t cnt = 4; // 4 dummy bytes - while (cnt--) // receive dummy bytes - _SPI_RX(); - cnt = 8; // 8 bytes UID - while (cnt--) // receive UID - uid[7 - cnt] = _SPI_RX(); - _CS_HIGH(); + _CS_LOW(); + _SPI_TX(_CMD_RD_UID); // send command 0x4b + uint8_t cnt = 4; // 4 dummy bytes + while (cnt--) // receive dummy bytes + _SPI_RX(); + cnt = 8; // 8 bytes UID + while (cnt--) // receive UID + uid[7 - cnt] = _SPI_RX(); + _CS_HIGH(); } int w25x20cl_mfrid_devid(void) { - _CS_LOW(); - _SPI_TX(_CMD_MFRID_DEVID); // send command 0x90 - uint8_t cnt = 3; // 3 address bytes - while (cnt--) // send address bytes - _SPI_TX(0x00); - uint8_t w25x20cl_mfrid = _SPI_RX(); // receive mfrid - uint8_t w25x20cl_devid = _SPI_RX(); // receive devid - _CS_HIGH(); - return ((w25x20cl_mfrid == _MFRID) && (w25x20cl_devid == _DEVID)); + _CS_LOW(); + _SPI_TX(_CMD_MFRID_DEVID); // send command 0x90 + uint8_t cnt = 3; // 3 address bytes + while (cnt--) // send address bytes + _SPI_TX(0x00); + uint8_t w25x20cl_mfrid = _SPI_RX(); // receive mfrid + uint8_t w25x20cl_devid = _SPI_RX(); // receive devid + _CS_HIGH(); + return ((w25x20cl_mfrid == _MFRID) && (w25x20cl_devid == _DEVID)); } void w25x20cl_wait_busy(void) { - while (w25x20cl_rd_status_reg() & W25X20CL_STATUS_BUSY) ; + while (w25x20cl_rd_status_reg() & W25X20CL_STATUS_BUSY) ; } diff --git a/Firmware/xyzcal.cpp b/Firmware/xyzcal.cpp index 3b9c0a4fa2..f4a200d962 100755 --- a/Firmware/xyzcal.cpp +++ b/Firmware/xyzcal.cpp @@ -40,47 +40,47 @@ uint16_t xyzcal_calc_delay(uint16_t nd, uint16_t dd); void xyzcal_meassure_enter(void) { - DBG(_n("xyzcal_meassure_enter\n")); - disable_heater(); - DISABLE_TEMPERATURE_INTERRUPT(); + DBG(_n("xyzcal_meassure_enter\n")); + disable_heater(); + DISABLE_TEMPERATURE_INTERRUPT(); #if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1)) - DISABLE_FANCHECK_INTERRUPT(); + DISABLE_FANCHECK_INTERRUPT(); #endif //(defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1)) - DISABLE_STEPPER_DRIVER_INTERRUPT(); + DISABLE_STEPPER_DRIVER_INTERRUPT(); #ifdef WATCHDOG - wdt_disable(); + wdt_disable(); #endif //WATCHDOG - sm4_stop_cb = 0; - sm4_update_pos_cb = xyzcal_update_pos; - sm4_calc_delay_cb = xyzcal_calc_delay; + sm4_stop_cb = 0; + sm4_update_pos_cb = xyzcal_update_pos; + sm4_calc_delay_cb = xyzcal_calc_delay; } void xyzcal_meassure_leave(void) { - DBG(_n("xyzcal_meassure_leave\n")); + DBG(_n("xyzcal_meassure_leave\n")); planner_abort_hard(); - ENABLE_TEMPERATURE_INTERRUPT(); + ENABLE_TEMPERATURE_INTERRUPT(); #if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1)) - ENABLE_FANCHECK_INTERRUPT(); + ENABLE_FANCHECK_INTERRUPT(); #endif //(defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1)) - ENABLE_STEPPER_DRIVER_INTERRUPT(); + ENABLE_STEPPER_DRIVER_INTERRUPT(); #ifdef WATCHDOG - wdt_enable(WDTO_4S); + wdt_enable(WDTO_4S); #endif //WATCHDOG - sm4_stop_cb = 0; - sm4_update_pos_cb = 0; - sm4_calc_delay_cb = 0; + sm4_stop_cb = 0; + sm4_update_pos_cb = 0; + sm4_calc_delay_cb = 0; } uint8_t check_pinda_0() { - return _PINDA?0:1; + return _PINDA?0:1; } uint8_t check_pinda_1() { - return _PINDA?1:0; + return _PINDA?1:0; } uint8_t xyzcal_dm = 0; @@ -88,9 +88,12 @@ uint8_t xyzcal_dm = 0; void xyzcal_update_pos(uint16_t dx, uint16_t dy, uint16_t dz, uint16_t) { // DBG(_n("xyzcal_update_pos dx=%d dy=%d dz=%d dir=%02x\n"), dx, dy, dz, xyzcal_dm); - if (xyzcal_dm&1) count_position[0] -= dx; else count_position[0] += dx; - if (xyzcal_dm&2) count_position[1] -= dy; else count_position[1] += dy; - if (xyzcal_dm&4) count_position[2] -= dz; else count_position[2] += dz; + if (xyzcal_dm&1) count_position[0] -= dx; + else count_position[0] += dx; + if (xyzcal_dm&2) count_position[1] -= dy; + else count_position[1] += dy; + if (xyzcal_dm&4) count_position[2] -= dz; + else count_position[2] += dz; // DBG(_n(" after xyzcal_update_pos x=%ld y=%ld z=%ld\n"), count_position[0], count_position[1], count_position[2]); } @@ -109,31 +112,31 @@ uint16_t xyzcal_sm4_ac2 = (uint32_t)xyzcal_sm4_ac * 1024 / 10000; #ifdef SM4_ACCEL_TEST uint16_t xyzcal_calc_delay(uint16_t nd, uint16_t dd) { - uint16_t del_us = 0; - if (xyzcal_sm4_v & 0xf000) //>=4096 - { - del_us = (uint16_t)62500 / (uint16_t)(xyzcal_sm4_v >> 4); - xyzcal_sm4_v += (xyzcal_sm4_ac2 * del_us + 512) >> 10; - if (xyzcal_sm4_v > xyzcal_sm4_vm) xyzcal_sm4_v = xyzcal_sm4_vm; - if (del_us > 25) return del_us - 25; - } - else - { - del_us = (uint32_t)1000000 / xyzcal_sm4_v; - xyzcal_sm4_v += ((uint32_t)xyzcal_sm4_ac2 * del_us + 512) >> 10; - if (xyzcal_sm4_v > xyzcal_sm4_vm) xyzcal_sm4_v = xyzcal_sm4_vm; - if (del_us > 50) return del_us - 50; - } - -// uint16_t del_us = (uint16_t)(((float)1000000 / xyzcal_sm4_v) + 0.5); -// uint16_t del_us = (uint32_t)1000000 / xyzcal_sm4_v; -// uint16_t del_us = 100; + uint16_t del_us = 0; + if (xyzcal_sm4_v & 0xf000) //>=4096 + { + del_us = (uint16_t)62500 / (uint16_t)(xyzcal_sm4_v >> 4); + xyzcal_sm4_v += (xyzcal_sm4_ac2 * del_us + 512) >> 10; + if (xyzcal_sm4_v > xyzcal_sm4_vm) xyzcal_sm4_v = xyzcal_sm4_vm; + if (del_us > 25) return del_us - 25; + } + else + { + del_us = (uint32_t)1000000 / xyzcal_sm4_v; + xyzcal_sm4_v += ((uint32_t)xyzcal_sm4_ac2 * del_us + 512) >> 10; + if (xyzcal_sm4_v > xyzcal_sm4_vm) xyzcal_sm4_v = xyzcal_sm4_vm; + if (del_us > 50) return del_us - 50; + } + +// uint16_t del_us = (uint16_t)(((float)1000000 / xyzcal_sm4_v) + 0.5); +// uint16_t del_us = (uint32_t)1000000 / xyzcal_sm4_v; +// uint16_t del_us = 100; // uint16_t del_us = (uint16_t)10000 / xyzcal_sm4_v; // v += (ac * del_us + 500) / 1000; // xyzcal_sm4_v += (xyzcal_sm4_ac * del_us) / 1000; // return xyzcal_sm4_delay; // DBG(_n("xyzcal_calc_delay nd=%d dd=%d v=%d del_us=%d\n"), nd, dd, xyzcal_sm4_v, del_us); - return 0; + return 0; } #else //SM4_ACCEL_TEST uint16_t xyzcal_calc_delay(uint16_t, uint16_t) @@ -145,165 +148,165 @@ uint16_t xyzcal_calc_delay(uint16_t, uint16_t) bool xyzcal_lineXYZ_to(int16_t x, int16_t y, int16_t z, uint16_t delay_us, int8_t check_pinda) { // DBG(_n("xyzcal_lineXYZ_to x=%d y=%d z=%d check=%d\n"), x, y, z, check_pinda); - x -= (int16_t)count_position[0]; - y -= (int16_t)count_position[1]; - z -= (int16_t)count_position[2]; - xyzcal_dm = ((x<0)?1:0) | ((y<0)?2:0) | ((z<0)?4:0); - sm4_set_dir_bits(xyzcal_dm); - sm4_stop_cb = check_pinda?((check_pinda<0)?check_pinda_0:check_pinda_1):0; - xyzcal_sm4_delay = delay_us; + x -= (int16_t)count_position[0]; + y -= (int16_t)count_position[1]; + z -= (int16_t)count_position[2]; + xyzcal_dm = ((x<0)?1:0) | ((y<0)?2:0) | ((z<0)?4:0); + sm4_set_dir_bits(xyzcal_dm); + sm4_stop_cb = check_pinda?((check_pinda<0)?check_pinda_0:check_pinda_1):0; + xyzcal_sm4_delay = delay_us; // uint32_t u = micros(); - bool ret = sm4_line_xyze_ui(abs(x), abs(y), abs(z), 0)?true:false; + bool ret = sm4_line_xyze_ui(abs(x), abs(y), abs(z), 0)?true:false; // u = micros() - u; - return ret; + return ret; } bool xyzcal_spiral2(int16_t cx, int16_t cy, int16_t z0, int16_t dz, int16_t radius, int16_t rotation, uint16_t delay_us, int8_t check_pinda, uint16_t* pad) { - bool ret = false; - float r = 0; //radius - uint8_t n = 0; //point number - uint16_t ad = 0; //angle [deg] - float ar; //angle [rad] - uint8_t dad = 0; //delta angle [deg] - uint8_t dad_min = 4; //delta angle min [deg] - uint8_t dad_max = 16; //delta angle max [deg] - uint8_t k = 720 / (dad_max - dad_min); //delta calculation constant - ad = 0; - if (pad) ad = *pad % 720; - DBG(_n("xyzcal_spiral2 cx=%d cy=%d z0=%d dz=%d radius=%d ad=%d\n"), cx, cy, z0, dz, radius, ad); - for (; ad < 720; ad++) - { - if (radius > 0) - { - dad = dad_max - (ad / k); - r = (float)(((uint32_t)ad) * radius) / 720; - } - else - { - dad = dad_max - ((719 - ad) / k); - r = (float)(((uint32_t)(719 - ad)) * (-radius)) / 720; - } - ar = (ad + rotation)* (float)_PI / 180; - float _cos = cos(ar); - float _sin = sin(ar); - int x = (int)(cx + (_cos * r)); - int y = (int)(cy + (_sin * r)); - int z = (int)(z0 - ((float)((int32_t)dz * ad) / 720)); - if (xyzcal_lineXYZ_to(x, y, z, delay_us, check_pinda)) - { - ad += dad + 1; - ret = true; - break; - } - n++; - ad += dad; - } - if (pad) *pad = ad; - return ret; + bool ret = false; + float r = 0; //radius + uint8_t n = 0; //point number + uint16_t ad = 0; //angle [deg] + float ar; //angle [rad] + uint8_t dad = 0; //delta angle [deg] + uint8_t dad_min = 4; //delta angle min [deg] + uint8_t dad_max = 16; //delta angle max [deg] + uint8_t k = 720 / (dad_max - dad_min); //delta calculation constant + ad = 0; + if (pad) ad = *pad % 720; + DBG(_n("xyzcal_spiral2 cx=%d cy=%d z0=%d dz=%d radius=%d ad=%d\n"), cx, cy, z0, dz, radius, ad); + for (; ad < 720; ad++) + { + if (radius > 0) + { + dad = dad_max - (ad / k); + r = (float)(((uint32_t)ad) * radius) / 720; + } + else + { + dad = dad_max - ((719 - ad) / k); + r = (float)(((uint32_t)(719 - ad)) * (-radius)) / 720; + } + ar = (ad + rotation)* (float)_PI / 180; + float _cos = cos(ar); + float _sin = sin(ar); + int x = (int)(cx + (_cos * r)); + int y = (int)(cy + (_sin * r)); + int z = (int)(z0 - ((float)((int32_t)dz * ad) / 720)); + if (xyzcal_lineXYZ_to(x, y, z, delay_us, check_pinda)) + { + ad += dad + 1; + ret = true; + break; + } + n++; + ad += dad; + } + if (pad) *pad = ad; + return ret; } bool xyzcal_spiral8(int16_t cx, int16_t cy, int16_t z0, int16_t dz, int16_t radius, uint16_t delay_us, int8_t check_pinda, uint16_t* pad) { - bool ret = false; - uint16_t ad = 0; - if (pad) ad = *pad; - DBG(_n("xyzcal_spiral8 cx=%d cy=%d z0=%d dz=%d radius=%d ad=%d\n"), cx, cy, z0, dz, radius, ad); - if (!ret && (ad < 720)) - if ((ret = xyzcal_spiral2(cx, cy, z0 - 0*dz, dz, radius, 0, delay_us, check_pinda, &ad)) != 0) - ad += 0; - if (!ret && (ad < 1440)) - if ((ret = xyzcal_spiral2(cx, cy, z0 - 1*dz, dz, -radius, 0, delay_us, check_pinda, &ad)) != 0) - ad += 720; - if (!ret && (ad < 2160)) - if ((ret = xyzcal_spiral2(cx, cy, z0 - 2*dz, dz, radius, 180, delay_us, check_pinda, &ad)) != 0) - ad += 1440; - if (!ret && (ad < 2880)) - if ((ret = xyzcal_spiral2(cx, cy, z0 - 3*dz, dz, -radius, 180, delay_us, check_pinda, &ad)) != 0) - ad += 2160; - if (pad) *pad = ad; - return ret; + bool ret = false; + uint16_t ad = 0; + if (pad) ad = *pad; + DBG(_n("xyzcal_spiral8 cx=%d cy=%d z0=%d dz=%d radius=%d ad=%d\n"), cx, cy, z0, dz, radius, ad); + if (!ret && (ad < 720)) + if ((ret = xyzcal_spiral2(cx, cy, z0 - 0*dz, dz, radius, 0, delay_us, check_pinda, &ad)) != 0) + ad += 0; + if (!ret && (ad < 1440)) + if ((ret = xyzcal_spiral2(cx, cy, z0 - 1*dz, dz, -radius, 0, delay_us, check_pinda, &ad)) != 0) + ad += 720; + if (!ret && (ad < 2160)) + if ((ret = xyzcal_spiral2(cx, cy, z0 - 2*dz, dz, radius, 180, delay_us, check_pinda, &ad)) != 0) + ad += 1440; + if (!ret && (ad < 2880)) + if ((ret = xyzcal_spiral2(cx, cy, z0 - 3*dz, dz, -radius, 180, delay_us, check_pinda, &ad)) != 0) + ad += 2160; + if (pad) *pad = ad; + return ret; } #ifdef XYZCAL_MEASSURE_PINDA_HYSTEREZIS int8_t xyzcal_meassure_pinda_hysterezis(int16_t min_z, int16_t max_z, uint16_t delay_us, uint8_t samples) { - DBG(_n("xyzcal_meassure_pinda_hysterezis\n")); - int8_t ret = -1; // PINDA signal error - int16_t z = _Z; - int16_t sum_up = 0; - int16_t sum_dn = 0; - int16_t up; - int16_t dn; - uint8_t sample; - xyzcal_lineXYZ_to(_X, _Y, min_z, delay_us, 1); - xyzcal_lineXYZ_to(_X, _Y, max_z, delay_us, -1); - if (!_PINDA) - { - for (sample = 0; sample < samples; sample++) - { - dn = _Z; - if (!xyzcal_lineXYZ_to(_X, _Y, min_z, delay_us, 1)) break; - dn = dn - _Z; - up = _Z; - if (!xyzcal_lineXYZ_to(_X, _Y, max_z, delay_us, -1)) break; - up = _Z - up; - DBG(_n("%d. up=%d dn=%d\n"), sample, up, dn); - sum_up += up; - sum_dn += dn; - if (abs(up - dn) > XYZCAL_PINDA_HYST_DIF) - { - ret = -2; // difference between up-dn to high - break; - } - } - if (sample == samples) - { - up = sum_up / samples; - dn = sum_dn / samples; - uint16_t hyst = (up + dn) / 2; - if (abs(up - dn) > XYZCAL_PINDA_HYST_DIF) - ret = -2; // difference between up-dn to high - else if ((hyst < XYZCAL_PINDA_HYST_MIN) || (hyst > XYZCAL_PINDA_HYST_MAX)) - ret = -3; // hysterezis out of range - else - ret = hyst; - } - } - xyzcal_lineXYZ_to(_X, _Y, z, delay_us, 0); - return ret; + DBG(_n("xyzcal_meassure_pinda_hysterezis\n")); + int8_t ret = -1; // PINDA signal error + int16_t z = _Z; + int16_t sum_up = 0; + int16_t sum_dn = 0; + int16_t up; + int16_t dn; + uint8_t sample; + xyzcal_lineXYZ_to(_X, _Y, min_z, delay_us, 1); + xyzcal_lineXYZ_to(_X, _Y, max_z, delay_us, -1); + if (!_PINDA) + { + for (sample = 0; sample < samples; sample++) + { + dn = _Z; + if (!xyzcal_lineXYZ_to(_X, _Y, min_z, delay_us, 1)) break; + dn = dn - _Z; + up = _Z; + if (!xyzcal_lineXYZ_to(_X, _Y, max_z, delay_us, -1)) break; + up = _Z - up; + DBG(_n("%d. up=%d dn=%d\n"), sample, up, dn); + sum_up += up; + sum_dn += dn; + if (abs(up - dn) > XYZCAL_PINDA_HYST_DIF) + { + ret = -2; // difference between up-dn to high + break; + } + } + if (sample == samples) + { + up = sum_up / samples; + dn = sum_dn / samples; + uint16_t hyst = (up + dn) / 2; + if (abs(up - dn) > XYZCAL_PINDA_HYST_DIF) + ret = -2; // difference between up-dn to high + else if ((hyst < XYZCAL_PINDA_HYST_MIN) || (hyst > XYZCAL_PINDA_HYST_MAX)) + ret = -3; // hysterezis out of range + else + ret = hyst; + } + } + xyzcal_lineXYZ_to(_X, _Y, z, delay_us, 0); + return ret; } #endif //XYZCAL_MEASSURE_PINDA_HYSTEREZIS void xyzcal_scan_pixels_32x32(int16_t cx, int16_t cy, int16_t min_z, int16_t max_z, uint16_t delay_us, uint8_t* pixels) { - DBG(_n("xyzcal_scan_pixels_32x32 cx=%d cy=%d min_z=%d max_z=%d\n"), cx, cy, min_z, max_z); + DBG(_n("xyzcal_scan_pixels_32x32 cx=%d cy=%d min_z=%d max_z=%d\n"), cx, cy, min_z, max_z); // xyzcal_lineXYZ_to(cx - 1024, cy - 1024, max_z, 2*delay_us, 0); // xyzcal_lineXYZ_to(cx, cy, max_z, delay_us, 0); - int16_t z = (int16_t)count_position[2]; - xyzcal_lineXYZ_to(cx, cy, z, 2*delay_us, 0); - for (uint8_t r = 0; r < 32; r++) - { + int16_t z = (int16_t)count_position[2]; + xyzcal_lineXYZ_to(cx, cy, z, 2*delay_us, 0); + for (uint8_t r = 0; r < 32; r++) + { // int8_t _pinda = _PINDA; - xyzcal_lineXYZ_to((r&1)?(cx+1024):(cx-1024), cy - 1024 + r*64, z, 2*delay_us, 0); - xyzcal_lineXYZ_to(_X, _Y, min_z, delay_us, 1); - xyzcal_lineXYZ_to(_X, _Y, max_z, delay_us, -1); - z = (int16_t)count_position[2]; - sm4_set_dir(X_AXIS, (r&1)?1:0); - for (uint8_t c = 0; c < 32; c++) - { - uint16_t sum = 0; - int16_t z_sum = 0; - for (uint8_t i = 0; i < 64; i++) - { - int8_t pinda = _PINDA; - int16_t pix = z - min_z; - pix += (pinda)?23:-24; - if (pix < 0) pix = 0; - if (pix > 255) pix = 255; - sum += pix; - z_sum += z; + xyzcal_lineXYZ_to((r&1)?(cx+1024):(cx-1024), cy - 1024 + r*64, z, 2*delay_us, 0); + xyzcal_lineXYZ_to(_X, _Y, min_z, delay_us, 1); + xyzcal_lineXYZ_to(_X, _Y, max_z, delay_us, -1); + z = (int16_t)count_position[2]; + sm4_set_dir(X_AXIS, (r&1)?1:0); + for (uint8_t c = 0; c < 32; c++) + { + uint16_t sum = 0; + int16_t z_sum = 0; + for (uint8_t i = 0; i < 64; i++) + { + int8_t pinda = _PINDA; + int16_t pix = z - min_z; + pix += (pinda)?23:-24; + if (pix < 0) pix = 0; + if (pix > 255) pix = 255; + sum += pix; + z_sum += z; // if (_pinda != pinda) // { // if (pinda) @@ -311,106 +314,106 @@ void xyzcal_scan_pixels_32x32(int16_t cx, int16_t cy, int16_t min_z, int16_t max // else // DBG(_n("!0 x=%d z=%d\n"), c*64+i, z-24); // } - sm4_set_dir(Z_AXIS, !pinda); - if (!pinda) - { - if (z > min_z) - { - sm4_do_step(Z_AXIS_MASK); - z--; - } - } - else - { - if (z < max_z) - { - sm4_do_step(Z_AXIS_MASK); - z++; - } - } - sm4_do_step(X_AXIS_MASK); - delayMicroseconds(600); + sm4_set_dir(Z_AXIS, !pinda); + if (!pinda) + { + if (z > min_z) + { + sm4_do_step(Z_AXIS_MASK); + z--; + } + } + else + { + if (z < max_z) + { + sm4_do_step(Z_AXIS_MASK); + z++; + } + } + sm4_do_step(X_AXIS_MASK); + delayMicroseconds(600); // _pinda = pinda; - } - sum >>= 6; //div 64 - if (z_sum < 0) - { - z_sum = -z_sum; - z_sum >>= 6; //div 64 - z_sum = -z_sum; - } - else - z_sum >>= 6; //div 64 - if (pixels) pixels[((uint16_t)r<<5) + ((r&1)?(31-c):c)] = sum; + } + sum >>= 6; //div 64 + if (z_sum < 0) + { + z_sum = -z_sum; + z_sum >>= 6; //div 64 + z_sum = -z_sum; + } + else + z_sum >>= 6; //div 64 + if (pixels) pixels[((uint16_t)r<<5) + ((r&1)?(31-c):c)] = sum; // DBG(_n("c=%d r=%d l=%d z=%d\n"), c, r, sum, z_sum); - count_position[0] += (r&1)?-64:64; - count_position[2] = z; - } - if (pixels) - for (uint8_t c = 0; c < 32; c++) - DBG(_n("%02x"), pixels[((uint16_t)r<<5) + c]); - DBG(_n("\n")); - } + count_position[0] += (r&1)?-64:64; + count_position[2] = z; + } + if (pixels) + for (uint8_t c = 0; c < 32; c++) + DBG(_n("%02x"), pixels[((uint16_t)r<<5) + c]); + DBG(_n("\n")); + } // xyzcal_lineXYZ_to(cx, cy, z, 2*delay_us, 0); } void xyzcal_histo_pixels_32x32(uint8_t* pixels, uint16_t* histo) { - for (uint8_t l = 0; l < 16; l++) - histo[l] = 0; - for (uint8_t r = 0; r < 32; r++) - for (uint8_t c = 0; c < 32; c++) - { - uint8_t pix = pixels[((uint16_t)r<<5) + c]; - histo[pix >> 4]++; - } - for (uint8_t l = 0; l < 16; l++) - DBG(_n(" %2d %d\n"), l, histo[l]); + for (uint8_t l = 0; l < 16; l++) + histo[l] = 0; + for (uint8_t r = 0; r < 32; r++) + for (uint8_t c = 0; c < 32; c++) + { + uint8_t pix = pixels[((uint16_t)r<<5) + c]; + histo[pix >> 4]++; + } + for (uint8_t l = 0; l < 16; l++) + DBG(_n(" %2d %d\n"), l, histo[l]); } void xyzcal_adjust_pixels(uint8_t* pixels, uint16_t* histo) { - uint8_t l; - uint16_t max_c = histo[1]; - uint8_t max_l = 1; - for (l = 1; l < 16; l++) - { - uint16_t c = histo[l]; - if (c > max_c) - { - max_c = c; - max_l = l; - } - } - DBG(_n("max_c=%2d max_l=%d\n"), max_c, max_l); - for (l = 14; l > 8; l--) - if (histo[l] >= 10) - break; - uint8_t pix_min = 0; - uint8_t pix_max = l << 4; - if (histo[0] < (32*32 - 144)) - { - pix_min = (max_l << 4) / 2; - } - uint8_t pix_dif = pix_max - pix_min; - DBG(_n(" min=%d max=%d dif=%d\n"), pix_min, pix_max, pix_dif); - for (int16_t i = 0; i < 32*32; i++) - { - uint16_t pix = pixels[i]; - if (pix > pix_min) pix -= pix_min; - else pix = 0; - pix <<= 8; - pix /= pix_dif; + uint8_t l; + uint16_t max_c = histo[1]; + uint8_t max_l = 1; + for (l = 1; l < 16; l++) + { + uint16_t c = histo[l]; + if (c > max_c) + { + max_c = c; + max_l = l; + } + } + DBG(_n("max_c=%2d max_l=%d\n"), max_c, max_l); + for (l = 14; l > 8; l--) + if (histo[l] >= 10) + break; + uint8_t pix_min = 0; + uint8_t pix_max = l << 4; + if (histo[0] < (32*32 - 144)) + { + pix_min = (max_l << 4) / 2; + } + uint8_t pix_dif = pix_max - pix_min; + DBG(_n(" min=%d max=%d dif=%d\n"), pix_min, pix_max, pix_dif); + for (int16_t i = 0; i < 32*32; i++) + { + uint16_t pix = pixels[i]; + if (pix > pix_min) pix -= pix_min; + else pix = 0; + pix <<= 8; + pix /= pix_dif; // if (pix < 0) pix = 0; - if (pix > 255) pix = 255; - pixels[i] = (uint8_t)pix; - } - for (uint8_t r = 0; r < 32; r++) - { - for (uint8_t c = 0; c < 32; c++) - DBG(_n("%02x"), pixels[((uint16_t)r<<5) + c]); - DBG(_n("\n")); - } + if (pix > 255) pix = 255; + pixels[i] = (uint8_t)pix; + } + for (uint8_t r = 0; r < 32; r++) + { + for (uint8_t c = 0; c < 32; c++) + DBG(_n("%02x"), pixels[((uint16_t)r<<5) + c]); + DBG(_n("\n")); + } } /* @@ -431,49 +434,49 @@ void xyzcal_draw_pattern_12x12_in_32x32(uint8_t* pattern, uint32_t* pixels, int int16_t xyzcal_match_pattern_12x12_in_32x32(uint16_t* pattern, uint8_t* pixels, uint8_t c, uint8_t r) { - uint8_t thr = 16; - int16_t match = 0; - for (uint8_t i = 0; i < 12; i++) - for (uint8_t j = 0; j < 12; j++) - { - if (((i == 0) || (i == 11)) && ((j < 2) || (j >= 10))) continue; //skip corners - if (((j == 0) || (j == 11)) && ((i < 2) || (i >= 10))) continue; - uint16_t idx = (c + j) + 32 * (r + i); - uint8_t val = pixels[idx]; - if (pattern[i] & (1 << j)) - { - if (val > thr) match ++; - else match --; - } - else - { - if (val <= thr) match ++; - else match --; - } - } - return match; + uint8_t thr = 16; + int16_t match = 0; + for (uint8_t i = 0; i < 12; i++) + for (uint8_t j = 0; j < 12; j++) + { + if (((i == 0) || (i == 11)) && ((j < 2) || (j >= 10))) continue; //skip corners + if (((j == 0) || (j == 11)) && ((i < 2) || (i >= 10))) continue; + uint16_t idx = (c + j) + 32 * (r + i); + uint8_t val = pixels[idx]; + if (pattern[i] & (1 << j)) + { + if (val > thr) match ++; + else match --; + } + else + { + if (val <= thr) match ++; + else match --; + } + } + return match; } int16_t xyzcal_find_pattern_12x12_in_32x32(uint8_t* pixels, uint16_t* pattern, uint8_t* pc, uint8_t* pr) { - uint8_t max_c = 0; - uint8_t max_r = 0; - int16_t max_match = 0; - for (uint8_t r = 0; r < (32 - 12); r++) - for (uint8_t c = 0; c < (32 - 12); c++) - { - int16_t match = xyzcal_match_pattern_12x12_in_32x32(pattern, pixels, c, r); - if (max_match < match) - { - max_c = c; - max_r = r; - max_match = match; - } - } - DBG(_n("max_c=%d max_r=%d max_match=%d\n"), max_c, max_r, max_match); - if (pc) *pc = max_c; - if (pr) *pr = max_r; - return max_match; + uint8_t max_c = 0; + uint8_t max_r = 0; + int16_t max_match = 0; + for (uint8_t r = 0; r < (32 - 12); r++) + for (uint8_t c = 0; c < (32 - 12); c++) + { + int16_t match = xyzcal_match_pattern_12x12_in_32x32(pattern, pixels, c, r); + if (max_match < match) + { + max_c = c; + max_r = r; + max_match = match; + } + } + DBG(_n("max_c=%d max_r=%d max_match=%d\n"), max_c, max_r, max_match); + if (pc) *pc = max_c; + if (pr) *pr = max_r; + return max_match; } #define MAX_DIAMETR 600 @@ -481,21 +484,21 @@ int16_t xyzcal_find_pattern_12x12_in_32x32(uint8_t* pixels, uint16_t* pattern, u int8_t xyzcal_find_point_center2(uint16_t delay_us) { - printf_P(PSTR("xyzcal_find_point_center2\n")); - int16_t x0 = _X; - int16_t y0 = _Y; - int16_t z0 = _Z; - printf_P(PSTR(" x0=%d\n"), x0); - printf_P(PSTR(" y0=%d\n"), y0); - printf_P(PSTR(" z0=%d\n"), z0); - - xyzcal_lineXYZ_to(_X, _Y, z0 + 400, 500, -1); - xyzcal_lineXYZ_to(_X, _Y, z0 - 400, 500, 1); - xyzcal_lineXYZ_to(_X, _Y, z0 + 400, 500, -1); - xyzcal_lineXYZ_to(_X, _Y, z0 - 400, 500, 1); - - z0 = _Z - 20; - xyzcal_lineXYZ_to(_X, _Y, z0, 500, 0); + printf_P(PSTR("xyzcal_find_point_center2\n")); + int16_t x0 = _X; + int16_t y0 = _Y; + int16_t z0 = _Z; + printf_P(PSTR(" x0=%d\n"), x0); + printf_P(PSTR(" y0=%d\n"), y0); + printf_P(PSTR(" z0=%d\n"), z0); + + xyzcal_lineXYZ_to(_X, _Y, z0 + 400, 500, -1); + xyzcal_lineXYZ_to(_X, _Y, z0 - 400, 500, 1); + xyzcal_lineXYZ_to(_X, _Y, z0 + 400, 500, -1); + xyzcal_lineXYZ_to(_X, _Y, z0 - 400, 500, 1); + + z0 = _Z - 20; + xyzcal_lineXYZ_to(_X, _Y, z0, 500, 0); // xyzcal_lineXYZ_to(x0, y0, z0 - 100, 500, 1); // z0 = _Z; @@ -503,185 +506,185 @@ int8_t xyzcal_find_point_center2(uint16_t delay_us) // xyzcal_lineXYZ_to(x0, y0, z0 + 100, 500, -1); // z0 += _Z; // z0 /= 2; - printf_P(PSTR(" z0=%d\n"), z0); + printf_P(PSTR(" z0=%d\n"), z0); // xyzcal_lineXYZ_to(x0, y0, z0 - 100, 500, 1); // z0 = _Z - 10; - int8_t ret = 1; + int8_t ret = 1; #ifdef XYZCAL_FIND_CENTER_DIAGONAL - int32_t xc = 0; - int32_t yc = 0; - int16_t ad = 45; - for (; ad < 360; ad += 90) - { - float ar = (float)ad * _PI / 180; - int16_t x = x0 + MAX_DIAMETR * cos(ar); - int16_t y = y0 + MAX_DIAMETR * sin(ar); - if (!xyzcal_lineXYZ_to(x, y, z0, delay_us, -1)) - { - printf_P(PSTR("ERROR ad=%d\n"), ad); - ret = 0; - break; - } - xc += _X; - yc += _Y; - xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); - } - if (ret) - { - printf_P(PSTR("OK\n"), ad); - x0 = xc / 4; - y0 = yc / 4; - printf_P(PSTR(" x0=%d\n"), x0); - printf_P(PSTR(" y0=%d\n"), y0); - } + int32_t xc = 0; + int32_t yc = 0; + int16_t ad = 45; + for (; ad < 360; ad += 90) + { + float ar = (float)ad * _PI / 180; + int16_t x = x0 + MAX_DIAMETR * cos(ar); + int16_t y = y0 + MAX_DIAMETR * sin(ar); + if (!xyzcal_lineXYZ_to(x, y, z0, delay_us, -1)) + { + printf_P(PSTR("ERROR ad=%d\n"), ad); + ret = 0; + break; + } + xc += _X; + yc += _Y; + xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); + } + if (ret) + { + printf_P(PSTR("OK\n"), ad); + x0 = xc / 4; + y0 = yc / 4; + printf_P(PSTR(" x0=%d\n"), x0); + printf_P(PSTR(" y0=%d\n"), y0); + } #else //XYZCAL_FIND_CENTER_DIAGONAL - xyzcal_lineXYZ_to(x0 - MAX_DIAMETR, y0, z0, delay_us, -1); - int16_t dx1 = x0 - _X; - if (dx1 >= MAX_DIAMETR) - { - printf_P(PSTR("!!! dx1 = %d\n"), dx1); - return 0; - } - xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); - xyzcal_lineXYZ_to(x0 + MAX_DIAMETR, y0, z0, delay_us, -1); - int16_t dx2 = _X - x0; - if (dx2 >= MAX_DIAMETR) - { - printf_P(PSTR("!!! dx2 = %d\n"), dx2); - return 0; - } - xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); - xyzcal_lineXYZ_to(x0 , y0 - MAX_DIAMETR, z0, delay_us, -1); - int16_t dy1 = y0 - _Y; - if (dy1 >= MAX_DIAMETR) - { - printf_P(PSTR("!!! dy1 = %d\n"), dy1); - return 0; - } - xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); - xyzcal_lineXYZ_to(x0, y0 + MAX_DIAMETR, z0, delay_us, -1); - int16_t dy2 = _Y - y0; - if (dy2 >= MAX_DIAMETR) - { - printf_P(PSTR("!!! dy2 = %d\n"), dy2); - return 0; - } - printf_P(PSTR("dx1=%d\n"), dx1); - printf_P(PSTR("dx2=%d\n"), dx2); - printf_P(PSTR("dy1=%d\n"), dy1); - printf_P(PSTR("dy2=%d\n"), dy2); - - x0 += (dx2 - dx1) / 2; - y0 += (dy2 - dy1) / 2; - - printf_P(PSTR(" x0=%d\n"), x0); - printf_P(PSTR(" y0=%d\n"), y0); + xyzcal_lineXYZ_to(x0 - MAX_DIAMETR, y0, z0, delay_us, -1); + int16_t dx1 = x0 - _X; + if (dx1 >= MAX_DIAMETR) + { + printf_P(PSTR("!!! dx1 = %d\n"), dx1); + return 0; + } + xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); + xyzcal_lineXYZ_to(x0 + MAX_DIAMETR, y0, z0, delay_us, -1); + int16_t dx2 = _X - x0; + if (dx2 >= MAX_DIAMETR) + { + printf_P(PSTR("!!! dx2 = %d\n"), dx2); + return 0; + } + xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); + xyzcal_lineXYZ_to(x0, y0 - MAX_DIAMETR, z0, delay_us, -1); + int16_t dy1 = y0 - _Y; + if (dy1 >= MAX_DIAMETR) + { + printf_P(PSTR("!!! dy1 = %d\n"), dy1); + return 0; + } + xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); + xyzcal_lineXYZ_to(x0, y0 + MAX_DIAMETR, z0, delay_us, -1); + int16_t dy2 = _Y - y0; + if (dy2 >= MAX_DIAMETR) + { + printf_P(PSTR("!!! dy2 = %d\n"), dy2); + return 0; + } + printf_P(PSTR("dx1=%d\n"), dx1); + printf_P(PSTR("dx2=%d\n"), dx2); + printf_P(PSTR("dy1=%d\n"), dy1); + printf_P(PSTR("dy2=%d\n"), dy2); + + x0 += (dx2 - dx1) / 2; + y0 += (dy2 - dy1) / 2; + + printf_P(PSTR(" x0=%d\n"), x0); + printf_P(PSTR(" y0=%d\n"), y0); #endif //XYZCAL_FIND_CENTER_DIAGONAL - xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); + xyzcal_lineXYZ_to(x0, y0, z0, delay_us, 0); - return ret; + return ret; } #ifdef XYZCAL_FIND_POINT_CENTER int8_t xyzcal_find_point_center(int16_t x0, int16_t y0, int16_t z0, int16_t min_z, int16_t max_z, uint16_t delay_us, uint8_t turns) { - uint8_t n; - uint16_t ad; - float ar; - float _cos; - float _sin; - int16_t r_min = 0; - int16_t r_max = 0; - int16_t x_min = 0; - int16_t x_max = 0; - int16_t y_min = 0; - int16_t y_max = 0; - int16_t r = 10; - int16_t x = x0; - int16_t y = y0; - int16_t z = z0; - int8_t _pinda = _PINDA; - for (n = 0; n < turns; n++) - { - uint32_t r_sum = 0; - for (ad = 0; ad < 720; ad++) - { - ar = ad * _PI / 360; - _cos = cos(ar); - _sin = sin(ar); - x = x0 + (int)(_cos * r); - y = y0 + (int)(_sin * r); - xyzcal_lineXYZ_to(x, y, z, 1000, 0); - int8_t pinda = _PINDA; - if (pinda) - r += 1; - else - { - r -= 1; - ad--; - r_sum -= r; - } - if (ad == 0) - { - x_min = x0; - x_max = x0; - y_min = y0; - y_max = y0; - r_min = r; - r_max = r; - } - else if (pinda) - { - if (x_min > x) x_min = (2*x + x_min) / 3; - if (x_max < x) x_max = (2*x + x_max) / 3; - if (y_min > y) y_min = (2*y + y_min) / 3; - if (y_max < y) y_max = (2*y + y_max) / 3; -/* if (x_min > x) x_min = x; - if (x_max < x) x_max = x; - if (y_min > y) y_min = y; - if (y_max < y) y_max = y;*/ - if (r_min > r) r_min = r; - if (r_max < r) r_max = r; - } - r_sum += r; -/* if (_pinda != pinda) - { - if (pinda) - DBG(_n("!1 x=%d y=%d\n"), x, y); - else - DBG(_n("!0 x=%d y=%d\n"), x, y); - }*/ - _pinda = pinda; + uint8_t n; + uint16_t ad; + float ar; + float _cos; + float _sin; + int16_t r_min = 0; + int16_t r_max = 0; + int16_t x_min = 0; + int16_t x_max = 0; + int16_t y_min = 0; + int16_t y_max = 0; + int16_t r = 10; + int16_t x = x0; + int16_t y = y0; + int16_t z = z0; + int8_t _pinda = _PINDA; + for (n = 0; n < turns; n++) + { + uint32_t r_sum = 0; + for (ad = 0; ad < 720; ad++) + { + ar = ad * _PI / 360; + _cos = cos(ar); + _sin = sin(ar); + x = x0 + (int)(_cos * r); + y = y0 + (int)(_sin * r); + xyzcal_lineXYZ_to(x, y, z, 1000, 0); + int8_t pinda = _PINDA; + if (pinda) + r += 1; + else + { + r -= 1; + ad--; + r_sum -= r; + } + if (ad == 0) + { + x_min = x0; + x_max = x0; + y_min = y0; + y_max = y0; + r_min = r; + r_max = r; + } + else if (pinda) + { + if (x_min > x) x_min = (2*x + x_min) / 3; + if (x_max < x) x_max = (2*x + x_max) / 3; + if (y_min > y) y_min = (2*y + y_min) / 3; + if (y_max < y) y_max = (2*y + y_max) / 3; + /* if (x_min > x) x_min = x; + if (x_max < x) x_max = x; + if (y_min > y) y_min = y; + if (y_max < y) y_max = y;*/ + if (r_min > r) r_min = r; + if (r_max < r) r_max = r; + } + r_sum += r; + /* if (_pinda != pinda) + { + if (pinda) + DBG(_n("!1 x=%d y=%d\n"), x, y); + else + DBG(_n("!0 x=%d y=%d\n"), x, y); + }*/ + _pinda = pinda; // DBG(_n("x=%d y=%d rx=%d ry=%d\n"), x, y, rx, ry); - } - DBG(_n("x_min=%d x_max=%d y_min=%d y_max=%d r_min=%d r_max=%d r_avg=%d\n"), x_min, x_max, y_min, y_max, r_min, r_max, r_sum / 720); - if ((n > 2) && (n & 1)) - { - x0 += (x_min + x_max); - y0 += (y_min + y_max); - x0 /= 3; - y0 /= 3; - int rx = (x_max - x_min) / 2; - int ry = (y_max - y_min) / 2; - r = (rx + ry) / 3;//(rx < ry)?rx:ry; - DBG(_n("x0=%d y0=%d r=%d\n"), x0, y0, r); - } - } - xyzcal_lineXYZ_to(x0, y0, z, 200, 0); + } + DBG(_n("x_min=%d x_max=%d y_min=%d y_max=%d r_min=%d r_max=%d r_avg=%d\n"), x_min, x_max, y_min, y_max, r_min, r_max, r_sum / 720); + if ((n > 2) && (n & 1)) + { + x0 += (x_min + x_max); + y0 += (y_min + y_max); + x0 /= 3; + y0 /= 3; + int rx = (x_max - x_min) / 2; + int ry = (y_max - y_min) / 2; + r = (rx + ry) / 3;//(rx < ry)?rx:ry; + DBG(_n("x0=%d y0=%d r=%d\n"), x0, y0, r); + } + } + xyzcal_lineXYZ_to(x0, y0, z, 200, 0); } #endif //XYZCAL_FIND_POINT_CENTER uint8_t xyzcal_xycoords2point(int16_t x, int16_t y) { - uint8_t ix = (x > 10000)?1:0; - uint8_t iy = (y > 10000)?1:0; - return iy?(3-ix):ix; + uint8_t ix = (x > 10000)?1:0; + uint8_t iy = (y > 10000)?1:0; + return iy?(3-ix):ix; } //MK3 @@ -700,114 +703,115 @@ const uint16_t xyzcal_point_pattern[12] PROGMEM = {0x000, 0x0f0, 0x1f8, 0x3fc, 0 bool xyzcal_searchZ(void) { - DBG(_n("xyzcal_searchZ x=%ld y=%ld z=%ld\n"), count_position[X_AXIS], count_position[Y_AXIS], count_position[Z_AXIS]); - int16_t x0 = _X; - int16_t y0 = _Y; - int16_t z0 = _Z; + DBG(_n("xyzcal_searchZ x=%ld y=%ld z=%ld\n"), count_position[X_AXIS], count_position[Y_AXIS], count_position[Z_AXIS]); + int16_t x0 = _X; + int16_t y0 = _Y; + int16_t z0 = _Z; // int16_t min_z = -6000; // int16_t dz = 100; - int16_t z = z0; - while (z > -2300) //-6mm + 0.25mm - { - uint16_t ad = 0; - if (xyzcal_spiral8(x0, y0, z, 100, 900, 320, 1, &ad)) //dz=100 radius=900 delay=400 - { - int16_t x_on = _X; - int16_t y_on = _Y; - int16_t z_on = _Z; - DBG(_n(" ON-SIGNAL at x=%d y=%d z=%d ad=%d\n"), x_on, y_on, z_on, ad); - return true; - } - z -= 400; - } - DBG(_n("xyzcal_searchZ no signal\n x=%ld y=%ld z=%ld\n"), count_position[X_AXIS], count_position[Y_AXIS], count_position[Z_AXIS]); - return false; + int16_t z = z0; + while (z > -2300) //-6mm + 0.25mm + { + uint16_t ad = 0; + if (xyzcal_spiral8(x0, y0, z, 100, 900, 320, 1, &ad)) //dz=100 radius=900 delay=400 + { + int16_t x_on = _X; + int16_t y_on = _Y; + int16_t z_on = _Z; + DBG(_n(" ON-SIGNAL at x=%d y=%d z=%d ad=%d\n"), x_on, y_on, z_on, ad); + return true; + } + z -= 400; + } + DBG(_n("xyzcal_searchZ no signal\n x=%ld y=%ld z=%ld\n"), count_position[X_AXIS], count_position[Y_AXIS], count_position[Z_AXIS]); + return false; } bool xyzcal_scan_and_process(void) { - DBG(_n("sizeof(block_buffer)=%d\n"), sizeof(block_t)*BLOCK_BUFFER_SIZE); + DBG(_n("sizeof(block_buffer)=%d\n"), sizeof(block_t)*BLOCK_BUFFER_SIZE); // DBG(_n("sizeof(pixels)=%d\n"), 32*32); // DBG(_n("sizeof(histo)=%d\n"), 2*16); // DBG(_n("sizeof(pattern)=%d\n"), 2*12); - DBG(_n("sizeof(total)=%d\n"), 32*32+2*16+2*12); - bool ret = false; - int16_t x = _X; - int16_t y = _Y; - int16_t z = _Z; + DBG(_n("sizeof(total)=%d\n"), 32*32+2*16+2*12); + bool ret = false; + int16_t x = _X; + int16_t y = _Y; + int16_t z = _Z; - uint8_t* pixels = (uint8_t*)block_buffer; - xyzcal_scan_pixels_32x32(x, y, z - 72, 2400, 200, pixels); + uint8_t* pixels = (uint8_t*)block_buffer; + xyzcal_scan_pixels_32x32(x, y, z - 72, 2400, 200, pixels); - uint16_t* histo = (uint16_t*)(pixels + 32*32); - xyzcal_histo_pixels_32x32(pixels, histo); + uint16_t* histo = (uint16_t*)(pixels + 32*32); + xyzcal_histo_pixels_32x32(pixels, histo); - xyzcal_adjust_pixels(pixels, histo); + xyzcal_adjust_pixels(pixels, histo); - uint16_t* pattern = (uint16_t*)(histo + 2*16); - for (uint8_t i = 0; i < 12; i++) - { - pattern[i] = pgm_read_word((uint16_t*)(xyzcal_point_pattern + i)); + uint16_t* pattern = (uint16_t*)(histo + 2*16); + for (uint8_t i = 0; i < 12; i++) + { + pattern[i] = pgm_read_word((uint16_t*)(xyzcal_point_pattern + i)); // DBG(_n(" pattern[%d]=%d\n"), i, pattern[i]); - } - uint8_t c = 0; - uint8_t r = 0; - if (xyzcal_find_pattern_12x12_in_32x32(pixels, pattern, &c, &r) > 66) //total pixels=144, corner=12 (1/2 = 66) - { - DBG(_n(" pattern found at %d %d\n"), c, r); - c += 6; - r += 6; - x += ((int16_t)c - 16) << 6; - y += ((int16_t)r - 16) << 6; - DBG(_n(" x=%d y=%d z=%d\n"), x, y, z); - xyzcal_lineXYZ_to(x, y, z, 200, 0); - ret = true; - } - for (uint16_t i = 0; i < sizeof(block_t)*BLOCK_BUFFER_SIZE; i++) - pixels[i] = 0; - return ret; + } + uint8_t c = 0; + uint8_t r = 0; + if (xyzcal_find_pattern_12x12_in_32x32(pixels, pattern, &c, &r) > 66) //total pixels=144, corner=12 (1/2 = 66) + { + DBG(_n(" pattern found at %d %d\n"), c, r); + c += 6; + r += 6; + x += ((int16_t)c - 16) << 6; + y += ((int16_t)r - 16) << 6; + DBG(_n(" x=%d y=%d z=%d\n"), x, y, z); + xyzcal_lineXYZ_to(x, y, z, 200, 0); + ret = true; + } + for (uint16_t i = 0; i < sizeof(block_t)*BLOCK_BUFFER_SIZE; i++) + pixels[i] = 0; + return ret; } bool xyzcal_find_bed_induction_sensor_point_xy(void) { - DBG(_n("xyzcal_find_bed_induction_sensor_point_xy x=%ld y=%ld z=%ld\n"), count_position[X_AXIS], count_position[Y_AXIS], count_position[Z_AXIS]); - bool ret = false; - st_synchronize(); - int16_t x = _X; - int16_t y = _Y; - int16_t z = _Z; - uint8_t point = xyzcal_xycoords2point(x, y); - x = pgm_read_word((uint16_t*)(xyzcal_point_xcoords + point)); - y = pgm_read_word((uint16_t*)(xyzcal_point_ycoords + point)); - DBG(_n("point=%d x=%d y=%d z=%d\n"), point, x, y, z); - xyzcal_meassure_enter(); - xyzcal_lineXYZ_to(x, y, z, 200, 0); - if (xyzcal_searchZ()) - { - int16_t z = _Z; - xyzcal_lineXYZ_to(x, y, z, 200, 0); - if (xyzcal_scan_and_process()) - { - if (xyzcal_find_point_center2(500)) - { - uint32_t x_avg = 0; - uint32_t y_avg = 0; - uint8_t n; for (n = 0; n < 4; n++) - { - if (!xyzcal_find_point_center2(1000)) break; - x_avg += _X; - y_avg += _Y; - } - if (n == 4) - { - xyzcal_lineXYZ_to(x_avg >> 2, y_avg >> 2, _Z, 200, 0); - ret = true; - } - } - } - } - xyzcal_meassure_leave(); - return ret; + DBG(_n("xyzcal_find_bed_induction_sensor_point_xy x=%ld y=%ld z=%ld\n"), count_position[X_AXIS], count_position[Y_AXIS], count_position[Z_AXIS]); + bool ret = false; + st_synchronize(); + int16_t x = _X; + int16_t y = _Y; + int16_t z = _Z; + uint8_t point = xyzcal_xycoords2point(x, y); + x = pgm_read_word((uint16_t*)(xyzcal_point_xcoords + point)); + y = pgm_read_word((uint16_t*)(xyzcal_point_ycoords + point)); + DBG(_n("point=%d x=%d y=%d z=%d\n"), point, x, y, z); + xyzcal_meassure_enter(); + xyzcal_lineXYZ_to(x, y, z, 200, 0); + if (xyzcal_searchZ()) + { + int16_t z = _Z; + xyzcal_lineXYZ_to(x, y, z, 200, 0); + if (xyzcal_scan_and_process()) + { + if (xyzcal_find_point_center2(500)) + { + uint32_t x_avg = 0; + uint32_t y_avg = 0; + uint8_t n; + for (n = 0; n < 4; n++) + { + if (!xyzcal_find_point_center2(1000)) break; + x_avg += _X; + y_avg += _Y; + } + if (n == 4) + { + xyzcal_lineXYZ_to(x_avg >> 2, y_avg >> 2, _Z, 200, 0); + ret = true; + } + } + } + } + xyzcal_meassure_leave(); + return ret; } diff --git a/README.md b/README.md index c6cff6700f..7574c97caa 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# This FW is for use with MMU2, in combination with MMU2-FW https://github.com/TheZeroBeast/MM-control-01 + + + # Table of contents @@ -7,9 +11,6 @@ * [Documentation](#4-documentation) -This FW is for use with MMU2, in combination with MMU2-FW https://github.com/TheZeroBeast/MM-control-01 - - # 1. Development environment preparation 1. install `"Arduino Software IDE"` for your preferred operating system