Improvements to CLCD touch UI.

- Added support for moving axis.
- Added support for adjusting temperature settings.
- Reduced memory footprint of DL cache.
master
Marcio Teixeira 6 years ago
parent d3969b527b
commit ac437fdd54

@ -298,6 +298,20 @@ namespace FTDI {
const uint16_t OPT_NOHANDS = 49152;
}
// GPIO Bits
namespace FT800 {
const uint8_t GPIO_GP0 = 1 << 0;
const uint8_t GPIO_GP1 = 1 << 1;
const uint8_t GPIO_DISP = 1 << 7;
}
namespace FT810 {
const uint16_t GPIOX_GP0 = 1 << 0;
const uint16_t GPIOX_GP1 = 1 << 1;
const uint16_t GPIOX_DISP = 1 << 15;
}
// GLOBAL LCD REGISTER SET VALUES FOR WQVGA 480x272 DISPLAY
/*

@ -105,13 +105,10 @@
#ifndef _AO_FT810_FUNC_H
#define _AO_FT810_FUNC_H
#if defined(LCD_IS_FT800)
#define DL_CACHE_START 0x035000
#else
#define DL_CACHE_START 0x0F5000
#endif
#define DL_CACHE_START RAM_G_SIZE - 0xFFFF
// Uncomment the following to disable the DL caching mechanism
// (note, this will keep the LCD status message from working)
//#define DL_CACHE_DISABLED
#if defined(LCD_800x480)
@ -272,7 +269,7 @@ class CLCD::CommandFifo {
void Cmd (uint32_t cmd32);
void Cmd (void* data, uint16_t len);
void Cmd_Str (char* data);
void Cmd_Str (const char * const data);
void Cmd_Str (progmem_str data);
void Cmd_Clear_Color (uint32_t rgb);
void Cmd_Clear (bool Clr, bool Stl, bool Tag);
@ -577,7 +574,7 @@ void CLCD::CommandFifo::Cmd_Append (uint32_t ptr, uint32_t size)
* The DLCache can be used like so:
*
* void some_function() {
* static CLCD::DLCache dlcache;
* CLCD::DLCache dlcache(UNIQUE_ID);
*
* if(dlcache.hasData()) {
* dlcache.append();
@ -585,26 +582,88 @@ void CLCD::CommandFifo::Cmd_Append (uint32_t ptr, uint32_t size)
* // Add stuff to the DL
* dlcache.store();
* }
*
*
* Layout of Cache memory:
*
* The cache memory begins with a table at
* DL_CACHE_START: each table entry contains
* an address and size for a cached DL slot.
*
* Immediately following the table is the
* DL_FREE_ADDR, which points to free cache
* space; following this is occupied DL space,
* and after that free space that is yet to
* be used.
*
* location data sizeof
*
* DL_CACHE_START slot0_addr 4
* slot0_size 4
* slot1_addr 4
* slot1_size 4
* ...
* slotN_addr 4
* slotN_size 4
* DL_FREE_ADDR dl_free_ptr 4
* cached data
* ...
* dl_free_ptr empty space
* ...
*/
class CLCD::DLCache {
private:
static uint16_t dl_free;
uint16_t dl_addr = 0;
uint16_t dl_size = 0;
uint8_t dl_slot;
uint32_t dl_addr;
uint16_t dl_size;
void load_slot();
static void save_slot(uint8_t dl_slot, uint32_t dl_addr, uint32_t dl_size);
public:
static void init();
DLCache(uint8_t slot) {
dl_slot = slot;
load_slot();
}
bool hasData();
void store();
bool store(uint32_t num_bytes = 0);
void append();
};
uint16_t CLCD::DLCache::dl_free = 0;
#define DL_CACHE_SLOTS 250
#define DL_FREE_ADDR DL_CACHE_START + DL_CACHE_SLOTS * 8
// The init function ensures all cache locatios are marked as empty
void CLCD::DLCache::init() {
Mem_Write32(DL_FREE_ADDR, DL_FREE_ADDR + 4);
for(uint8_t slot = 0; slot < DL_CACHE_SLOTS; slot++) {
save_slot(slot, 0, 0);
}
}
bool CLCD::DLCache::hasData() {
#if !defined(DL_CACHE_DISABLED)
return dl_size != 0;
#else
return false;
#endif
}
void CLCD::DLCache::store() {
/* This caches the current display list in RAMG so
* that it can be appended later. The memory is
* dynamically allocated following DL_FREE_ADDR.
*
* If num_bytes is provided, then that many bytes
* will be reserved so that the cache may be re-written
* later with potentially a bigger DL.
*/
bool CLCD::DLCache::store(uint32_t num_bytes /* = 0*/) {
#if !defined(DL_CACHE_DISABLED)
CLCD::CommandFifo cmd;
@ -613,45 +672,79 @@ void CLCD::DLCache::store() {
cmd.Cmd_Wait_Until_Idle();
// Figure out how long the display list is
dl_size = Mem_Read32(REG_CMD_DL) & 0x1FFF;
dl_addr = dl_free;
uint32_t new_dl_size = Mem_Read32(REG_CMD_DL) & 0x1FFF;
uint32_t free_space = 0;
uint32_t dl_alloc = 0;
if(dl_addr == 0) {
// If we are allocating new space...
dl_addr = Mem_Read32(DL_FREE_ADDR);
free_space = RAM_G_SIZE - dl_addr;
dl_alloc = num_bytes ? num_bytes : new_dl_size;
dl_size = new_dl_size;
} else {
// Otherwise, we can only store as much space
// as was previously allocated.
free_space = num_bytes ? num_bytes : dl_size;
dl_alloc = 0;
dl_size = new_dl_size;
}
if((dl_addr + dl_size) > RAM_G_SIZE) {
if(dl_size > free_space) {
// Not enough memory to cache the display list.
dl_addr = 0;
dl_size = 0;
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Not enough space in GRAM to cache display list, free space: ", RAM_G_SIZE - dl_free);
SERIAL_PROTOCOLPAIR("Not enough space in GRAM to cache display list, free space: ", free_space);
SERIAL_PROTOCOLLNPAIR(" Required: ", dl_size);
#else
Serial.print(F("Not enough space in GRAM to cache display list, free space:"));
Serial.println(RAM_G_SIZE - dl_free);
Serial.print(free_space);
Serial.print(F(" Required: "));
Serial.println(dl_size);
#endif
#endif
return false;
} else {
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLPAIR("Saving DL to RAMG cache, bytes: ", dl_size);
SERIAL_PROTOCOLPAIR(" (Free space: ", RAM_G_SIZE - dl_free);
SERIAL_PROTOCOLPAIR(" (Free space: ", free_space);
SERIAL_PROTOCOLLNPGM(")");
#else
Serial.print(F("Saving DL to RAMG cache, bytes: "));
Serial.println(dl_size);
Serial.print(F(" (Free space: "));
Serial.println(RAM_G_SIZE - dl_free);
Serial.println(free_space);
Serial.print(F(")"));
#endif
#endif
cmd.Cmd_Mem_Cpy(DL_CACHE_START + dl_addr, RAM_DL, dl_size);
cmd.Cmd_Mem_Cpy(dl_addr, RAM_DL, dl_size);
cmd.Cmd_Execute();
dl_free += dl_size;
save_slot(dl_slot, dl_addr, dl_size);
if(dl_alloc > 0) {
// If we allocated space dynamically, then adjust dl_free_addr.
Mem_Write32(DL_FREE_ADDR, dl_addr + dl_alloc);
}
return true;
}
#endif
}
void CLCD::DLCache::save_slot(uint8_t dl_slot, uint32_t dl_addr, uint32_t dl_size) {
Mem_Write32(DL_CACHE_START + dl_slot * 8 + 0, dl_addr);
Mem_Write32(DL_CACHE_START + dl_slot * 8 + 4, dl_size);
}
void CLCD::DLCache::load_slot() {
dl_addr = Mem_Read32(DL_CACHE_START + dl_slot * 8 + 0);
dl_size = Mem_Read32(DL_CACHE_START + dl_slot * 8 + 4);
}
void CLCD::DLCache::append() {
CLCD::CommandFifo cmd;
cmd.Cmd_Append(DL_CACHE_START + dl_addr, dl_size);
#if !defined(DL_CACHE_DISABLED)
cmd.Cmd_Append(dl_addr, dl_size);
#endif
#if defined(UI_FRAMEWORK_DEBUG)
cmd.Cmd_Execute();
cmd.Cmd_Wait_Until_Idle();
@ -758,14 +851,15 @@ void CLCD::Init (void) {
Mem_Write8(REG_DLSWAP, 0x02); // Swap on New Frame
/*
* Turn On the Display
* Turn on the Display (set DISP high)
* Turn on the Audio Amplifier (set GP0 high; on the AO CLCD board, this is tied to the amplifier control)
*/
#if defined(LCD_IS_FT800)
Mem_Write8(REG_GPIO_DIR, 0x80); // Turn ON Display Enable
Mem_Write8(REG_GPIO, 0x80);
Mem_Write8(REG_GPIO_DIR, GPIO_DISP | GPIO_GP0);
Mem_Write8(REG_GPIO, GPIO_DISP | GPIO_GP0);
#else
Mem_Write16(REG_GPIOX_DIR, 1 << 15); // Turn ON Display Enable
Mem_Write16(REG_GPIOX, 1 << 15);
Mem_Write16(REG_GPIOX_DIR, GPIOX_DISP | GPIOX_GP0);
Mem_Write16(REG_GPIOX, GPIOX_DISP | GPIOX_GP0);
#endif
Enable(); // Turns on Clock by setting PCLK Register to 5
@ -794,6 +888,8 @@ class CLCD::SoundPlayer {
uint8_t sixteenths; // Duration of note, in sixteeths of a second, or zero to play to completion
};
const uint8_t WAIT = 0;
private:
const sound_t *sequence;
uint32_t next;
@ -838,18 +934,23 @@ bool CLCD::SoundPlayer::soundPlaying() {
void CLCD::SoundPlayer::onIdle() {
if(!sequence) return;
const bool readyForNextNote = next != 0 ? (millis() > next) : !soundPlaying();
const bool readyForNextNote = (next == WAIT) ? !soundPlaying() : (millis() > next);
if(readyForNextNote) {
const effect_t fx = effect_t(pgm_read_byte_near(&sequence->effect));
const note_t nt = note_t(pgm_read_byte_near(&sequence->note));
const uint16_t ms = uint32_t(pgm_read_byte_near(&sequence->sixteenths)) * 1000 / 16;
const note_t nt = note_t(pgm_read_byte_near(&sequence->note));
const uint32_t ms = uint32_t(pgm_read_byte_near(&sequence->sixteenths)) * 1000 / 16;
if(ms == 0 && fx == SILENCE && nt == 0) {
sequence = 0;
} else {
next = ms ? (millis() + ms) : 0;
play(fx, nt != 0 ? nt : NOTE_C4);
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Scheduling note in ", ms);
#endif
#endif
next = (ms == WAIT) ? 0 : (millis() + ms);
play(fx, (nt == 0) ? NOTE_C4 : nt);
sequence++;
}
}

@ -398,7 +398,7 @@ void CLCD::CommandFifo::Cmd (void* data, uint16_t len) {
}
void CLCD::CommandFifo::Cmd_Str (char* data) {
void CLCD::CommandFifo::Cmd_Str (const char * const data) {
write(data, strlen(data)+1);
}

@ -16,12 +16,14 @@
* location: <http://www.gnu.org/licenses/>. *
****************************************************************************/
#define STATUS_MESSAGE_BUFFER_LENGTH 32
char lcd_status_message[STATUS_MESSAGE_BUFFER_LENGTH] = WELCOME_MSG;
#define DISPLAY_UPDATE_INTERVAL 1000
#define TOUCH_REPEATS_PER_SECOND 4
// To save MCU RAM, the status message is "baked" in to the status screen
// cache, so we reserve a large chunk of memory for the DL cache
#define RAMG_STATUS_SCREEN_DL_SIZE 2048
static float marlin_x_axis = 100;
static float marlin_y_axis = 50;
static float marlin_z_axis = 170;
static float marlin_x_steps = 100;
static float marlin_y_steps = 100;
static float marlin_z_steps = 100;
@ -94,6 +96,8 @@ static float marlin_z_offset = 0.150;
#define MENU_BTN_STYLE Theme::font_medium, OPT_3D
#define EXEC_GCODE(cmd) Marlin_LCD_API::runGCode(cmd)
/************************* MENU SCREEN DECLARATIONS *************************/
class BootScreen : public UIScreen {
@ -106,14 +110,14 @@ class AboutScreen : public UIScreen {
public:
static void onEntry();
static void onRefresh();
static void onTouchStart(uint8_t tag);
static void onIdle();
static bool onTouchStart(uint8_t tag);
};
class KillScreen : public UIScreen {
class KillScreen {
// The KillScreen is behaves differently than the
// others, so we do not bother extending UIScreen.
public:
static void onEntry();
static void onRefresh();
static void show(progmem_str msg);
};
class StatusScreen : public UIScreen {
@ -122,24 +126,25 @@ class StatusScreen : public UIScreen {
static void static_temperature();
static void static_progress();
static void static_interaction_buttons();
static void static_status_message(const char * const message);
static void dynamic_axis_position();
static void dynamic_temperature();
static void dynamic_progress();
static void dynamic_status_message();
public:
static void setStatusMessage(const char * message);
static void onRefresh();
static void onStartup();
static void onEntry();
static void onIdle();
static void onTouchStart(uint8_t tag);
static bool onTouchStart(uint8_t tag);
};
class MenuScreen : public UIScreen {
public:
static void onRefresh();
static void onTouchStart(uint8_t tag);
static bool onTouchStart(uint8_t tag);
};
class CalibrationScreen : public UIScreen {
@ -151,13 +156,13 @@ class CalibrationScreen : public UIScreen {
class CalibrationRegistersScreen : public UIScreen {
public:
static void onRefresh();
static void onTouchStart(uint8_t tag);
static bool onTouchStart(uint8_t tag);
};
class AdvancedSettingsScreen : public UIScreen {
public:
static void onRefresh();
static void onTouchStart(uint8_t tag);
static bool onTouchStart(uint8_t tag);
};
class ValueAdjusters : public UIScreen {
@ -199,31 +204,37 @@ class ValueAdjusters : public UIScreen {
static float getIncrement();
public:
static void onTouchStart(uint8_t tag);
static bool onTouchStart(uint8_t tag);
};
class MoveAxisScreen : public ValueAdjusters {
public:
static void onRefresh();
static void onTouchHeld(uint8_t tag);
static bool onTouchHeld(uint8_t tag);
};
class StepsScreen : public ValueAdjusters {
public:
static void onRefresh();
static void onTouchHeld(uint8_t tag);
static bool onTouchHeld(uint8_t tag);
};
class ZOffsetScreen : public ValueAdjusters {
public:
static void onRefresh();
static void onTouchHeld(uint8_t tag);
static bool onTouchHeld(uint8_t tag);
};
class TemperatureScreen : public ValueAdjusters {
public:
static void onRefresh();
static void onTouchHeld(uint8_t tag);
static bool onTouchHeld(uint8_t tag);
};
class FilesScreen : public UIScreen {
public:
static void onRefresh();
static bool onTouchHeld(uint8_t tag);
};
/******************************* MENU SCREEN TABLE ******************************/
@ -231,7 +242,6 @@ class TemperatureScreen : public ValueAdjusters {
SCREEN_TABLE {
DECL_SCREEN(BootScreen),
DECL_SCREEN(AboutScreen),
DECL_SCREEN(KillScreen),
DECL_SCREEN(CalibrationScreen),
DECL_SCREEN(StatusScreen),
DECL_SCREEN(MenuScreen),
@ -240,11 +250,29 @@ SCREEN_TABLE {
DECL_SCREEN(StepsScreen),
DECL_SCREEN(ZOffsetScreen),
DECL_SCREEN(TemperatureScreen),
DECL_SCREEN(CalibrationRegistersScreen)
DECL_SCREEN(CalibrationRegistersScreen),
DECL_SCREEN(FilesScreen),
};
SCREEN_TABLE_POST
/********************************* DL CACHE SLOTS ******************************/
// In order to reduce SPI traffic, we cache display lists (DL) in RAMG. This
// is done using the CLCD::DLCache class, which takes a unique ID for each
// cache location. These IDs are defined here:
enum {
STATUS_SCREEN_CACHE,
MENU_SCREEN_CACHE,
ADVANCED_SETTINGS_SCREEN_CACHE,
MOVE_AXIS_SCREEN_CACHE,
TEMPERATURE_SCREEN_CACHE,
STEPS_SCREEN_CACHE,
ZOFFSET_SCREEN_CACHE,
FILES_SCREEN_CACHE
};
/************************************ MENU THEME ********************************/
namespace Theme {
@ -345,37 +373,6 @@ void BootScreen::onIdle() {
CLCD::SoundPlayer sound;
const PROGMEM CLCD::SoundPlayer::sound_t chimes[] = {
{CHIMES, NOTE_G3, 13},
{CHIMES, NOTE_E4, 13},
{CHIMES, NOTE_C4, 19},
{SILENCE, END_SONG, 0}
};
const PROGMEM CLCD::SoundPlayer::sound_t samples[] = {
{HARP},
{XYLOPHONE},
{TUBA},
{GLOCKENSPIEL},
{ORGAN},
{TRUMPET},
{PIANO},
{CHIMES},
{MUSIC_BOX},
{BELL},
{CLICK},
{SWITCH},
{COWBELL},
{NOTCH},
{HIHAT},
{KICKDRUM},
{SWITCH},
{POP},
{CLACK},
{CHACK},
{SILENCE}
};
void AboutScreen::onEntry() {
UIScreen::onEntry();
@ -405,42 +402,22 @@ void AboutScreen::onRefresh() {
cmd.Cmd_Execute();
}
void AboutScreen::onTouchStart(uint8_t tag) {
bool AboutScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); return;
case 2: GOTO_SCREEN(CalibrationRegistersScreen); return;
case 1: GOTO_PREVIOUS(); return true;
case 2: GOTO_SCREEN(CalibrationRegistersScreen); return true;
}
}
void AboutScreen::onIdle() {
sound.onIdle();
}
/************************************ KILL SCREEN *******************************/
const PROGMEM CLCD::SoundPlayer::sound_t sad_trombone[] = {
{TRUMPET, NOTE_A3S, 10},
{TRUMPET, NOTE_A3 , 10},
{TRUMPET, NOTE_G3S, 10},
{TRUMPET, NOTE_G3, 20},
{SILENCE, END_SONG, 0}
};
void KillScreen::onEntry() {
UIScreen::onEntry();
CLCD::Mem_Write8(REG_VOL_SOUND, 0xFF);
sound.play(sad_trombone);
// The kill screen is an oddball that happens after Marlin has killed the events
// loop. So we only have a show() method rather than onRefresh(). The KillScreen
// should not be used as a model for other UI screens as it is an exception.
// Marlin won't call the idle function anymore, so we
// have to do it to play the sounds.
while(sound.hasMoreNotes()) {
sound.onIdle();
}
}
void KillScreen::onRefresh() {
void KillScreen::show(progmem_str message) {
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd_Clear_Color(Theme::about_bg);
cmd.Cmd_Clear(1,1,1);
@ -448,7 +425,7 @@ void KillScreen::onRefresh() {
#define GRID_COLS 4
#define GRID_ROWS 8
BTX( BTN_POS(1,2), BTN_SIZE(4,1), lcd_status_message, FONT_LRG);
BTX( BTN_POS(1,2), BTN_SIZE(4,1), message, FONT_LRG);
BTX( BTN_POS(1,3), BTN_SIZE(4,1), F("PRINTER HALTED"), FONT_LRG);
@ -457,6 +434,14 @@ void KillScreen::onRefresh() {
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
sound.play(sad_trombone);
// Marlin won't call the idle function anymore,
// so we have to loop here to play the sounds.
while(sound.hasMoreNotes()) {
sound.onIdle();
}
}
/*********************************** STATUS SCREEN ******************************/
@ -590,7 +575,7 @@ void StatusScreen::dynamic_temperature() {
sprintf_P(
fan_str,
PSTR("%-3d %%"),
Marlin_LCD_API::getFan_percent(0)
int8_t(Marlin_LCD_API::getFan_percent(0))
);
sprintf_P(
@ -696,14 +681,39 @@ void StatusScreen::static_interaction_buttons() {
#define GRID_COLS 1
void StatusScreen::dynamic_status_message() {
void StatusScreen::static_status_message(const char * const message) {
CLCD::CommandFifo cmd;
#if defined(LCD_PORTRAIT)
THEME(status_msg) BTN( BTN_POS(1,4), BTN_SIZE(1,1), message, FONT_LRG, OPT_FLAT);
#else
THEME(status_msg) BTN( BTN_POS(1,3), BTN_SIZE(1,2), message, FONT_LRG, OPT_FLAT);
#endif
}
void StatusScreen::setStatusMessage(const char * const message) {
CLCD::DLCache dlcache(STATUS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
#if defined(LCD_PORTRAIT)
THEME(status_msg) BTN( BTN_POS(1,4), BTN_SIZE(1,1), lcd_status_message, FONT_LRG, OPT_FLAT);
#else
THEME(status_msg) BTN( BTN_POS(1,3), BTN_SIZE(1,2), lcd_status_message, FONT_LRG, OPT_FLAT);
#endif
cmd.Cmd_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
static_temperature();
static_progress();
static_axis_position();
static_interaction_buttons();
static_status_message(message);
if(!dlcache.store(RAMG_STATUS_SCREEN_DL_SIZE)) {
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Unable to set the status message, not enough DL cache space: ",message);
#else
Serial.print(F("Unable to set the status message, not enough DL cache space: "));
Serial.println(message);
#endif
}
}
#if defined(LCD_PORTRAIT)
@ -722,29 +732,21 @@ void StatusScreen::onStartup() {
}
void StatusScreen::onRefresh() {
static CLCD::DLCache dlcache;
CLCD::DLCache dlcache(STATUS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
if(dlcache.hasData()) {
dlcache.append();
} else {
cmd.Cmd_Clear_Color(Theme::background);
cmd.Cmd_Clear(1,1,1);
static_temperature();
static_progress();
static_axis_position();
static_interaction_buttons();
dlcache.store();
// This should not happen, as setStatusMessage will
// populate the cache.
}
/* Dynamic content, non-cached data follows */
dynamic_temperature();
dynamic_progress();
dynamic_status_message();
dynamic_axis_position();
cmd.Cmd(DL_DISPLAY);
@ -760,12 +762,13 @@ void StatusScreen::onIdle() {
onRefresh();
}
void StatusScreen::onTouchStart(uint8_t tag) {
bool StatusScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 4: GOTO_SCREEN(MenuScreen); break;
case 5: GOTO_SCREEN(TemperatureScreen); break;
case 6: GOTO_SCREEN(MoveAxisScreen); break;
case 6: GOTO_SCREEN(MoveAxisScreen); break;
}
return true;
}
/************************************ MENU SCREEN *******************************/
@ -779,7 +782,7 @@ void StatusScreen::onTouchStart(uint8_t tag) {
#endif
void MenuScreen::onRefresh() {
static CLCD::DLCache dlcache;
CLCD::DLCache dlcache(MENU_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
@ -826,15 +829,20 @@ void MenuScreen::onRefresh() {
cmd.Cmd_Execute();
}
void MenuScreen::onTouchStart(uint8_t tag) {
bool MenuScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); break;
case 2: EXEC_GCODE(F("G28")); break;
case 3: GOTO_SCREEN(MoveAxisScreen); break;
case 4: EXEC_GCODE(F("M84")); break;
case 5: GOTO_SCREEN(TemperatureScreen); break;
case 6: GOTO_SCREEN(AdvancedSettingsScreen); break;
case 7: GOTO_SCREEN(AboutScreen); break;
case 8: GOTO_SCREEN(CalibrationScreen); break;
default:
return false;
}
return true;
}
/******************************* CONFIGURATION SCREEN ****************************/
@ -848,7 +856,7 @@ void MenuScreen::onTouchStart(uint8_t tag) {
#endif
void AdvancedSettingsScreen::onRefresh() {
static CLCD::DLCache dlcache;
CLCD::DLCache dlcache(ADVANCED_SETTINGS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
@ -889,13 +897,16 @@ void AdvancedSettingsScreen::onRefresh() {
cmd.Cmd_Execute();
}
void AdvancedSettingsScreen::onTouchStart(uint8_t tag) {
bool AdvancedSettingsScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); break;
case 2: GOTO_PREVIOUS(); break;
case 3: GOTO_SCREEN(ZOffsetScreen); break;
case 4: GOTO_SCREEN(StepsScreen); break;
default:
return false;
}
return true;
}
/******************************** CALIBRATION SCREEN ****************************/
@ -984,10 +995,13 @@ void CalibrationRegistersScreen::onRefresh() {
cmd.Cmd_Execute();
}
void CalibrationRegistersScreen::onTouchStart(uint8_t tag) {
bool CalibrationRegistersScreen::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); return;
case 1: GOTO_PREVIOUS(); break;
default:
return false;
}
return true;
}
/*************************** GENERIC VALUE ADJUSTMENT SCREEN ******************************/
@ -1135,13 +1149,14 @@ void ValueAdjusters::adjuster_t::dynamic_parts(stacker_t &s, float value) const
s.line++;
}
void ValueAdjusters::onTouchStart(uint8_t tag) {
bool ValueAdjusters::onTouchStart(uint8_t tag) {
switch(tag) {
case 1: GOTO_PREVIOUS(); return;
case 1: GOTO_PREVIOUS(); return true;
case 240 ... 245: increment = tag; break;
default: current_screen.onTouchHeld(tag); return;
default: return current_screen.onTouchHeld(tag);
}
current_screen.onRefresh();
return true;
}
float ValueAdjusters::getIncrement() {
@ -1162,7 +1177,7 @@ uint8_t ValueAdjusters::increment = 20;
/******************************** MOVE AXIS SCREEN ******************************/
void MoveAxisScreen::onRefresh() {
static CLCD::DLCache dlcache;
CLCD::DLCache dlcache(MOVE_AXIS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
@ -1187,9 +1202,9 @@ void MoveAxisScreen::onRefresh() {
}
s.dynamic_parts();
h.dynamic_parts(s);
x.dynamic_parts(s,marlin_x_axis);
y.dynamic_parts(s,marlin_y_axis);
z.dynamic_parts(s,marlin_z_axis);
x.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::X));
y.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Y));
z.dynamic_parts(s,Marlin_LCD_API::getAxisPosition_mm(Marlin_LCD_API::Z));
i.dynamic_parts(s);
cmd.Cmd(DL_DISPLAY);
@ -1197,22 +1212,34 @@ void MoveAxisScreen::onRefresh() {
cmd.Cmd_Execute();
}
void MoveAxisScreen::onTouchHeld(uint8_t tag) {
bool MoveAxisScreen::onTouchHeld(uint8_t tag) {
// We don't want to stack up moves, so wait until the
// machine is idle before sending another.
if(Marlin_LCD_API::isMoving()) {
return false;
}
float inc = getIncrement();
Marlin_LCD_API::axis_t axis;
const float feedrate_mm_s = inc * TOUCH_REPEATS_PER_SECOND;
switch(tag) {
case 2: marlin_x_axis -= getIncrement(); break;
case 3: marlin_x_axis += getIncrement(); break;
case 4: marlin_y_axis -= getIncrement(); break;
case 5: marlin_y_axis += getIncrement(); break;
case 6: marlin_z_axis -= getIncrement(); break;
case 7: marlin_z_axis += getIncrement(); break;
case 2: axis = Marlin_LCD_API::X; inc *= -1; break;
case 3: axis = Marlin_LCD_API::X; inc *= 1; break;
case 4: axis = Marlin_LCD_API::Y; inc *= -1; break;
case 5: axis = Marlin_LCD_API::Y; inc *= 1; break;
case 6: axis = Marlin_LCD_API::Z; inc *= -1; break;
case 7: axis = Marlin_LCD_API::Z; inc *= 1; break;
}
Marlin_LCD_API::setAxisPosition_mm(axis, Marlin_LCD_API::getAxisPosition_mm(axis) + inc, feedrate_mm_s);
onRefresh();
return true;
}
/******************************* TEMPERATURE SCREEN ******************************/
void TemperatureScreen::onRefresh() {
static CLCD::DLCache dlcache;
CLCD::DLCache dlcache(TEMPERATURE_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
@ -1252,7 +1279,7 @@ void TemperatureScreen::onRefresh() {
cmd.Cmd_Execute();
}
void TemperatureScreen::onTouchHeld(uint8_t tag) {
bool TemperatureScreen::onTouchHeld(uint8_t tag) {
switch(tag) {
case 20: Marlin_LCD_API::setTargetTemp_celsius(0, Marlin_LCD_API::getTargetTemp_celsius(0) - getIncrement()); break;
case 21: Marlin_LCD_API::setTargetTemp_celsius(0, Marlin_LCD_API::getTargetTemp_celsius(0) + getIncrement()); break;
@ -1262,14 +1289,17 @@ void TemperatureScreen::onTouchHeld(uint8_t tag) {
case 5: Marlin_LCD_API::setTargetTemp_celsius(2, Marlin_LCD_API::getTargetTemp_celsius(2) + getIncrement()); break;
case 10: Marlin_LCD_API::setFan_percent( 0, Marlin_LCD_API::getFan_percent(0) - getIncrement()); break;
case 11: Marlin_LCD_API::setFan_percent( 0, Marlin_LCD_API::getFan_percent(0) + getIncrement()); break;
default:
return false;
}
onRefresh();
return true;
}
/******************************* STEPS SCREEN ******************************/
void StepsScreen::onRefresh() {
static CLCD::DLCache dlcache;
CLCD::DLCache dlcache(STEPS_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
@ -1307,7 +1337,7 @@ void StepsScreen::onRefresh() {
cmd.Cmd_Execute();
}
void StepsScreen::onTouchHeld(uint8_t tag) {
bool StepsScreen::onTouchHeld(uint8_t tag) {
switch(tag) {
case 2: marlin_x_steps -= getIncrement(); break;
case 3: marlin_x_steps += getIncrement(); break;
@ -1317,14 +1347,17 @@ void StepsScreen::onTouchHeld(uint8_t tag) {
case 7: marlin_z_steps += getIncrement(); break;
case 8: marlin_e0_steps -= getIncrement(); break;
case 9: marlin_e0_steps += getIncrement(); break;
default:
return false;
}
onRefresh();
return true;
}
/***************************** Z-OFFSET SCREEN ***************************/
void ZOffsetScreen::onRefresh() {
static CLCD::DLCache dlcache;
CLCD::DLCache dlcache(ZOFFSET_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
@ -1353,20 +1386,48 @@ void ZOffsetScreen::onRefresh() {
cmd.Cmd_Execute();
}
void ZOffsetScreen::onTouchHeld(uint8_t tag) {
bool ZOffsetScreen::onTouchHeld(uint8_t tag) {
switch(tag) {
case 4: marlin_z_offset -= getIncrement(); break;
case 5: marlin_z_offset += getIncrement(); break;
default:
return false;
}
onRefresh();
return true;
}
/***************************** FILES SCREEN ***************************/
void FilesScreen::onRefresh() {
CLCD::DLCache dlcache(FILES_SCREEN_CACHE);
CLCD::CommandFifo cmd;
cmd.Cmd(CMD_DLSTART);
cmd.Cmd(DL_DISPLAY);
cmd.Cmd(CMD_SWAP);
cmd.Cmd_Execute();
}
bool FilesScreen::onTouchHeld(uint8_t tag) {
switch(tag) {
default:
return false;
}
onRefresh();
return true;
}
/******************************** MAIN EVENT HANDLER *******************************/
#define DISPLAY_UPDATE_INTERVAL 1000
void lcd_setstatusPGM(const char * const message, int8_t level = 0);
void lcd_init() {
CLCD::Init();
CLCD::DLCache::init();
lcd_setstatusPGM(PSTR(WELCOME_MSG));
current_screen.start();
}
@ -1377,6 +1438,8 @@ void lcd_update() {
static uint32_t last_repeat = 0;
static uint32_t last_update = 0;
sound.onIdle();
if(millis() - last_update > DISPLAY_UPDATE_INTERVAL) {
current_screen.onIdle();
last_update = millis();
@ -1418,19 +1481,20 @@ void lcd_update() {
else if(pressed == NONE) {
// When the user taps on a button, activate the onTouchStart handler
const uint8_t lastScreen = current_screen.getScreen();
current_screen.onTouchStart(tag);
last_repeat = millis();
sound.play(Theme::press_sound);
if(current_screen.onTouchStart(tag)) {
last_repeat = millis();
sound.play(Theme::press_sound);
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Touch start: ", tag);
#else
Serial.print("Touch start: ");
Serial.println(tag);
#if defined(UI_FRAMEWORK_DEBUG)
#if defined (SERIAL_PROTOCOLLNPAIR)
SERIAL_PROTOCOLLNPAIR("Touch start: ", tag);
#else
Serial.print("Touch start: ");
Serial.println(tag);
#endif
#endif
#endif
}
if(lastScreen != current_screen.getScreen()) {
// In the case in which a touch event triggered a new screen to be
@ -1442,10 +1506,11 @@ void lcd_update() {
}
} else if(tag == pressed) {
// The user is holding down a button.
if((millis() - last_repeat) > 250) {
current_screen.onTouchHeld(tag);
sound.play(Theme::repeat_sound);
last_repeat = millis();
if((millis() - last_repeat) > (1000 / TOUCH_REPEATS_PER_SECOND)) {
if(current_screen.onTouchHeld(tag)) {
sound.play(Theme::repeat_sound);
last_repeat = millis();
}
}
}
}
@ -1453,18 +1518,22 @@ void lcd_update() {
inline bool lcd_hasstatus() { return true; }
void lcd_setstatus(const char * const message, const bool persist = false) {
strncpy(lcd_status_message, message, STATUS_MESSAGE_BUFFER_LENGTH);
StatusScreen::setStatusMessage(message);
}
void lcd_setstatusPGM(const char * const message, int8_t level = 0) {
strncpy_P(lcd_status_message, message, STATUS_MESSAGE_BUFFER_LENGTH);
void lcd_setstatusPGM(const char * const message, int8_t level /* = 0 */) {
char buff[64];
strncpy_P(buff, message, sizeof(buff));
StatusScreen::setStatusMessage(buff);
}
void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...) {
char buff[64];
va_list args;
va_start(args, fmt);
vsnprintf_P(lcd_status_message, STATUS_MESSAGE_BUFFER_LENGTH, fmt, args);
vsnprintf_P(buff, sizeof(buff), fmt, args);
va_end(args);
StatusScreen::setStatusMessage(buff);
}
void lcd_setalertstatusPGM(const char * const message) {
@ -1478,6 +1547,5 @@ inline bool lcd_detected() { return true; }
inline void lcd_refresh() {current_screen.onIdle();}
void kill_screen(const char* lcd_msg) {
strncpy_P(lcd_status_message, lcd_msg, STATUS_MESSAGE_BUFFER_LENGTH);
GOTO_SCREEN(KillScreen);
KillScreen::show(progmem_str(lcd_msg));
}

@ -0,0 +1,110 @@
/****************************************************************************
* Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
* *
* 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. *
* *
* To view a copy of the GNU General Public License, go to the following *
* location: <http://www.gnu.org/licenses/>. *
****************************************************************************/
#ifndef _AO_FT810_SNDS_H
#define _AO_FT810_SNDS_H
/* A sound sequence consists of an array of the following:
struct sound_t {
effect_t effect; // The sound effect number
note_t note; // The MIDI note value, or C4 if 0
uint8_t sixteenths; // Note duration in 1/16th of a sec;
// If 0, play until sample is finished.
};
Constants are defined in "AO_FT810_Constants.h".
Both note and sixteenths are optional. If omitted, the compiler
will fill them in with 0 which will be interpreted by play C4
for the duration of the sample.
The sequence must be terminated by "{SILENCE, END_SONG, WAIT}", i.e
all zeros.
*/
const PROGMEM CLCD::SoundPlayer::sound_t chimes[] = {
{CHIMES, NOTE_G3, 5},
{CHIMES, NOTE_E4, 5},
{CHIMES, NOTE_C4, 5},
{SILENCE, END_SONG, 0}
};
const PROGMEM CLCD::SoundPlayer::sound_t sad_trombone[] = {
{TRUMPET, NOTE_A3S, 10},
{TRUMPET, NOTE_A3 , 10},
{TRUMPET, NOTE_G3S, 10},
{TRUMPET, NOTE_G3, 20},
{SILENCE, END_SONG, 0}
};
const PROGMEM CLCD::SoundPlayer::sound_t js_bach_joy[] = {
{PIANO, NOTE_G3, 10},
{PIANO, NOTE_A3, 10},
{PIANO, NOTE_B3, 10},
{PIANO, NOTE_D4, 10},
{PIANO, NOTE_C4, 10},
{PIANO, NOTE_C4, 10},
{PIANO, NOTE_E4, 10},
{PIANO, NOTE_D4, 10},
{PIANO, NOTE_D4, 10},
{PIANO, NOTE_G4 , 10},
{PIANO, NOTE_F4S, 10},
{PIANO, NOTE_G4, 10},
{PIANO, NOTE_D4, 10},
{PIANO, NOTE_B3, 10},
{PIANO, NOTE_G3, 10},
{PIANO, NOTE_A3, 10},
{PIANO, NOTE_B3, 10},
{PIANO, NOTE_C4, 10},
{PIANO, NOTE_D4, 10},
{PIANO, NOTE_E4, 10},
{PIANO, NOTE_D4, 10},
{PIANO, NOTE_C4, 10},
{PIANO, NOTE_B3, 10},
{PIANO, NOTE_A3, 10},
{PIANO, NOTE_B3, 10},
{PIANO, NOTE_G3, 10},
{PIANO, NOTE_G3, 10},
{SILENCE, END_SONG, 0}
};
const PROGMEM CLCD::SoundPlayer::sound_t all_instruments[] = {
{HARP},
{XYLOPHONE},
{TUBA},
{GLOCKENSPIEL},
{ORGAN},
{TRUMPET},
{PIANO},
{CHIMES},
{MUSIC_BOX},
{BELL},
{CLICK},
{SWITCH},
{COWBELL},
{NOTCH},
{HIHAT},
{KICKDRUM},
{SWITCH},
{POP},
{CLACK},
{CHACK},
{SILENCE, END_SONG, 0}
};
#endif // _AO_FT810_SNDS_H

@ -46,9 +46,9 @@ class ScreenRef {
typedef void onExit_func_t(void);
typedef void onIdle_func_t(void);
typedef void onRefresh_func_t(void);
typedef void onTouchStart_func_t(uint8_t);
typedef void onTouchHeld_func_t(uint8_t);
typedef void onTouchEnd_func_t(uint8_t);
typedef bool onTouchStart_func_t(uint8_t);
typedef bool onTouchHeld_func_t(uint8_t);
typedef bool onTouchEnd_func_t(uint8_t);
private:
typedef struct {
@ -103,9 +103,9 @@ class ScreenRef {
void onExit() {GET_METHOD(type, onExit)();}
void onIdle() {GET_METHOD(type, onIdle)();}
void onRefresh() {GET_METHOD(type, onRefresh)();}
void onTouchStart(uint8_t tag) {GET_METHOD(type, onTouchStart)(tag);}
void onTouchHeld(uint8_t tag) {GET_METHOD(type, onTouchHeld)(tag);}
void onTouchEnd(uint8_t tag) {GET_METHOD(type, onTouchEnd)(tag);}
bool onTouchStart(uint8_t tag) {return GET_METHOD(type, onTouchStart)(tag);}
bool onTouchHeld(uint8_t tag) {return GET_METHOD(type, onTouchHeld)(tag);}
bool onTouchEnd(uint8_t tag) {return GET_METHOD(type, onTouchEnd)(tag);}
void initializeAll() {
for(uint8_t type = 0; type < functionTableSize; type++) {
@ -171,9 +171,9 @@ class UIScreen {
static void onEntry() {current_screen.onRefresh();}
static void onExit() {}
static void onIdle() {}
static void onTouchStart(uint8_t) {}
static void onTouchHeld(uint8_t) {}
static void onTouchEnd(uint8_t) {}
static bool onTouchStart(uint8_t) {return false;}
static bool onTouchHeld(uint8_t) {return false;}
static bool onTouchEnd(uint8_t) {return false;}
};
#define GOTO_SCREEN(screen) current_screen.goTo(screen::onRefresh);

@ -41,11 +41,15 @@ class Marlin_LCD_API {
static const uint8_t getFeedRate_percent();
static const float getZOffset_mm();
static const bool isAxisPositionKnown(const axis_t axis);
static const bool isMoving();
static const progmem_str getFirmwareName();
static const void setTargetTemp_celsius(const uint8_t extruder, float temp);
static const void setFan_percent(const uint8_t fan, float percent);
static const void setAxisPosition_mm(const Marlin_LCD_API::axis_t axis, float position, float _feedrate_mm_s);
static const void runGCode(progmem_str gcode);
static float clamp(float value, float minimum, float maximum) {return max(min(value,maximum),minimum);};
@ -86,6 +90,26 @@ const float Marlin_LCD_API::getAxisPosition_mm(const Marlin_LCD_API::axis_t axis
}
}
const void Marlin_LCD_API::setAxisPosition_mm(const Marlin_LCD_API::axis_t axis, float position, float _feedrate_mm_s) {
set_destination_from_current();
switch(axis) {
case X: destination[X_AXIS] = position; break;
case Y: destination[Y_AXIS] = position; break;
case Z: destination[Z_AXIS] = position; break;
case E0: destination[E_AXIS] = position; break;
case E1: destination[E_AXIS+1] = position; break;
}
const float old_feedrate = feedrate_mm_s;
feedrate_mm_s = _feedrate_mm_s;
prepare_move_to_destination();
feedrate_mm_s = old_feedrate;
}
const bool Marlin_LCD_API::isMoving() {
return planner.blocks_queued();
}
const float Marlin_LCD_API::getAxisSteps_per_mm(const Marlin_LCD_API::axis_t axis) {
return 0;
}
@ -105,6 +129,10 @@ const uint8_t Marlin_LCD_API::getFeedRate_percent() {
return feedrate_percentage;
}
const void Marlin_LCD_API::runGCode(progmem_str gcode) {
enqueue_and_echo_commands_P((const char*)gcode);
}
const bool Marlin_LCD_API::isAxisPositionKnown(const axis_t axis) {
switch(axis) {
case X: return axis_known_position[X_AXIS]; break;

@ -13,7 +13,7 @@
* got disabled.
*/
#define LULZBOT_FW_VERSION ".8" // Change this with each update
#define LULZBOT_FW_VERSION ".9" // Change this with each update
#if ( \
!defined(LULZBOT_Gladiola_Mini) && \

@ -356,6 +356,7 @@
#include "AO_FT810_Pins.h"
#include "AO_FT810_SPI.h"
#include "AO_FT810_UI_Bitmaps.h"
#include "AO_FT810_UI_Sounds.h"
#include "AO_FT810_UI_Screens.h"
#endif

Loading…
Cancel
Save