/* This file is part of Repetier-Firmware. Repetier-Firmware 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. Repetier-Firmware 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 Repetier-Firmware. If not, see . */ #define UI_MAIN #include "Reptier.h" #include extern const int8_t encoder_table[16] PROGMEM ; #include "ui.h" #include #include #include #include #include #include #include "Eeprom.h" #include #if UI_ENCODER_SPEED==0 const int8_t encoder_table[16] PROGMEM = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0}; // Full speed #elif UI_ENCODER_SPEED==1 const int8_t encoder_table[16] PROGMEM = {0,0,-1,0,0,0,0,1,1,0,0,0,0,-1,0,0}; // Half speed #else const int8_t encoder_table[16] PROGMEM = {0,0,0,0,0,0,0,0,1,0,0,0,0,-1,0,0}; // Quart speed #endif #if BEEPER_TYPE==2 && defined(UI_HAS_I2C_KEYS) && UI_I2C_KEY_ADDRESS!=BEEPER_ADDRESS #error Beeper address and i2c key address must be identical #else #if BEEPER_TYPE==2 #define UI_I2C_KEY_ADDRESS BEEPER_ADDRESS #endif #endif #if UI_AUTORETURN_TO_MENU_AFTER!=0 long ui_autoreturn_time=0; #endif void beep(byte duration,byte count) { #if FEATURE_BEEPER #if BEEPER_TYPE!=0 #if BEEPER_TYPE==1 SET_OUTPUT(BEEPER_PIN); #endif #if BEEPER_TYPE==2 i2c_start_wait(BEEPER_ADDRESS+I2C_WRITE); #if UI_DISPLAY_I2C_CHIPTYPE==1 i2c_write( 0x14); // Start at port a #endif #endif for(byte i=0;i>8); #endif #endif delay(duration); #if BEEPER_TYPE==1 WRITE(BEEPER_PIN,LOW); #else #if UI_DISPLAY_I2C_CHIPTYPE==0 #if BEEPER_ADDRESS == UI_DISPLAY_I2C_ADDRESS i2c_write((BEEPER_PIN) | uid.outputMask); #else i2c_write(255); #endif #endif #if UI_DISPLAY_I2C_CHIPTYPE==1 i2c_write( uid.outputMask); i2c_write(uid.outputMask>>8); #endif #endif delay(duration); } #if BEEPER_TYPE==2 i2c_stop(); #endif #endif #endif } //============================================================= // I2C driver //============================================================= #ifdef COMPILE_I2C_DRIVER /************************************************************************* * Title: I2C master library using hardware TWI interface * Author: Peter Fleury http://jump.to/fleury * File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 * Target: any AVR device with hardware TWI * Usage: API compatible with I2C Software Library i2cmaster.h **************************************************************************/ #include #include /* I2C clock in Hz */ #define SCL_CLOCK UI_I2C_CLOCKSPEED /************************************************************************* Initialization of the I2C bus interface. Need to be called only once *************************************************************************/ inline void i2c_init(void) { /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */ uid.outputMask = UI_DISPLAY_I2C_OUTPUT_START_MASK; TWSR = 0; /* no prescaler */ TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */ #if UI_DISPLAY_I2C_CHIPTYPE==0 && BEEPER_TYPE==2 && BEEPER_PIN>=0 #if BEEPER_ADDRESS == UI_DISPLAY_I2C_ADDRESS uid.outputMask |= BEEPER_PIN #endif #endif #if UI_DISPLAY_I2C_CHIPTYPE==1 // set direction of pins i2c_start(UI_DISPLAY_I2C_ADDRESS+I2C_WRITE); i2c_write(0); // IODIRA i2c_write(~(UI_DISPLAY_I2C_OUTPUT_PINS & 255)); // i2c_stop(); // i2c_start(UI_DISPLAY_I2C_ADDRESS+I2C_WRITE); // i2c_write(1); // IODIRB i2c_write(~(UI_DISPLAY_I2C_OUTPUT_PINS >> 8)); i2c_stop(); // Set pullups according to UI_DISPLAY_I2C_PULLUP i2c_start(UI_DISPLAY_I2C_ADDRESS+I2C_WRITE); i2c_write(0x0C); // GPPUA i2c_write(UI_DISPLAY_I2C_PULLUP & 255); // i2c_stop(); // i2c_start(UI_DISPLAY_I2C_ADDRESS+I2C_WRITE); // i2c_write(0x0D); // GPPUB i2c_write(UI_DISPLAY_I2C_PULLUP >> 8); i2c_stop(); #endif }/* i2c_init */ /************************************************************************* Issues a start condition and sends address and transfer direction. return 0 = device accessible, 1= failed to access device *************************************************************************/ unsigned char i2c_start(unsigned char address) { uint8_t twst; // send START condition TWCR = (1<> 8); i2c_write(v & 255);i2c_write(v >> 8); #endif } void lcdWriteByte(byte c,byte rs) { #if UI_DISPLAY_I2C_CHIPTYPE==0 byte mod = (rs?UI_DISPLAY_RS_PIN:0) | uid.outputMask; // | (UI_DISPLAY_RW_PIN); #if UI_DISPLAY_D4_PIN==1 && UI_DISPLAY_D5_PIN==2 && UI_DISPLAY_D6_PIN==4 && UI_DISPLAY_D7_PIN==8 byte value = (c >> 4) | mod; i2c_write((value) | UI_DISPLAY_ENABLE_PIN); i2c_write(value); value = (c & 15) | mod; i2c_write((value) | UI_DISPLAY_ENABLE_PIN); i2c_write(value); #else byte value = (c & 16?UI_DISPLAY_D4_PIN:0)|(c & 32?UI_DISPLAY_D5_PIN:0)|(c & 64?UI_DISPLAY_D6_PIN:0)|(c & 128?UI_DISPLAY_D7_PIN:0) | mod; i2c_write((value) | UI_DISPLAY_ENABLE_PIN); i2c_write(value); value = (c & 1?UI_DISPLAY_D4_PIN:0)|(c & 2?UI_DISPLAY_D5_PIN:0)|(c & 4?UI_DISPLAY_D6_PIN:0)|(c & 8?UI_DISPLAY_D7_PIN:0) | mod; i2c_write((value) | UI_DISPLAY_ENABLE_PIN); i2c_write(value); #endif #endif #if UI_DISPLAY_I2C_CHIPTYPE==1 unsigned int mod = (rs?UI_DISPLAY_RS_PIN:0) | uid.outputMask; // | (UI_DISPLAY_RW_PIN); unsigned int value = (c & 16?UI_DISPLAY_D4_PIN:0)|(c & 32?UI_DISPLAY_D5_PIN:0)|(c & 64?UI_DISPLAY_D6_PIN:0)|(c & 128?UI_DISPLAY_D7_PIN:0) | mod; unsigned int value2 = (value) | UI_DISPLAY_ENABLE_PIN; i2c_write(value2 & 255);i2c_write(value2 >>8); i2c_write(value & 255);i2c_write(value>>8); value = (c & 1?UI_DISPLAY_D4_PIN:0)|(c & 2?UI_DISPLAY_D5_PIN:0)|(c & 4?UI_DISPLAY_D6_PIN:0)|(c & 8?UI_DISPLAY_D7_PIN:0) | mod; value2 = (value) | UI_DISPLAY_ENABLE_PIN; i2c_write(value2 & 255);i2c_write(value2 >>8); i2c_write(value & 255);i2c_write(value>>8); #endif } void initializeLCD() { delay(135); lcdStartWrite(); i2c_write(uid.outputMask & 255); #if UI_DISPLAY_I2C_CHIPTYPE==1 i2c_write(uid.outputMask >> 16); #endif delayMicroseconds(10); lcdWriteNibble(0x03); delayMicroseconds(5000); // I have one LCD for which 4500 here was not long enough. // second try lcdWriteNibble(0x03); delayMicroseconds(150); // wait // third go! lcdWriteNibble(0x03); delayMicroseconds(150); // finally, set to 4-bit interface lcdWriteNibble(0x02); delayMicroseconds(150); // finally, set # lines, font size, etc. lcdCommand(LCD_4BIT | LCD_2LINE | LCD_5X7); lcdCommand(LCD_CLEAR); //- Clear Screen delay(2); // clear is slow operation lcdCommand(LCD_INCREASE | LCD_DISPLAYSHIFTOFF); //- Entrymode (Display Shift: off, Increment Address Counter) lcdCommand(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGOFF); //- Display on uid.lastSwitch = uid.lastRefresh = millis(); uid.createChar(1,character_back); uid.createChar(2,character_degree); uid.createChar(3,character_selected); uid.createChar(4,character_unselected); uid.createChar(5,character_temperature); uid.createChar(6,character_folder); lcdStopWrite(); } #endif #if UI_DISPLAY_TYPE==1 || UI_DISPLAY_TYPE==2 void lcdWriteNibble(byte value) { WRITE(UI_DISPLAY_D4_PIN,value & 1); WRITE(UI_DISPLAY_D5_PIN,value & 2); WRITE(UI_DISPLAY_D6_PIN,value & 4); WRITE(UI_DISPLAY_D7_PIN,value & 8); WRITE(UI_DISPLAY_ENABLE_PIN, HIGH);// enable pulse must be >450ns __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); WRITE(UI_DISPLAY_ENABLE_PIN, LOW); __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); } void lcdWriteByte(byte c,byte rs) { #if UI_DISPLAY_RW_PIN<0 delayMicroseconds(UI_DELAYPERCHAR); #else SET_INPUT(UI_DISPLAY_D4_PIN); SET_INPUT(UI_DISPLAY_D5_PIN); SET_INPUT(UI_DISPLAY_D6_PIN); SET_INPUT(UI_DISPLAY_D7_PIN); WRITE(UI_DISPLAY_RW_PIN, HIGH); WRITE(UI_DISPLAY_RS_PIN, LOW); uint8_t busy; do { WRITE(UI_DISPLAY_ENABLE_PIN, HIGH); __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); busy = READ(UI_DISPLAY_D7_PIN); WRITE(UI_DISPLAY_ENABLE_PIN, LOW); __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); WRITE(UI_DISPLAY_ENABLE_PIN, HIGH); __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); WRITE(UI_DISPLAY_ENABLE_PIN, LOW); __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); } while (busy); SET_OUTPUT(UI_DISPLAY_D4_PIN); SET_OUTPUT(UI_DISPLAY_D5_PIN); SET_OUTPUT(UI_DISPLAY_D6_PIN); SET_OUTPUT(UI_DISPLAY_D7_PIN); WRITE(UI_DISPLAY_RW_PIN, LOW); #endif WRITE(UI_DISPLAY_RS_PIN, rs); WRITE(UI_DISPLAY_D4_PIN, c & 0x10); WRITE(UI_DISPLAY_D5_PIN, c & 0x20); WRITE(UI_DISPLAY_D6_PIN, c & 0x40); WRITE(UI_DISPLAY_D7_PIN, c & 0x80); WRITE(UI_DISPLAY_ENABLE_PIN, HIGH); // enable pulse must be >450ns __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); WRITE(UI_DISPLAY_ENABLE_PIN, LOW); __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); WRITE(UI_DISPLAY_D4_PIN, c & 0x01); WRITE(UI_DISPLAY_D5_PIN, c & 0x02); WRITE(UI_DISPLAY_D6_PIN, c & 0x04); WRITE(UI_DISPLAY_D7_PIN, c & 0x08); WRITE(UI_DISPLAY_ENABLE_PIN, HIGH); // enable pulse must be >450ns __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); WRITE(UI_DISPLAY_ENABLE_PIN, LOW); __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); } void initializeLCD() { // 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 before 4.5V. // is this delay long enough for all cases?? delay(135); SET_OUTPUT(UI_DISPLAY_D4_PIN); SET_OUTPUT(UI_DISPLAY_D5_PIN); SET_OUTPUT(UI_DISPLAY_D6_PIN); SET_OUTPUT(UI_DISPLAY_D7_PIN); SET_OUTPUT(UI_DISPLAY_RS_PIN); #if UI_DISPLAY_RW_PIN>-1 SET_OUTPUT(UI_DISPLAY_RW_PIN); #endif SET_OUTPUT(UI_DISPLAY_ENABLE_PIN); // Now we pull both RS and R/W low to begin commands WRITE(UI_DISPLAY_RS_PIN, LOW); WRITE(UI_DISPLAY_ENABLE_PIN, LOW); //put the LCD into 4 bit mode // this is according to the hitachi HD44780 datasheet // figure 24, pg 46 // we start in 8bit mode, try to set 4 bit mode // at this point we are in 8 bit mode but of course in this // interface 4 pins are dangling unconnected and the values // on them don't matter for these instructions. WRITE(UI_DISPLAY_RS_PIN, LOW); delayMicroseconds(10); lcdWriteNibble(0x03); delayMicroseconds(5000); // I have one LCD for which 4500 here was not long enough. // second try lcdWriteNibble(0x03); delayMicroseconds(150); // wait // third go! lcdWriteNibble(0x03); delayMicroseconds(150); // finally, set to 4-bit interface lcdWriteNibble(0x02); delayMicroseconds(150); // finally, set # lines, font size, etc. lcdCommand(LCD_4BIT | LCD_2LINE | LCD_5X7); lcdCommand(LCD_CLEAR); //- Clear Screen delay(2); // clear is slow operation lcdCommand(LCD_INCREASE | LCD_DISPLAYSHIFTOFF); //- Entrymode (Display Shift: off, Increment Address Counter) lcdCommand(LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKINGOFF); //- Display on uid.lastSwitch = uid.lastRefresh = millis(); uid.createChar(1,character_back); uid.createChar(2,character_degree); uid.createChar(3,character_selected); uid.createChar(4,character_unselected); uid.createChar(5,character_temperature); uid.createChar(6,character_folder); } // ----------- end direct LCD driver #endif #if UI_DISPLAY_TYPE==4 // Use LiquidCrystal library instead #include LiquidCrystal lcd(UI_DISPLAY_RS_PIN, UI_DISPLAY_RW_PIN,UI_DISPLAY_ENABLE_PIN,UI_DISPLAY_D4_PIN,UI_DISPLAY_D5_PIN,UI_DISPLAY_D6_PIN,UI_DISPLAY_D7_PIN); void UIDisplay::createChar(byte location,const byte charmap[]) { location &= 0x7; // we only have 8 locations 0-7 byte data[8]; for (int i=0; i<8; i++) { data[i]=pgm_read_byte(&(charmap[i])); } lcd.createChar(location, data); } void UIDisplay::printRow(byte r,char *txt) { byte col=0; // Set row if(r >= UI_ROWS) return; lcd.setCursor(0,r); char c; while(col0 initializeLCD(); uid.printRowP(0,versionString); uid.printRowP(1,versionString2); #endif #if BEEPER_TYPE==2 || defined(UI_HAS_I2C_KEYS) // Make sure the beeper is off i2c_start_wait(UI_I2C_KEY_ADDRESS+I2C_WRITE); i2c_write(255); // Disable beeper, enable read for other pins. i2c_stop(); #endif } #if UI_DISPLAY_TYPE==1 || UI_DISPLAY_TYPE==2 || UI_DISPLAY_TYPE==3 void UIDisplay::createChar(byte location,const byte PROGMEM charmap[]) { location &= 0x7; // we only have 8 locations 0-7 lcdCommand(LCD_SETCGRAMADDR | (location << 3)); for (int i=0; i<8; i++) { lcdPutChar(pgm_read_byte(&(charmap[i]))); } } void UIDisplay::printRow(byte r,char *txt) { byte col=0; // Set row if(r >= UI_ROWS) return; #if UI_DISPLAY_TYPE==3 lcdStartWrite(); #endif lcdWriteByte(128 + pgm_read_byte(&LCDLineOffsets[r]),0); // Position cursor char c; while(col0 ui_check_slow_encoder(); #endif } #endif void UIDisplay::printRowP(byte r,PGM_P txt) { if(r >= UI_ROWS) return; col=0; addStringP(txt); printCols[col]=0; printRow(r,printCols); } void UIDisplay::addInt(int value,byte digits) { byte dig=0,neg=0; if(value<0) { value = -value; neg=1; dig++; } char buf[7]; // Assumes 8-bit chars plus zero byte. char *str = &buf[6]; buf[6]=0; do { unsigned int m = value; value /= 10; char c = m - 10 * value; *--str = c + '0'; dig++; } while(value); if(neg) printCols[col++]='-'; if(digits<6) while(dig=UI_COLS) return; number = -number; fixdigits--; } number += pgm_read_float(&roundingTable[digits]); // for correct rounding // Extract the integer part of the number and print it unsigned long int_part = (unsigned long)number; float remainder = number - (float)int_part; addLong(int_part,fixdigits); if(col>=UI_COLS) return; // Print the decimal point, but only if there are digits beyond if (digits > 0) { printCols[col++]='.'; } // Extract digits from the remainder one at a time while (col 0) { remainder *= 10.0; byte toPrint = byte(remainder); printCols[col++] = '0'+toPrint; remainder -= toPrint; } } void UIDisplay::addStringP(PGM_P text) { while(coltempControl.currentTemperatureC; else if(c2>='0' && c2<='9') fvalue=extruder[c2-'0'].tempControl.currentTemperatureC; else if(c2=='b') fvalue=heated_bed_get_temperature(); else if(c2=='B') {ivalue=0;fvalue=heated_bed_get_temperature();} addFloat(fvalue,3,ivalue); break; case 'E': // Target extruder temperature if(c2=='c') fvalue=current_extruder->tempControl.targetTemperatureC; else if(c2>='0' && c2<='9') fvalue=extruder[c2-'0'].tempControl.targetTemperatureC; #if HAVE_HEATED_BED else if(c2=='b') fvalue=heatedBedController.targetTemperatureC; #endif addFloat(fvalue,3,0 /*UI_TEMP_PRECISION*/); break; case 'f': if(c2=='x') addFloat(max_feedrate[0],5,0); else if(c2=='y') addFloat(max_feedrate[1],5,0); else if(c2=='z') addFloat(max_feedrate[2],5,0); else if(c2=='X') addFloat(homing_feedrate[0],5,0); else if(c2=='Y') addFloat(homing_feedrate[1],5,0); else if(c2=='Z') addFloat(homing_feedrate[2],5,0); break; case 'i': if(c2=='s') addLong(stepper_inactive_time,4); else if(c2=='p') addLong(max_inactive_time,4); break; case 'O': // ops related stuff #if USE_OPS==1 if(c2=='0') addStringP(printer_state.opsMode==0?ui_selected:ui_unselected); else if(c2=='1') addStringP(printer_state.opsMode==1?ui_selected:ui_unselected); else if(c2=='2') addStringP(printer_state.opsMode==2?ui_selected:ui_unselected); else if(c2=='r') addFloat(printer_state.opsRetractDistance,2,1); else if(c2=='b') addFloat(printer_state.opsRetractBacklash,2,1); else if(c2=='d') addFloat(printer_state.opsMinDistance,2,1); else if(c2=='a') { addFloat(printer_state.opsMoveAfter,3,0); if(col>8)*100/(sd.filesize>>8); addInt((int)percent,3); if(col='0' && c2<='9') ivalue=pwm_pos[c2-'0']; #if HAVE_HEATED_BED else if(c2=='b') ivalue=pwm_pos[heatedBedController.pwmIndex]; #endif else if(c2=='C') ivalue=pwm_pos[current_extruder->id]; ivalue=(ivalue*100)/255; addInt(ivalue,3); if(col='0' && c2<='3') #if NUM_EXTRUDER>0 if(c2=='0') fvalue = (float)(printer_state.currentPositionSteps[c2-'0']+current_extruder->xOffset)*inv_axis_steps_per_unit[c2-'0']; else if(c2=='1') fvalue = (float)(printer_state.currentPositionSteps[c2-'0']+current_extruder->yOffset)*inv_axis_steps_per_unit[c2-'0']; else fvalue = (float)printer_state.currentPositionSteps[c2-'0']*inv_axis_steps_per_unit[c2-'0']; #else fvalue = (float)printer_state.currentPositionSteps[c2-'0']*inv_axis_steps_per_unit[c2-'0']; #endif addFloat(fvalue,3,2); break; case 'y': #if DRIVE_SYSTEM==3 if(c2>='0' && c2<='3') fvalue = (float)printer_state.currentDeltaPositionSteps[c2-'0']*inv_axis_steps_per_unit[c2-'0']; addFloat(fvalue,3,2); #endif break; case 'X': // Extruder related #if NUM_EXTRUDER>0 if(c2>='0' && c2<='9') {addStringP(current_extruder->id==c2-'0'?ui_selected:ui_unselected);} #ifdef TEMP_PID else if(c2=='i') {addFloat(current_extruder->tempControl.pidIGain,4,2);} else if(c2=='p') {addFloat(current_extruder->tempControl.pidPGain,4,2);} else if(c2=='d') {addFloat(current_extruder->tempControl.pidDGain,4,2);} else if(c2=='m') {addInt(current_extruder->tempControl.pidDriveMin,3);} else if(c2=='M') {addInt(current_extruder->tempControl.pidDriveMax,3);} else if(c2=='D') {addInt(current_extruder->tempControl.pidMax,3);} #endif else if(c2=='w') {addInt(current_extruder->watchPeriod,4);} #if RETRACT_DURING_HEATUP else if(c2=='T') {addInt(current_extruder->waitRetractTemperature,4);} else if(c2=='U') {addInt(current_extruder->waitRetractUnits,2);} #endif else if(c2=='h') {addStringP(!current_extruder->tempControl.heatManager?PSTR(UI_TEXT_STRING_HM_BANGBANG):PSTR(UI_TEXT_STRING_HM_PID));} #ifdef USE_ADVANCE #ifdef ENABLE_QUADRATIC_ADVANCE else if(c2=='a') {addFloat(current_extruder->advanceK,3,0);} #endif else if(c2=='l') {addFloat(current_extruder->advanceL,3,0);} #endif else if(c2=='x') {addFloat(current_extruder->xOffset,4,2);} else if(c2=='y') {addFloat(current_extruder->yOffset,4,2);} else if(c2=='f') {addFloat(current_extruder->maxStartFeedrate,5,0);} else if(c2=='F') {addFloat(current_extruder->maxFeedrate,5,0);} else if(c2=='A') {addFloat(current_extruder->maxAcceleration,5,0);} #endif break; case 's': // Endstop positions if(c2=='x') { #if (X_MIN_PIN > -1) && MIN_HARDWARE_ENDSTOP_X addStringP((READ(X_MIN_PIN)^ENDSTOP_X_MIN_INVERTING)?ui_text_on:ui_text_off); #else addStringP(ui_text_na); #endif } if(c2=='X') #if (X_MAX_PIN > -1) && MAX_HARDWARE_ENDSTOP_X addStringP((READ(X_MAX_PIN)^ENDSTOP_X_MAX_INVERTING)?ui_text_on:ui_text_off); #else addStringP(ui_text_na); #endif if(c2=='y') #if (Y_MIN_PIN > -1)&& MIN_HARDWARE_ENDSTOP_Y addStringP((READ(Y_MIN_PIN)^ENDSTOP_Y_MIN_INVERTING)?ui_text_on:ui_text_off); #else addStringP(ui_text_na); #endif if(c2=='Y') #if (Y_MAX_PIN > -1) && MAX_HARDWARE_ENDSTOP_Y addStringP((READ(Y_MAX_PIN)^ENDSTOP_Y_MAX_INVERTING)?ui_text_on:ui_text_off); #else addStringP(ui_text_na); #endif if(c2=='z') #if (Z_MIN_PIN > -1) && MIN_HARDWARE_ENDSTOP_Z addStringP((READ(Z_MIN_PIN)^ENDSTOP_Z_MIN_INVERTING)?ui_text_on:ui_text_off); #else addStringP(ui_text_na); #endif if(c2=='Z') #if (Z_MAX_PIN > -1) && MAX_HARDWARE_ENDSTOP_Z addStringP((READ(Z_MAX_PIN)^ENDSTOP_Z_MAX_INVERTING)?ui_text_on:ui_text_off); #else addStringP(ui_text_na); #endif break; case 'S': if(c2=='x') addFloat(axis_steps_per_unit[0],3,1); if(c2=='y') addFloat(axis_steps_per_unit[1],3,1); if(c2=='z') addFloat(axis_steps_per_unit[2],3,1); if(c2=='e') addFloat(current_extruder->stepsPerMM,3,1); break; } } printCols[col] = 0; } void UIDisplay::setStatusP(PGM_P txt) { byte i=0; while(i<16) { byte c = pgm_read_byte(txt++); if(!c) break; statusMsg[i++] = c; } statusMsg[i]=0; } void UIDisplay::setStatus(char *txt) { byte i=0; while(*txt && i<16) statusMsg[i++] = *txt++; statusMsg[i]=0; } const UIMenu * const ui_pages[UI_NUM_PAGES] PROGMEM = UI_PAGES; #if SDSUPPORT byte nFilesOnCard; void UIDisplay::updateSDFileCount() { dir_t* p; byte offset = menuTop[menuLevel]; SdBaseFile *root = sd.fat.vwd(); root->rewind(); nFilesOnCard = 0; while ((p = root->readDirCache())) { // done if past last used entry if (p->name[0] == DIR_NAME_FREE) break; // skip deleted entry and entries for . and .. if(!sd.showFilename(p->name) && !(p->name[0]=='.' && p->name[1]=='.')) continue; // only list subdirectories and files if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; if(folderLevel>=SD_MAX_FOLDER_DEPTH && DIR_IS_SUBDIR(p) && !(p->name[0]=='.' && p->name[1]=='.')) continue; nFilesOnCard++; if(nFilesOnCard==254) return; } } void getSDFilenameAt(byte filePos,char *filename) { dir_t* p; byte c=0; SdBaseFile *root = sd.fat.vwd(); root->rewind(); while ((p = root->readDirCache())) { // done if past last used entry if (p->name[0] == DIR_NAME_FREE) break; // skip deleted entry and entries for . and .. if(!sd.showFilename(p->name) && !(p->name[0]=='.' && p->name[1]=='.')) continue; // only list subdirectories and files if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; if(uid.folderLevel>=SD_MAX_FOLDER_DEPTH && DIR_IS_SUBDIR(p) && !(p->name[0]=='.' && p->name[1]=='.')) continue; if(filePos) { filePos--; continue; } for (uint8_t i = 0; i < 11; i++) { if (p->name[i] == ' ')continue; if (i == 8) filename[c++]='.'; filename[c++]=tolower(p->name[i]); } if(DIR_IS_SUBDIR(p)) filename[c++]='/'; // Set marker for directory break; } filename[c]=0; } bool UIDisplay::isDirname(char *name) { while(*name) name++; name--; return *name=='/'; } void UIDisplay::goDir(char *name) { char *p = cwd; while(*p)p++; if(name[0]=='.' && name[1]=='.') { if(folderLevel==0) return; p--;p--; while(*p!='/') p--; p++; *p = 0; folderLevel--; } else { if(folderLevel>=SD_MAX_FOLDER_DEPTH) return; while(*name) *p++ = *name++; *p = 0; folderLevel++; } sd.fat.chdir(cwd); updateSDFileCount(); } void UIDisplay::sdrefresh(byte &r) { dir_t* p; byte offset = menuTop[menuLevel]; sd.fat.chdir(cwd); SdBaseFile *root = sd.fat.vwd(); root->rewind(); byte skip = (offset>0?offset-1:0); while (r+offsetreadDirCache())) { // done if past last used entry if (p->name[0] == DIR_NAME_FREE) break; // skip deleted entry and entries for . and .. if(!sd.showFilename(p->name) && !(p->name[0]=='.' && p->name[1]=='.')) continue; // only list subdirectories and files if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; if(folderLevel>=SD_MAX_FOLDER_DEPTH && DIR_IS_SUBDIR(p) && !(p->name[0]=='.' && p->name[1]=='.')) continue; if(skip>0) {skip--;continue;} col=0; if(r+offset==menuPos[menuLevel]) printCols[col++]='>'; else printCols[col++]=' '; // print file name with possible blank fill if(DIR_IS_SUBDIR(p)) printCols[col++] = 6; // Prepend folder symbol else printCols[col++] = ' '; for (byte i = 0; i < 11; i++) { if (p->name[i] == ' ')continue; if (i == 8) printCols[col++]='.'; printCols[col++]=tolower(p->name[i]); } printCols[col]=0; printRow(r,printCols); r++; } } #endif // Refresh current menu page void UIDisplay::refreshPage() { byte r; byte mtype; if(menuLevel==0) { UIMenu *men = (UIMenu*)pgm_read_word(&(ui_pages[menuPos[0]])); byte nr = pgm_read_word_near(&(men->numEntries)); UIMenuEntry **entries = (UIMenuEntry**)pgm_read_word(&(men->entries)); for(r=0;rtext)),false); printRow(r,(char*)printCols); } } else { UIMenu *men = (UIMenu*)menu[menuLevel]; byte nr = pgm_read_word_near((void*)&(men->numEntries)); mtype = pgm_read_byte((void*)&(men->menuType)); byte offset = menuTop[menuLevel]; UIMenuEntry **entries = (UIMenuEntry**)pgm_read_word(&(men->entries)); for(r=0;r+offsetmenuType)); unsigned int entAction = pgm_read_word(&(ent->action)); col=0; if(entType>=2 && entType<=4) { if(r+offset==menuPos[menuLevel] && activeAction!=entAction) printCols[col++]=CHAR_SELECTOR; else if(activeAction==entAction) printCols[col++]=CHAR_SELECTED; else printCols[col++]=' '; } parse((char*)pgm_read_word(&(ent->text)),false); if(entType==2) { // Draw submenu marker at the right side while(colmenuType))==1) // Open files list updateSDFileCount(); #endif if(refresh) refreshPage(); } void UIDisplay::okAction() { #if UI_HAS_KEYS==1 if(menuLevel==0) { // Enter menu menuLevel = 1; menuTop[1] = menuPos[1] = 0; menu[1] = (void*)&ui_menu_main; BEEP_SHORT return; } UIMenu *men = (UIMenu*)menu[menuLevel]; //byte nr = pgm_read_word_near(&(menu->numEntries)); byte mtype = pgm_read_byte(&(men->menuType)); UIMenuEntry **entries = (UIMenuEntry**)pgm_read_word(&(men->entries)); UIMenuEntry *ent =(UIMenuEntry *)pgm_read_word(&(entries[menuPos[menuLevel]])); unsigned char entType = pgm_read_byte(&(ent->menuType));// 0 = Info, 1 = Headline, 2 = submenu ref, 3 = direct action command, 4 = modify action int action = pgm_read_word(&(ent->action)); if(mtype==3) { // action menu action = pgm_read_word(&(men->id)); finishAction(action); executeAction(UI_ACTION_BACK); return; } if(mtype==2 && entType==4) { // Modify action if(activeAction) { // finish action finishAction(action); activeAction = 0; } else activeAction = action; return; } #if SDSUPPORT if(mtype==1) { if(menuPos[menuLevel]==0) { // Selected back instead of file executeAction(UI_ACTION_BACK); return; } byte filePos = menuPos[menuLevel]-1; char filename[14]; getSDFilenameAt(filePos,filename); if(isDirname(filename)) { // Directory change selected goDir(filename); menuTop[menuLevel]=0; menuPos[menuLevel]=1; refreshPage(); return; } menuLevel--; men = (UIMenu*)menu[menuLevel]; entries = (UIMenuEntry**)pgm_read_word(&(men->entries)); ent =(UIMenuEntry *)pgm_read_word(&(entries[menuPos[menuLevel]])); switch(pgm_read_word(&(ent->action))) { case UI_ACTION_SD_PRINT: if(sd.sdactive){ sd.sdmode = false; sd.file.close(); if (sd.file.open(filename, O_READ)) { OUT_P("File opened:"); out.print(filename); OUT_P(" Size:"); out.println(sd.file.fileSize()); sd.sdpos = 0; sd.filesize = sd.file.fileSize(); OUT_P_LN("File selected"); sd.sdmode = true; // Start print immediately menuLevel = 0; BEEP_LONG; } else{ OUT_P_LN("file.open failed"); } } break; case UI_ACTION_SD_DELETE: if(sd.sdactive){ sd.sdmode = false; sd.file.close(); if(sd.fat.remove(filename)) { OUT_P_LN("File deleted"); BEEP_LONG } else { OUT_P_LN("Deletion failed"); } } break; } } #endif if(entType==2) { // Enter submenu pushMenu((void*)action,false); BEEP_SHORT return; } if(entType==3) { executeAction(action); return; } executeAction(UI_ACTION_BACK); #endif } #define INCREMENT_MIN_MAX(a,steps,_min,_max) a+=increment*steps;if(a<(_min)) a=_min;else if(a>(_max)) a=_max; void UIDisplay::nextPreviousAction(char next) { #if UI_HAS_KEYS==1 if(menuLevel==0) { lastSwitch = millis(); if((UI_INVERT_MENU_DIRECTION && next<0) || (!UI_INVERT_MENU_DIRECTION && next>0)) { menuPos[0]++; if(menuPos[0]>=UI_NUM_PAGES) menuPos[0]=0; } else { if(menuPos[0]==0) menuPos[0]=UI_NUM_PAGES-1; else menuPos[0]--; } return; } UIMenu *men = (UIMenu*)menu[menuLevel]; byte nr = pgm_read_word_near(&(men->numEntries)); byte mtype = pgm_read_byte(&(men->menuType)); UIMenuEntry **entries = (UIMenuEntry**)pgm_read_word(&(men->entries)); UIMenuEntry *ent =(UIMenuEntry *)pgm_read_word(&(entries[menuPos[menuLevel]])); unsigned char entType = pgm_read_byte(&(ent->menuType));// 0 = Info, 1 = Headline, 2 = submenu ref, 3 = direct action command int action = pgm_read_word(&(ent->action)); if(mtype==2 && activeAction==0) { // browse through menu items if((UI_INVERT_MENU_DIRECTION && next<0) || (!UI_INVERT_MENU_DIRECTION && next>0)) { if(menuPos[menuLevel]+10) menuPos[menuLevel]--; if(menuTop[menuLevel]>menuPos[menuLevel]) menuTop[menuLevel]=menuPos[menuLevel]; else if(menuTop[menuLevel]+UI_ROWS-10)) { if(menuPos[menuLevel]0) menuPos[menuLevel]--; if(menuTop[menuLevel]>menuPos[menuLevel]) menuTop[menuLevel]=menuPos[menuLevel]; else if(menuTop[menuLevel]+UI_ROWS-1id)); else action=activeAction; char increment = next; switch(action) { case UI_ACTION_XPOSITION: move_steps(increment,0,0,0,homing_feedrate[0],true,true); printPosition(); break; case UI_ACTION_YPOSITION: move_steps(0,increment,0,0,homing_feedrate[1],true,true); printPosition(); break; case UI_ACTION_ZPOSITION: move_steps(0,0,increment,0,homing_feedrate[2],true,true); printPosition(); break; case UI_ACTION_XPOSITION_FAST: move_steps(axis_steps_per_unit[0]*increment,0,0,0,homing_feedrate[0],true,true); printPosition(); break; case UI_ACTION_YPOSITION_FAST: move_steps(0,axis_steps_per_unit[1]*increment,0,0,homing_feedrate[1],true,true); printPosition(); break; case UI_ACTION_ZPOSITION_FAST: move_steps(0,0,axis_steps_per_unit[2]*increment,0,homing_feedrate[2],true,true); printPosition(); break; case UI_ACTION_EPOSITION: move_steps(0,0,0,axis_steps_per_unit[3]*increment,UI_SET_EXTRUDER_FEEDRATE,true,false); printPosition(); break; case UI_ACTION_HEATED_BED_TEMP: #if HAVE_HEATED_BED==true { int tmp = (int)heatedBedController.targetTemperatureC; if(tmpUI_SET_MAX_HEATED_BED_TEMP) tmp = UI_SET_MAX_HEATED_BED_TEMP; heated_bed_set_temperature(tmp); } #endif break; case UI_ACTION_EXTRUDER0_TEMP: { int tmp = (int)extruder[0].tempControl.targetTemperatureC; if(tmpUI_SET_MAX_EXTRUDER_TEMP) tmp = UI_SET_MAX_EXTRUDER_TEMP; extruder_set_temperature(tmp,0); } break; case UI_ACTION_EXTRUDER1_TEMP: #if NUM_EXTRUDER>1 { int tmp = (int)extruder[1].tempControl.targetTemperatureC; tmp+=increment; if(tmp==1) tmp = UI_SET_MIN_EXTRUDER_TEMP; if(tmpUI_SET_MAX_EXTRUDER_TEMP) tmp = UI_SET_MAX_EXTRUDER_TEMP; extruder_set_temperature(tmp,1); } #endif break; #if USE_OPS==1 case UI_ACTION_OPS_RETRACTDISTANCE: printer_state.opsRetractDistance+=increment*0.1; if(printer_state.opsRetractDistance<0) printer_state.opsRetractDistance=0; else if(printer_state.opsRetractDistance>10) printer_state.opsRetractDistance=10; extruder_select(current_extruder->id); break; case UI_ACTION_OPS_BACKLASH: printer_state.opsRetractBacklash+=increment*0.1; if(printer_state.opsRetractBacklash<-5) printer_state.opsRetractBacklash=-5; else if(printer_state.opsRetractBacklash>5) printer_state.opsRetractBacklash=5; extruder_select(current_extruder->id); break; case UI_ACTION_OPS_MOVE_AFTER: printer_state.opsMoveAfter+=increment; if(printer_state.opsMoveAfter<0) printer_state.opsMoveAfter=0; else if(printer_state.opsMoveAfter>10) printer_state.opsMoveAfter=100; extruder_select(current_extruder->id); break; case UI_ACTION_OPS_MINDISTANCE: printer_state.opsMinDistance+=increment; if(printer_state.opsMinDistance<0) printer_state.opsMinDistance=0; else if(printer_state.opsMinDistance>10) printer_state.opsMinDistance=10; extruder_select(current_extruder->id); break; #endif case UI_ACTION_FEEDRATE_MULTIPLY: { int fr = printer_state.feedrateMultiply; INCREMENT_MIN_MAX(fr,1,25,500); change_feedrate_multiply(fr); } break; case UI_ACTION_FLOWRATE_MULTIPLY: { INCREMENT_MIN_MAX(printer_state.extrudeMultiply,1,25,500); OUT_P_I_LN("FlowrateMultiply:",printer_state.extrudeMultiply); } break; case UI_ACTION_STEPPER_INACTIVE: INCREMENT_MIN_MAX(stepper_inactive_time,60,0,9999); break; case UI_ACTION_MAX_INACTIVE: INCREMENT_MIN_MAX(max_inactive_time,60,0,9999); break; case UI_ACTION_PRINT_ACCEL_X: INCREMENT_MIN_MAX(max_acceleration_units_per_sq_second[0],100,0,10000); update_ramps_parameter(); break; case UI_ACTION_PRINT_ACCEL_Y: INCREMENT_MIN_MAX(max_acceleration_units_per_sq_second[1],100,0,10000); update_ramps_parameter(); break; case UI_ACTION_PRINT_ACCEL_Z: INCREMENT_MIN_MAX(max_acceleration_units_per_sq_second[2],100,0,10000); update_ramps_parameter(); break; case UI_ACTION_MOVE_ACCEL_X: INCREMENT_MIN_MAX(max_travel_acceleration_units_per_sq_second[0],100,0,10000); update_ramps_parameter(); break; case UI_ACTION_MOVE_ACCEL_Y: INCREMENT_MIN_MAX(max_travel_acceleration_units_per_sq_second[1],100,0,10000); update_ramps_parameter(); break; case UI_ACTION_MOVE_ACCEL_Z: INCREMENT_MIN_MAX(max_travel_acceleration_units_per_sq_second[2],100,0,10000); update_ramps_parameter(); break; case UI_ACTION_MAX_JERK: INCREMENT_MIN_MAX(printer_state.maxJerk,0.1,1,99.9); break; case UI_ACTION_MAX_ZJERK: INCREMENT_MIN_MAX(printer_state.maxZJerk,0.1,0.1,99.9); break; case UI_ACTION_HOMING_FEEDRATE_X: INCREMENT_MIN_MAX(homing_feedrate[0],1,5,1000); break; case UI_ACTION_HOMING_FEEDRATE_Y: INCREMENT_MIN_MAX(homing_feedrate[1],1,5,1000); break; case UI_ACTION_HOMING_FEEDRATE_Z: INCREMENT_MIN_MAX(homing_feedrate[2],1,1,1000); break; case UI_ACTION_MAX_FEEDRATE_X: INCREMENT_MIN_MAX(max_feedrate[0],1,1,1000); break; case UI_ACTION_MAX_FEEDRATE_Y: INCREMENT_MIN_MAX(max_feedrate[1],1,1,1000); break; case UI_ACTION_MAX_FEEDRATE_Z: INCREMENT_MIN_MAX(max_feedrate[2],1,1,1000); break; case UI_ACTION_STEPS_X: INCREMENT_MIN_MAX(axis_steps_per_unit[0],0.1,0,999); update_ramps_parameter(); break; case UI_ACTION_STEPS_Y: INCREMENT_MIN_MAX(axis_steps_per_unit[1],0.1,0,999); update_ramps_parameter(); break; case UI_ACTION_STEPS_Z: INCREMENT_MIN_MAX(axis_steps_per_unit[2],0.1,0,999); update_ramps_parameter(); break; case UI_ACTION_BAUDRATE: #if EEPROM_MODE!=0 { char p=0; long rate; do { rate = pgm_read_dword(&(baudrates[p])); if(rate==baudrate) break; p++; } while(rate!=0); if(rate==0) p-=2; p+=increment; if(p<0) p = 0; rate = pgm_read_dword(&(baudrates[p])); if(rate==0) p--; baudrate = pgm_read_dword(&(baudrates[p])); } #endif break; #ifdef TEMP_PID case UI_ACTION_PID_PGAIN: INCREMENT_MIN_MAX(current_extruder->tempControl.pidPGain,0.1,0,200); break; case UI_ACTION_PID_IGAIN: INCREMENT_MIN_MAX(current_extruder->tempControl.pidIGain,0.01,0,100); extruder_select(current_extruder->id); break; case UI_ACTION_PID_DGAIN: INCREMENT_MIN_MAX(current_extruder->tempControl.pidDGain,0.1,0,200); break; case UI_ACTION_DRIVE_MIN: INCREMENT_MIN_MAX(current_extruder->tempControl.pidDriveMin,1,1,255); break; case UI_ACTION_DRIVE_MAX: INCREMENT_MIN_MAX(current_extruder->tempControl.pidDriveMax,1,1,255); break; case UI_ACTION_PID_MAX: INCREMENT_MIN_MAX(current_extruder->tempControl.pidMax,1,1,255); break; #endif case UI_ACTION_X_OFFSET: INCREMENT_MIN_MAX(current_extruder->xOffset,1,-99999,99999); extruder_select(current_extruder->id); break; case UI_ACTION_Y_OFFSET: INCREMENT_MIN_MAX(current_extruder->yOffset,1,-99999,99999); extruder_select(current_extruder->id); break; case UI_ACTION_EXTR_STEPS: INCREMENT_MIN_MAX(current_extruder->stepsPerMM,1,1,9999); extruder_select(current_extruder->id); break; case UI_ACTION_EXTR_ACCELERATION: INCREMENT_MIN_MAX(current_extruder->maxAcceleration,10,10,99999); extruder_select(current_extruder->id); break; case UI_ACTION_EXTR_MAX_FEEDRATE: INCREMENT_MIN_MAX(current_extruder->maxFeedrate,1,1,999); extruder_select(current_extruder->id); break; case UI_ACTION_EXTR_START_FEEDRATE: INCREMENT_MIN_MAX(current_extruder->maxStartFeedrate,1,1,999); extruder_select(current_extruder->id); break; case UI_ACTION_EXTR_HEATMANAGER: INCREMENT_MIN_MAX(current_extruder->tempControl.heatManager,1,0,1); break; case UI_ACTION_EXTR_WATCH_PERIOD: INCREMENT_MIN_MAX(current_extruder->watchPeriod,1,0,999); break; #if RETRACT_DURING_HEATUP case UI_ACTION_EXTR_WAIT_RETRACT_TEMP: INCREMENT_MIN_MAX(current_extruder->waitRetractTemperature,1,100,UI_SET_MAX_EXTRUDER_TEMP); break; case UI_ACTION_EXTR_WAIT_RETRACT_UNITS: INCREMENT_MIN_MAX(current_extruder->waitRetractUnits,1,0,99); break; #endif #ifdef USE_ADVANCE #ifdef ENABLE_QUADRATIC_ADVANCE case UI_ACTION_ADVANCE_K: INCREMENT_MIN_MAX(current_extruder->advanceK,1,0,200); break; #endif case UI_ACTION_ADVANCE_L: INCREMENT_MIN_MAX(current_extruder->advanceL,1,0,600); break; #endif } #if UI_AUTORETURN_TO_MENU_AFTER!=0 ui_autoreturn_time=millis()+UI_AUTORETURN_TO_MENU_AFTER; #endif #endif } void UIDisplay::finishAction(int action) { } // Actions are events from user input. Depending on the current state, each // action can behave differently. Other actions do always the same like home, disable extruder etc. void UIDisplay::executeAction(int action) { #if UI_HAS_KEYS==1 bool skipBeep = false; if(action & UI_ACTION_TOPMENU) { // Go to start menu action -= UI_ACTION_TOPMENU; menuLevel = 0; } if(action>=2000 && action<3000) { setStatusP(ui_action); } else switch(action) { case UI_ACTION_OK: okAction(); skipBeep=true; // Prevent double beep break; case UI_ACTION_BACK: if(menuLevel>0) menuLevel--; activeAction = 0; break; case UI_ACTION_NEXT: nextPreviousAction(1); break; case UI_ACTION_PREVIOUS: nextPreviousAction(-1); break; case UI_ACTION_MENU_UP: if(menuLevel>0) menuLevel--; break; case UI_ACTION_TOP_MENU: menuLevel = 0; break; case UI_ACTION_EMERGENCY_STOP: emergencyStop(); break; case UI_ACTION_HOME_ALL: home_axis(true,true,true); printPosition(); break; case UI_ACTION_HOME_X: home_axis(true,false,false); printPosition(); break; case UI_ACTION_HOME_Y: home_axis(false,true,false); printPosition(); break; case UI_ACTION_HOME_Z: home_axis(false,false,true); printPosition(); break; case UI_ACTION_SET_ORIGIN: printer_state.currentPositionSteps[0] = -printer_state.offsetX; printer_state.currentPositionSteps[1] = -printer_state.offsetY; printer_state.currentPositionSteps[2] = 0; break; case UI_ACTION_DEBUG_ECHO: if(DEBUG_ECHO) debug_level-=1;else debug_level+=1; break; case UI_ACTION_DEBUG_INFO: if(DEBUG_INFO) debug_level-=2;else debug_level+=2; break; case UI_ACTION_DEBUG_ERROR: if(DEBUG_ERRORS) debug_level-=4;else debug_level+=4; break; case UI_ACTION_DEBUG_DRYRUN: if(DEBUG_DRYRUN) debug_level-=8;else debug_level+=8; if(DEBUG_DRYRUN) { // simulate movements without printing extruder_set_temperature(0,0); #if NUM_EXTRUDER>1 extruder_set_temperature(0,1); #endif #if HAVE_HEATED_BED==true heated_bed_set_temperature(0); #endif } break; case UI_ACTION_POWER: break; case UI_ACTION_PREHEAT_PLA: UI_STATUS(UI_TEXT_PREHEAT_PLA); extruder_set_temperature(UI_SET_PRESET_EXTRUDER_TEMP_PLA,0); #if NUM_EXTRUDER>1 extruder_set_temperature(UI_SET_PRESET_EXTRUDER_TEMP_PLA,1); #endif #if HAVE_HEATED_BED==true heated_bed_set_temperature(UI_SET_PRESET_HEATED_BED_TEMP_PLA); #endif break; case UI_ACTION_PREHEAT_ABS: UI_STATUS(UI_TEXT_PREHEAT_ABS); extruder_set_temperature(UI_SET_PRESET_EXTRUDER_TEMP_ABS,0); #if NUM_EXTRUDER>1 extruder_set_temperature(UI_SET_PRESET_EXTRUDER_TEMP_ABS,1); #endif #if HAVE_HEATED_BED==true heated_bed_set_temperature(UI_SET_PRESET_HEATED_BED_TEMP_ABS); #endif break; case UI_ACTION_COOLDOWN: UI_STATUS(UI_TEXT_COOLDOWN); extruder_set_temperature(0,0); #if NUM_EXTRUDER>1 extruder_set_temperature(0,1); #endif #if HAVE_HEATED_BED==true heated_bed_set_temperature(0); #endif break; case UI_ACTION_HEATED_BED_OFF: #if HAVE_HEATED_BED==true heated_bed_set_temperature(0); #endif break; case UI_ACTION_EXTRUDER0_OFF: extruder_set_temperature(0,0); break; case UI_ACTION_EXTRUDER1_OFF: #if NUM_EXTRUDER>1 extruder_set_temperature(0,1); #endif break; #if USE_OPS==1 case UI_ACTION_OPS_OFF: printer_state.opsMode=0; break; case UI_ACTION_OPS_CLASSIC: printer_state.opsMode=1; break; case UI_ACTION_OPS_FAST: printer_state.opsMode=2; break; #endif case UI_ACTION_DISABLE_STEPPER: kill(true); break; case UI_ACTION_RESET_EXTRUDER: printer_state.currentPositionSteps[3] = 0; break; case UI_ACTION_EXTRUDER_RELATIVE: relative_mode_e=!relative_mode_e; break; case UI_ACTION_SELECT_EXTRUDER0: extruder_select(0); break; case UI_ACTION_SELECT_EXTRUDER1: #if NUM_EXTRUDER>1 extruder_select(1); #endif break; #if EEPROM_MODE!=0 case UI_ACTION_STORE_EEPROM: epr_data_to_eeprom(false); pushMenu((void*)&ui_menu_eeprom_saved,false); BEEP_LONG;skipBeep = true; break; case UI_ACTION_LOAD_EEPROM: epr_eeprom_to_data(); pushMenu((void*)&ui_menu_eeprom_loaded,false); BEEP_LONG;skipBeep = true; break; #endif #if SDSUPPORT case UI_ACTION_SD_DELETE: if(sd.sdactive){ pushMenu((void*)&ui_menu_sd_fileselector,false); } else { UI_ERROR(UI_TEXT_NOSDCARD); } break; case UI_ACTION_SD_PRINT: if(sd.sdactive){ pushMenu((void*)&ui_menu_sd_fileselector,false); } break; case UI_ACTION_SD_PAUSE: if(sd.sdmode){ sd.sdmode = false; } break; case UI_ACTION_SD_CONTINUE: if(sd.sdactive){ sd.sdmode = true; } break; case UI_ACTION_SD_UNMOUNT: sd.sdmode = false; sd.sdactive = false; break; case UI_ACTION_SD_MOUNT: sd.sdmode = false; sd.initsd(); break; case UI_ACTION_MENU_SDCARD: pushMenu((void*)&ui_menu_sd,false); break; #endif #if FAN_PIN>-1 case UI_ACTION_FAN_OFF: set_fan_speed(0,false); OUT_P_LN("Fanspeed:0"); break; case UI_ACTION_FAN_25: set_fan_speed(64,false); OUT_P_LN("Fanspeed:64"); break; case UI_ACTION_FAN_50: set_fan_speed(128,false); OUT_P_LN("Fanspeed:128"); break; case UI_ACTION_FAN_75: set_fan_speed(192,false); OUT_P_LN("Fanspeed:192"); break; case UI_ACTION_FAN_FULL: set_fan_speed(255,false); OUT_P_LN("Fanspeed:255"); break; #endif case UI_ACTION_MENU_XPOS: pushMenu((void*)&ui_menu_xpos,false); break; case UI_ACTION_MENU_YPOS: pushMenu((void*)&ui_menu_ypos,false); break; case UI_ACTION_MENU_ZPOS: pushMenu((void*)&ui_menu_zpos,false); break; case UI_ACTION_MENU_XPOSFAST: pushMenu((void*)&ui_menu_xpos_fast,false); break; case UI_ACTION_MENU_YPOSFAST: pushMenu((void*)&ui_menu_ypos_fast,false); break; case UI_ACTION_MENU_ZPOSFAST: pushMenu((void*)&ui_menu_zpos_fast,false); break; case UI_ACTION_MENU_QUICKSETTINGS: pushMenu((void*)&ui_menu_quick,false); break; case UI_ACTION_MENU_EXTRUDER: pushMenu((void*)&ui_menu_extruder,false); break; case UI_ACTION_MENU_POSITIONS: pushMenu((void*)&ui_menu_positions,false); break; #ifdef UI_USERMENU1 case UI_ACTION_SHOW_USERMENU1: pushMenu((void*)&UI_USERMENU1,false); break; #endif #ifdef UI_USERMENU2 case UI_ACTION_SHOW_USERMENU2: pushMenu((void*)&UI_USERMENU2,false); break; #endif #ifdef UI_USERMENU3 case UI_ACTION_SHOW_USERMENU3: pushMenu((void*)&UI_USERMENU3,false); break; #endif #ifdef UI_USERMENU4 case UI_ACTION_SHOW_USERMENU4: pushMenu((void*)&UI_USERMENU4,false); break; #endif #ifdef UI_USERMENU5 case UI_ACTION_SHOW_USERMENU5: pushMenu((void*)&UI_USERMENU5,false); break; #endif #ifdef UI_USERMENU6 case UI_ACTION_SHOW_USERMENU6: pushMenu((void*)&UI_USERMENU6,false); break; #endif #ifdef UI_USERMENU7 case UI_ACTION_SHOW_USERMENU7: pushMenu((void*)&UI_USERMENU7,false); break; #endif #ifdef UI_USERMENU8 case UI_ACTION_SHOW_USERMENU8: pushMenu((void*)&UI_USERMENU8,false); break; #endif #ifdef UI_USERMENU9 case UI_ACTION_SHOW_USERMENU9: pushMenu((void*)&UI_USERMENU9,false); break; #endif #ifdef UI_USERMENU10 case UI_ACTION_SHOW_USERMENU10: pushMenu((void*)&UI_USERMENU10,false); break; #endif case UI_ACTION_X_UP: move_steps(axis_steps_per_unit[0],0,0,0,homing_feedrate[0],false,true); break; case UI_ACTION_X_DOWN: move_steps(-axis_steps_per_unit[0],0,0,0,homing_feedrate[0],false,true); break; case UI_ACTION_Y_UP: move_steps(0,axis_steps_per_unit[1],0,0,homing_feedrate[1],false,true); break; case UI_ACTION_Y_DOWN: move_steps(0,-axis_steps_per_unit[1],0,0,homing_feedrate[1],false,true); break; case UI_ACTION_Z_UP: move_steps(0,0,axis_steps_per_unit[2],0,homing_feedrate[2],false,true); break; case UI_ACTION_Z_DOWN: move_steps(0,0,-axis_steps_per_unit[2],0,homing_feedrate[2],false,true); break; case UI_ACTION_EXTRUDER_UP: move_steps(0,0,0,axis_steps_per_unit[3],UI_SET_EXTRUDER_FEEDRATE,false,true); break; case UI_ACTION_EXTRUDER_DOWN: move_steps(0,0,0,-axis_steps_per_unit[3],UI_SET_EXTRUDER_FEEDRATE,false,true); break; case UI_ACTION_EXTRUDER_TEMP_UP: { int tmp = (int)(current_extruder->tempControl.targetTemperatureC)+1; if(tmp==1) tmp = UI_SET_MIN_EXTRUDER_TEMP; else if(tmp>UI_SET_MAX_EXTRUDER_TEMP) tmp = UI_SET_MAX_EXTRUDER_TEMP; extruder_set_temperature(tmp,current_extruder->id); } break; case UI_ACTION_EXTRUDER_TEMP_DOWN: { int tmp = (int)(current_extruder->tempControl.targetTemperatureC)-1; if(tmpid); } break; case UI_ACTION_HEATED_BED_UP: #if HAVE_HEATED_BED==true { int tmp = (int)heatedBedController.targetTemperatureC+1; if(tmp==1) tmp = UI_SET_MIN_HEATED_BED_TEMP; else if(tmp>UI_SET_MAX_HEATED_BED_TEMP) tmp = UI_SET_MAX_HEATED_BED_TEMP; heated_bed_set_temperature(tmp); } #endif break; case UI_ACTION_SHOW_MEASUREMENT: #ifdef STEP_COUNTER { out.print_float_P(PSTR("Measure/delta ="),printer_state.countZSteps * inv_axis_steps_per_unit[2]); } #endif break; case UI_ACTION_RESET_MEASUREMENT: #ifdef STEP_COUNTER { printer_state.countZSteps = 0; out.println_P(PSTR("Measurement reset.")); } #endif break; case UI_ACTION_SET_MEASURED_ORIGIN: #ifdef STEP_COUNTER { if (printer_state.countZSteps < 0) printer_state.countZSteps = -printer_state.countZSteps; printer_state.zLength = inv_axis_steps_per_unit[2] * printer_state.countZSteps; printer_state.zMaxSteps = printer_state.countZSteps; for (byte i=0; i<3; i++) { printer_state.currentPositionSteps[i] = 0; } calculate_delta(printer_state.currentPositionSteps, printer_state.currentDeltaPositionSteps); out.println_P(PSTR("Measured origin set. Measurement reset.")); #if EEPROM_MODE!=0 epr_data_to_eeprom(false); out.println_P(PSTR("EEPROM updated")); #endif } #endif case UI_ACTION_SET_P1: #ifdef SOFTWARE_LEVELING for (byte i=0; i<3; i++) { printer_state.levelingP1[i] = printer_state.currentPositionSteps[i]; } #endif break; case UI_ACTION_SET_P2: #ifdef SOFTWARE_LEVELING for (byte i=0; i<3; i++) { printer_state.levelingP2[i] = printer_state.currentPositionSteps[i]; } #endif break; case UI_ACTION_SET_P3: #ifdef SOFTWARE_LEVELING for (byte i=0; i<3; i++) { printer_state.levelingP3[i] = printer_state.currentPositionSteps[i]; } #endif break; case UI_ACTION_CALC_LEVEL: #ifdef SOFTWARE_LEVELING long factors[4]; calculate_plane(factors, printer_state.levelingP1, printer_state.levelingP2, printer_state.levelingP3); out.println_P(PSTR("Leveling calc:")); out.println_float_P(PSTR("Tower 1:"), calc_zoffset(factors, DELTA_TOWER1_X_STEPS, DELTA_TOWER1_Y_STEPS) * inv_axis_steps_per_unit[0]); out.println_float_P(PSTR("Tower 2:"), calc_zoffset(factors, DELTA_TOWER2_X_STEPS, DELTA_TOWER2_Y_STEPS) * inv_axis_steps_per_unit[1]); out.println_float_P(PSTR("Tower 3:"), calc_zoffset(factors, DELTA_TOWER3_X_STEPS, DELTA_TOWER3_Y_STEPS) * inv_axis_steps_per_unit[2]); #endif break; case UI_ACTION_HEATED_BED_DOWN: #if HAVE_HEATED_BED==true { int tmp = (int)heatedBedController.targetTemperatureC-1; if(tmp-1 WRITE(EXT0_HEATER_PIN,0); #endif #if defined(EXT1_HEATER_PIN) && EXT1_HEATER_PIN>-1 WRITE(EXT1_HEATER_PIN,0); #endif #if defined(EXT2_HEATER_PIN) && EXT2_HEATER_PIN>-1 WRITE(EXT2_HEATER_PIN,0); #endif #if FAN_PIN>-1 WRITE(FAN_PIN,0); #endif resetFunc(); while(1) {} break; case UI_ACTION_RESET: resetFunc(); break; case UI_ACTION_PAUSE: OUT_P_LN("RequestPause:"); break; } refreshPage(); if(!skipBeep) BEEP_SHORT #if UI_AUTORETURN_TO_MENU_AFTER!=0 ui_autoreturn_time=millis()+UI_AUTORETURN_TO_MENU_AFTER; #endif #endif } void UIDisplay::mediumAction() { #if UI_HAS_I2C_ENCODER>0 ui_check_slow_encoder(); #endif } void UIDisplay::slowAction() { unsigned long time = millis(); byte refresh=0; #if UI_HAS_KEYS==1 // Update key buffer cli(); if((flags & 9)==0) { flags|=8; sei(); int nextAction = 0; ui_check_slow_keys(nextAction); if(lastButtonAction!=nextAction) { lastButtonStart = time; lastButtonAction = nextAction; cli(); flags|=2; // Mark slow action } cli(); flags-=8; } cli(); if((flags & 4)==0) { flags |= 4; // Reset click encoder cli(); char epos = encoderPos; encoderPos=0; sei(); if(epos) { nextPreviousAction(epos); BEEP_SHORT refresh=1; } if(lastAction!=lastButtonAction) { if(lastButtonAction==0) { if(lastAction>=2000 && lastAction<3000) { statusMsg[0] = 0; } lastAction = 0; cli(); flags &= ~3; } else if(time-lastButtonStart>UI_KEY_BOUNCETIME) { // New key pressed lastAction = lastButtonAction; executeAction(lastAction); nextRepeat = time+UI_KEY_FIRST_REPEAT; repeatDuration = UI_KEY_FIRST_REPEAT; } } else if(lastAction<1000 && lastAction) { // Repeatable key if(time-nextRepeat<10000) { executeAction(lastAction); repeatDuration -=UI_KEY_REDUCE_REPEAT; if(repeatDuration0 && ui_autoreturn_time4000) { if(time-lastSwitch>UI_PAGES_DURATION) { lastSwitch = time; #if !defined(UI_DISABLE_AUTO_PAGESWITCH) || !UI_DISABLE_AUTO_PAGESWITCH menuPos[0]++; if(menuPos[0]>=UI_NUM_PAGES) menuPos[0]=0; #endif refresh = 1; } else if(time-lastRefresh>=1000) refresh=1; } else if(time-lastRefresh>=1000) { UIMenu *men = (UIMenu*)menu[menuLevel]; byte mtype = pgm_read_byte((void*)&(men->menuType)); if(mtype!=1) refresh=1; } if(refresh) { refreshPage(); lastRefresh = time; } } void UIDisplay::fastAction() { #if UI_HAS_KEYS==1 // Check keys cli(); if((flags & 10)==0) { flags |= 8; sei(); int nextAction = 0; ui_check_keys(nextAction); if(lastButtonAction!=nextAction) { lastButtonStart = millis(); lastButtonAction = nextAction; cli(); flags|=1; } cli(); flags-=8; } sei(); #endif } #endif