Merge remote-tracking branch 'upstream/bugfix-2.0.x' into bf2_granty_fix_15017

2.0.x
Scott Lahteine 5 years ago
commit 09ee5a5da1

@ -242,12 +242,12 @@ jobs:
echo testing STM32F1 targets...
export TEST_PLATFORM="-e STM32F1"
restore_configs
echo use_example_configs STM32F10
use_example_configs STM32F10
echo use_example_configs STM32/STM32F10
use_example_configs STM32/STM32F10
build_marlin_pio ./ ${TEST_PLATFORM}
restore_configs
echo use_example_configs stm32f103ret6
use_example_configs stm32f103ret6
echo use_example_configs STM32/stm32f103ret6
use_example_configs STM32/stm32f103ret6
build_marlin_pio ./ ${TEST_PLATFORM}
restore_configs

@ -359,6 +359,7 @@
* -1 : thermocouple with AD595
* 0 : not used
* 1 : 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
* 331 : (3.3V scaled thermistor 1 table)
* 2 : 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
* 3 : Mendel-parts thermistor (4.7k pullup)
* 4 : 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
@ -402,7 +403,7 @@
* 998 : Dummy Table that ALWAYS reads 25°C or the temperature defined below.
* 999 : Dummy Table that ALWAYS reads 100°C or the temperature defined below.
*
* :{ '0':"Not used", '1':"100k / 4.7k - EPCOS", '2':"200k / 4.7k - ATC Semitec 204GT-2", '3':"Mendel-parts / 4.7k", '4':"10k !! do not use for a hotend. Bad resolution at high temp. !!", '5':"100K / 4.7k - ATC Semitec 104GT-2 (Used in ParCan & J-Head)", '501':"100K Zonestar (Tronxy X3A)", '512':"100k RPW-Ultra hotend thermistor", '6':"100k / 4.7k EPCOS - Not as accurate as Table 1", '7':"100k / 4.7k Honeywell 135-104LAG-J01", '8':"100k / 4.7k 0603 SMD Vishay NTCS0603E3104FXT", '9':"100k / 4.7k GE Sensing AL03006-58.2K-97-G1", '10':"100k / 4.7k RS 198-961", '11':"100k / 4.7k beta 3950 1%", '12':"100k / 4.7k 0603 SMD Vishay NTCS0603E3104FXT (calibrated for Makibox hot bed)", '13':"100k Hisens 3950 1% up to 300°C for hotend 'Simple ONE ' & hotend 'All In ONE'", '18':"ATC Semitec 204GT-2 (4.7k pullup) Dagoma.Fr - MKS_Base_DKU001327" '20':"Pt100 (Ultimainboard V2.x)", '201':"Pt100 (Overlord)", '51':"100k / 1k - EPCOS", '52':"200k / 1k - ATC Semitec 204GT-2", '55':"100k / 1k - ATC Semitec 104GT-2 (Used in ParCan & J-Head)", '60':"100k Maker's Tool Works Kapton Bed Thermistor beta=3950", '61':"100k Formbot / Vivedino 3950 350C thermistor 4.7k pullup", '66':"Dyze Design 4.7M High Temperature thermistor", '67':"Slice Engineering 450C High Temperature thermistor", '70':"the 100K thermistor found in the bq Hephestos 2", '71':"100k / 4.7k Honeywell 135-104LAF-J01", '147':"Pt100 / 4.7k", '1047':"Pt1000 / 4.7k", '110':"Pt100 / 1k (non-standard)", '1010':"Pt1000 / 1k (non standard)", '-4':"Thermocouple + AD8495", '-3':"Thermocouple + MAX31855 (only for sensor 0)", '-2':"Thermocouple + MAX6675 (only for sensor 0)", '-1':"Thermocouple + AD595", '998':"Dummy 1", '999':"Dummy 2", '1000':"Custom thermistor params" }
* :{ '0':"Not used", '1':"100k / 4.7k - EPCOS", '331':"(3.3V thermistor 1)", '2':"200k / 4.7k - ATC Semitec 204GT-2", '3':"Mendel-parts / 4.7k", '4':"10k !! do not use for a hotend. Bad resolution at high temp. !!", '5':"100K / 4.7k - ATC Semitec 104GT-2 (Used in ParCan & J-Head)", '501':"100K Zonestar (Tronxy X3A)", '512':"100k RPW-Ultra hotend thermistor", '6':"100k / 4.7k EPCOS - Not as accurate as Table 1", '7':"100k / 4.7k Honeywell 135-104LAG-J01", '8':"100k / 4.7k 0603 SMD Vishay NTCS0603E3104FXT", '9':"100k / 4.7k GE Sensing AL03006-58.2K-97-G1", '10':"100k / 4.7k RS 198-961", '11':"100k / 4.7k beta 3950 1%", '12':"100k / 4.7k 0603 SMD Vishay NTCS0603E3104FXT (calibrated for Makibox hot bed)", '13':"100k Hisens 3950 1% up to 300°C for hotend 'Simple ONE ' & hotend 'All In ONE'", '18':"ATC Semitec 204GT-2 (4.7k pullup) Dagoma.Fr - MKS_Base_DKU001327" '20':"Pt100 (Ultimainboard V2.x)", '201':"Pt100 (Overlord)", '51':"100k / 1k - EPCOS", '52':"200k / 1k - ATC Semitec 204GT-2", '55':"100k / 1k - ATC Semitec 104GT-2 (Used in ParCan & J-Head)", '60':"100k Maker's Tool Works Kapton Bed Thermistor beta=3950", '61':"100k Formbot / Vivedino 3950 350C thermistor 4.7k pullup", '66':"Dyze Design 4.7M High Temperature thermistor", '67':"Slice Engineering 450C High Temperature thermistor", '70':"the 100K thermistor found in the bq Hephestos 2", '71':"100k / 4.7k Honeywell 135-104LAF-J01", '147':"Pt100 / 4.7k", '1047':"Pt1000 / 4.7k", '110':"Pt100 / 1k (non-standard)", '1010':"Pt1000 / 1k (non standard)", '-4':"Thermocouple + AD8495", '-3':"Thermocouple + MAX31855 (only for sensor 0)", '-2':"Thermocouple + MAX6675 (only for sensor 0)", '-1':"Thermocouple + AD595", '998':"Dummy 1", '999':"Dummy 2", '1000':"Custom thermistor params" }
*/
#define TEMP_SENSOR_0 1
#define TEMP_SENSOR_1 0
@ -2033,6 +2034,12 @@
//
//#define MALYAN_LCD
//
// LulzBot Color Touch UI for FTDI EVE (FT800/FT810) displays
// See Configuration_adv.h for all configuration options.
//
//#define LULZBOT_TOUCH_UI
//
// Third-party or vendor-customized controller interfaces.
// Sources should be installed in 'src/lcd/extensible_ui'.

@ -279,9 +279,10 @@
*/
//#define USE_CONTROLLER_FAN
#if ENABLED(USE_CONTROLLER_FAN)
//#define CONTROLLER_FAN_PIN -1 // Set a custom pin for the controller fan
#define CONTROLLERFAN_SECS 60 // Duration in seconds for the fan to run after all motors are disabled
#define CONTROLLERFAN_SPEED 255 // 255 == full speed
//#define CONTROLLER_FAN_PIN -1 // Set a custom pin for the controller fan
#define CONTROLLERFAN_SECS 60 // Duration in seconds for the fan to run after all motors are disabled
#define CONTROLLERFAN_SPEED 255 // 255 == full speed
//#define CONTROLLERFAN_SPEED_Z_ONLY 127 // Reduce noise on machines that keep Z enabled
#endif
// When first starting the main fan, run it at full speed for the
@ -657,10 +658,10 @@
#endif
#endif
// @section extras
// @section motion
// minimum time in microseconds that a movement needs to take if the buffer is emptied.
#define DEFAULT_MINSEGMENTTIME 20000
// Minimum time that a segment needs to take if the buffer is emptied
#define DEFAULT_MINSEGMENTTIME 20000 // (ms)
// If defined the movements slow down when the look ahead buffer is only half full
#define SLOWDOWN
@ -850,11 +851,35 @@
#define FEEDRATE_CHANGE_BEEP_FREQUENCY 440
#endif
// Include a page of printer information in the LCD Main Menu
//#define LCD_INFO_MENU
#if ENABLED(LCD_INFO_MENU)
//#define LCD_PRINTER_INFO_IS_BOOTSCREEN // Show bootscreen(s) instead of Printer Info pages
#endif
#if HAS_LCD_MENU
// Include a page of printer information in the LCD Main Menu
//#define LCD_INFO_MENU
#if ENABLED(LCD_INFO_MENU)
//#define LCD_PRINTER_INFO_IS_BOOTSCREEN // Show bootscreen(s) instead of Printer Info pages
#endif
// BACK menu items keep the highlight at the top
//#define TURBO_BACK_MENU_ITEM
/**
* LED Control Menu
* Add LED Control to the LCD menu
*/
//#define LED_CONTROL_MENU
#if ENABLED(LED_CONTROL_MENU)
#define LED_COLOR_PRESETS // Enable the Preset Color menu option
#if ENABLED(LED_COLOR_PRESETS)
#define LED_USER_PRESET_RED 255 // User defined RED value
#define LED_USER_PRESET_GREEN 128 // User defined GREEN value
#define LED_USER_PRESET_BLUE 0 // User defined BLUE value
#define LED_USER_PRESET_WHITE 255 // User defined WHITE value
#define LED_USER_PRESET_BRIGHTNESS 255 // User defined intensity
//#define LED_USER_PRESET_STARTUP // Have the printer display the user preset color on startup
#endif
#endif
#endif // HAS_LCD_MENU
// Scroll a longer status message into view
//#define STATUS_MESSAGE_SCROLLING
@ -879,23 +904,6 @@
#endif
#endif
/**
* LED Control Menu
* Enable this feature to add LED Control to the LCD menu
*/
//#define LED_CONTROL_MENU
#if ENABLED(LED_CONTROL_MENU)
#define LED_COLOR_PRESETS // Enable the Preset Color menu option
#if ENABLED(LED_COLOR_PRESETS)
#define LED_USER_PRESET_RED 255 // User defined RED value
#define LED_USER_PRESET_GREEN 128 // User defined GREEN value
#define LED_USER_PRESET_BLUE 0 // User defined BLUE value
#define LED_USER_PRESET_WHITE 255 // User defined WHITE value
#define LED_USER_PRESET_BRIGHTNESS 255 // User defined intensity
//#define LED_USER_PRESET_STARTUP // Have the printer display the user preset color on startup
#endif
#endif // LED_CONTROL_MENU
#if ENABLED(SDSUPPORT)
// Some RAMPS and other boards don't detect when an SD card is inserted. You can work
@ -930,6 +938,7 @@
#if ENABLED(POWER_LOSS_RECOVERY)
//#define POWER_LOSS_PIN 44 // Pin to detect power loss
//#define POWER_LOSS_STATE HIGH // State of pin indicating power loss
//#define POWER_LOSS_PULL // Set pullup / pulldown as appropriate
//#define POWER_LOSS_PURGE_LEN 20 // (mm) Length of filament to purge on resume
//#define POWER_LOSS_RETRACT_LEN 10 // (mm) Length of filament to retract on fail. Requires backup power.
@ -1134,6 +1143,7 @@
//#define STATUS_FAN_FRAMES 3 // :[0,1,2,3,4] Number of fan animation frames
//#define STATUS_HEAT_PERCENT // Show heating in a progress bar
//#define BOOT_MARLIN_LOGO_SMALL // Show a smaller Marlin logo on the Boot Screen (saving 399 bytes of flash)
//#define BOOT_MARLIN_LOGO_ANIMATED // Animated Marlin logo. Costs ~3260 (or ~940) bytes of PROGMEM.
// Frivolous Game Options
//#define MARLIN_BRICKOUT
@ -1143,6 +1153,53 @@
#endif // HAS_GRAPHICAL_LCD
//
// Lulzbot Touch UI
//
#if ENABLED(LULZBOT_TOUCH_UI)
// Display board used
//#define LCD_FTDI_VM800B35A // FTDI 3.5" with FT800 (320x240)
//#define LCD_4DSYSTEMS_4DLCD_FT843 // 4D Systems 4.3" (480x272)
//#define LCD_HAOYU_FT800CB // Haoyu with 4.3" or 5" (480x272)
//#define LCD_HAOYU_FT810CB // Haoyu with 5" (800x480)
//#define LCD_ALEPHOBJECTS_CLCD_UI // Aleph Objects Color LCD UI
// Correct the resolution if not using the stock TFT panel.
//#define TOUCH_UI_320x240
//#define TOUCH_UI_480x272
//#define TOUCH_UI_800x480
// Mappings for boards with a standard RepRapDiscount Display connector
//#define AO_EXP1_PINMAP // AlephObjects CLCD UI EXP1 mapping
//#define AO_EXP2_PINMAP // AlephObjects CLCD UI EXP2 mapping
//#define CR10_TFT_PINMAP // Rudolph Riedel's CR10 pin mapping
//#define OTHER_PIN_LAYOUT // Define pins manually below
#if ENABLED(OTHER_PIN_LAYOUT)
// The pins for CS and MOD_RESET (PD) must be chosen.
#define CLCD_MOD_RESET 9
#define CLCD_SPI_CS 10
// If using software SPI, specify pins for SCLK, MOSI, MISO
//#define CLCD_USE_SOFT_SPI
#if ENABLED(CLCD_USE_SOFT_SPI)
#define CLCD_SOFT_SPI_MOSI 11
#define CLCD_SOFT_SPI_MISO 12
#define CLCD_SOFT_SPI_SCLK 13
#endif
#endif
// Display Orientation. An inverted (i.e. upside-down) display
// is supported on the FT800. The FT810 and beyond also support
// portrait and mirrored orientations.
//#define TOUCH_UI_INVERTED
//#define TOUCH_UI_PORTRAIT
//#define TOUCH_UI_MIRRORED
// Use a numeric passcode for "Screen lock" keypad.
// (recommended for smaller displays)
//#define TOUCH_UI_PASSCODE
#endif
// @section safety
/**
@ -2242,6 +2299,13 @@
*/
#define EXTENDED_CAPABILITIES_REPORT
/**
* Expected Printer Check
* Add the M16 G-code to compare a string to the MACHINE_NAME.
* M16 with a non-matching string causes the printer to halt.
*/
//#define EXPECTED_PRINTER_CHECK
/**
* Disable all Volumetric extrusion options
*/
@ -2296,6 +2360,13 @@
//#define VARIABLE_G0_FEEDRATE // The G0 feedrate is set by F in G0 motion mode
#endif
/**
* Startup commands
*
* Execute certain G-code commands immediately after power-on.
*/
//#define STARTUP_COMMANDS "M17 Z"
/**
* G-code Macros
*

@ -281,42 +281,44 @@ else ifeq ($(HARDWARE_MOTHERBOARD),1205)
else ifeq ($(HARDWARE_MOTHERBOARD),1300)
# Cartesio CN Controls V12
else ifeq ($(HARDWARE_MOTHERBOARD),1301)
# Cheaptronic v1.0
# Cartesio CN Controls V15
else ifeq ($(HARDWARE_MOTHERBOARD),1302)
# Cheaptronic v2.0
# Cheaptronic v1.0
else ifeq ($(HARDWARE_MOTHERBOARD),1303)
# Makerbot Mightyboard Revision E
# Cheaptronic v2.0
else ifeq ($(HARDWARE_MOTHERBOARD),1304)
# Megatronics
# Makerbot Mightyboard Revision E
else ifeq ($(HARDWARE_MOTHERBOARD),1305)
# Megatronics v2.0
# Megatronics
else ifeq ($(HARDWARE_MOTHERBOARD),1306)
# Megatronics v3.0
# Megatronics v2.0
else ifeq ($(HARDWARE_MOTHERBOARD),1307)
# Megatronics v3.1
# Megatronics v3.0
else ifeq ($(HARDWARE_MOTHERBOARD),1308)
# Megatronics v3.2
# Megatronics v3.1
else ifeq ($(HARDWARE_MOTHERBOARD),1309)
# Elefu Ra Board (v3)
# Megatronics v3.2
else ifeq ($(HARDWARE_MOTHERBOARD),1310)
# Leapfrog
# Elefu Ra Board (v3)
else ifeq ($(HARDWARE_MOTHERBOARD),1311)
# Mega controller
# Leapfrog
else ifeq ($(HARDWARE_MOTHERBOARD),1312)
# Geeetech GT2560 Rev B for Mecreator2
# Mega controller
else ifeq ($(HARDWARE_MOTHERBOARD),1313)
# Geeetech GT2560 Rev. A
# Geeetech GT2560 Rev B for Mecreator2
else ifeq ($(HARDWARE_MOTHERBOARD),1314)
# Geeetech GT2560 Rev. A+ (with auto level probe)
# Geeetech GT2560 Rev. A
else ifeq ($(HARDWARE_MOTHERBOARD),1315)
# Geeetech GT2560 Rev B for A10(M/D)
# Geeetech GT2560 Rev. A+ (with auto level probe)
else ifeq ($(HARDWARE_MOTHERBOARD),1316)
# Geeetech GT2560 Rev B for A20(M/D)
# Geeetech GT2560 Rev B for A10(M/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1317)
# Einstart retrofit
# Geeetech GT2560 Rev B for A20(M/D)
else ifeq ($(HARDWARE_MOTHERBOARD),1318)
# Wanhao 0ne+ i3 Mini
# Einstart retrofit
else ifeq ($(HARDWARE_MOTHERBOARD),1319)
# Wanhao 0ne+ i3 Mini
else ifeq ($(HARDWARE_MOTHERBOARD),1320)
#
# ATmega1281, ATmega2561

@ -23,6 +23,7 @@
#include "../../../inc/MarlinConfigPre.h"
#include "../../shared/Marduino.h"
#include <U8glib.h>
void u8g_SetPIOutput_DUE(u8g_t *u8g, uint8_t pin_index);
void u8g_SetPILevel_DUE(u8g_t *u8g, uint8_t pin_index, uint8_t level);

@ -70,7 +70,7 @@
const uint32_t mask = MASK(DIO ## IO ## _PIN); \
if (V) port->PIO_SODR = mask; \
else port->PIO_CODR = mask; \
} while(0)
}while(0)
// Toggle a pin
#define _TOGGLE(IO) _WRITE(IO, !READ(IO))

@ -112,7 +112,7 @@
* \def unused
* \brief Marking \a v as a unused parameter or value.
*/
#define unused(v) do { (void)(v); } while(0)
#define unused(v) do { (void)(v); }while(0)
/**
* \def barrier
@ -169,7 +169,7 @@
* heuristics and inline the function no matter how big it thinks it
* becomes.
*/
#if defined(__CC_ARM)
#ifdef __CC_ARM
# define __always_inline __forceinline
#elif (defined __GNUC__)
#ifdef __always_inline
@ -187,7 +187,7 @@
* This annotation instructs the compiler to ignore its inlining
* heuristics and not inline the function.
*/
#if defined(__CC_ARM)
#ifdef __CC_ARM
# define __no_inline __attribute__((noinline))
#elif (defined __GNUC__)
# define __no_inline __attribute__((__noinline__))
@ -204,7 +204,7 @@
*
* \param expr Expression to evaluate and supposed to be nonzero.
*/
#if defined(_ASSERT_ENABLE_)
#ifdef _ASSERT_ENABLE_
# if defined(TEST_SUITE_DEFINE_ASSERT_MACRO)
// Assert() is defined in unit_test/suite.h
# include "unit_test/suite.h"
@ -998,14 +998,14 @@ typedef U8 Byte; //!< 8-bit unsigned integer.
#endif // #ifndef __ASSEMBLY__
#if defined(__ICCARM__)
#ifdef __ICCARM__
#define SHORTENUM __packed
#elif defined(__GNUC__)
#define SHORTENUM __attribute__((packed))
#endif
/* No operation */
#if defined(__ICCARM__)
#ifdef __ICCARM__
#define nop() __no_operation()
#elif defined(__GNUC__)
#define nop() (__NOP())

@ -142,10 +142,10 @@ public:
void print_bin(uint32_t value, uint8_t num_digits) {
uint32_t mask = 1 << (num_digits -1);
for (uint8_t i = 0; i < num_digits; i++) {
if (!(i % 4) && i) write(' ');
if (!(i % 16) && i) write(' ');
if (value & mask) write('1');
else write('0');
if (!(i % 4) && i) write(' ');
if (!(i % 16) && i) write(' ');
if (value & mask) write('1');
else write('0');
value <<= 1;
}
}

@ -1,13 +1,37 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef TARGET_LPC1768
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(EMERGENCY_PARSER)
#include "../../feature/emergency_parser.h"
EmergencyParser::State emergency_state;
bool CDC_RecvCallback(const char buffer) {
emergency_parser.update(emergency_state, buffer);
return true;
}
#endif // ENABLED(EMERGENCY_PARSER)
#include "../../feature/emergency_parser.h"
EmergencyParser::State emergency_state;
bool CDC_RecvCallback(const char buffer) {
emergency_parser.update(emergency_state, buffer);
return true;
}
#endif // EMERGENCY_PARSER
#endif // TARGET_LPC1768

@ -115,12 +115,12 @@ HAL_SERVO_TIMER_ISR() {
tc->COUNT16.CC[tcChannel].reg = (uint16_t)(tcCounterValue - 4UL); // at least REFRESH_INTERVAL has elapsed
}
if (tcChannel == 0) {
SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
// Clear the interrupt
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
}
else {
SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
// Clear the interrupt
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1;
}

@ -243,6 +243,7 @@
#define DIO5_PIN PIN_PC21
#define DIO16_PIN PIN_PC22
#define DIO17_PIN PIN_PC23
#define DIO88_PIN PIN_PC24 // NEOPIXEL
// PORTD
#define DIO22_PIN PIN_PD12
#define DIO6_PIN PIN_PD20

@ -32,7 +32,7 @@
#endif
#if ENABLED(EMERGENCY_PARSER)
#error "EMERGENCY_PARSER is not yet implemented for STM32F4. Disable EMERGENCY_PARSER to continue."
#error "EMERGENCY_PARSER is not yet implemented for SAMD51. Disable EMERGENCY_PARSER to continue."
#endif
#if ENABLED(SDIO_SUPPORT)

@ -22,7 +22,6 @@
*/
#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
#include "../../inc/MarlinConfig.h"
#include <SPI.h>
@ -73,16 +72,22 @@ void spiInit(uint8_t spiRate) {
// Use datarates Marlin uses
uint32_t clock;
switch (spiRate) {
case SPI_FULL_SPEED: clock = 20000000; break; // 13.9mhz=20000000 6.75mhz=10000000 3.38mhz=5000000 .833mhz=1000000
case SPI_HALF_SPEED: clock = 5000000; break;
case SPI_QUARTER_SPEED: clock = 2500000; break;
case SPI_EIGHTH_SPEED: clock = 1250000; break;
case SPI_SPEED_5: clock = 625000; break;
case SPI_SPEED_6: clock = 300000; break;
default:
clock = 4000000; // Default from the SPI library
case SPI_FULL_SPEED: clock = 20000000; break; // 13.9mhz=20000000 6.75mhz=10000000 3.38mhz=5000000 .833mhz=1000000
case SPI_HALF_SPEED: clock = 5000000; break;
case SPI_QUARTER_SPEED: clock = 2500000; break;
case SPI_EIGHTH_SPEED: clock = 1250000; break;
case SPI_SPEED_5: clock = 625000; break;
case SPI_SPEED_6: clock = 300000; break;
default:
clock = 4000000; // Default from the SPI library
}
spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
#if defined(MISO_PIN) && defined(SDSS) && defined(MOSI_PIN) && defined(SCK_PIN)
SPI.setMISO(MISO_PIN);
SPI.setSSEL(SDSS);
SPI.setMOSI(MOSI_PIN);
SPI.setSCLK(SCK_PIN);
#endif
SPI.begin();
}

@ -53,7 +53,7 @@ void FastIO_init(); // Must be called before using fast io macros
#define _WRITE(IO, V) do { \
if (V) FastIOPortMap[STM_PORT(digitalPin[IO])]->BSRR = _BV32(STM_PIN(digitalPin[IO])) ; \
else FastIOPortMap[STM_PORT(digitalPin[IO])]->BRR = _BV32(STM_PIN(digitalPin[IO])) ; \
} while(0)
}while(0)
#else
#define _WRITE(IO, V) (FastIOPortMap[STM_PORT(digitalPin[IO])]->BSRR = _BV32(STM_PIN(digitalPin[IO]) + (V ? 0 : 16)))
#endif

@ -189,7 +189,7 @@ void port_print(const pin_t Ard_num) {
for (Index = 0; Index < NUMBER_PINS_TOTAL; Index++)
if (Ard_num == GET_PIN_MAP_PIN_M43(Index)) break;
char * const ppa = pin_xref[Index].Port_pin_alpha;
const char * ppa = pin_xref[Index].Port_pin_alpha;
sprintf_P(buffer, PSTR("%s"), ppa);
SERIAL_ECHO(buffer);
if (ppa[3] == '\0') SERIAL_CHAR(' ');

@ -33,7 +33,7 @@
#ifdef __STM32F1__
#include "../../inc/MarlinConfig.h"
#include <SPI.h>
#include "SPI.h"
// ------------------------
// Public functions

@ -0,0 +1,741 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Wirish SPI implementation.
*/
#ifdef __STM32F1__
#include "SPI.h"
#include <libmaple/timer.h>
#include <libmaple/util.h>
#include <libmaple/rcc.h>
#include <boards.h>
#include <wirish.h>
/** Time in ms for DMA receive timeout */
#define DMA_TIMEOUT 100
#if CYCLES_PER_MICROSECOND != 72
#warning "Unexpected clock speed; SPI frequency calculation will be incorrect"
#endif
struct spi_pins {
uint8_t nss;
uint8_t sck;
uint8_t miso;
uint8_t mosi;
};
static const spi_pins* dev_to_spi_pins(spi_dev *dev);
static void configure_gpios(spi_dev *dev, bool as_master);
static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq);
#if (BOARD_NR_SPI >= 3) && !defined(STM32_HIGH_DENSITY)
#error "The SPI library is misconfigured: 3 SPI ports only available on high density STM32 devices"
#endif
static const spi_pins board_spi_pins[] __FLASH__ = {
#if BOARD_NR_SPI >= 1
{ BOARD_SPI1_NSS_PIN,
BOARD_SPI1_SCK_PIN,
BOARD_SPI1_MISO_PIN,
BOARD_SPI1_MOSI_PIN },
#endif
#if BOARD_NR_SPI >= 2
{ BOARD_SPI2_NSS_PIN,
BOARD_SPI2_SCK_PIN,
BOARD_SPI2_MISO_PIN,
BOARD_SPI2_MOSI_PIN },
#endif
#if BOARD_NR_SPI >= 3
{ BOARD_SPI3_NSS_PIN,
BOARD_SPI3_SCK_PIN,
BOARD_SPI3_MISO_PIN,
BOARD_SPI3_MOSI_PIN },
#endif
};
#if BOARD_NR_SPI >= 1
static void (*_spi1_this);
#endif
#if BOARD_NR_SPI >= 2
static void (*_spi2_this);
#endif
#if BOARD_NR_SPI >= 3
static void (*_spi3_this);
#endif
/**
* Constructor
*/
SPIClass::SPIClass(uint32_t spi_num) {
_currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed
switch (spi_num) {
#if BOARD_NR_SPI >= 1
case 1:
_currentSetting->spi_d = SPI1;
_spi1_this = (void*)this;
break;
#endif
#if BOARD_NR_SPI >= 2
case 2:
_currentSetting->spi_d = SPI2;
_spi2_this = (void*)this;
break;
#endif
#if BOARD_NR_SPI >= 3
case 3:
_currentSetting->spi_d = SPI3;
_spi3_this = (void*)this;
break;
#endif
default: ASSERT(0);
}
// Init things specific to each SPI device
// clock divider setup is a bit of hack, and needs to be improved at a later date.
#if BOARD_NR_SPI >= 1
_settings[0].spi_d = SPI1;
_settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock);
_settings[0].spiDmaDev = DMA1;
_settings[0].spiTxDmaChannel = DMA_CH3;
_settings[0].spiRxDmaChannel = DMA_CH2;
#endif
#if BOARD_NR_SPI >= 2
_settings[1].spi_d = SPI2;
_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock);
_settings[1].spiDmaDev = DMA1;
_settings[1].spiTxDmaChannel = DMA_CH5;
_settings[1].spiRxDmaChannel = DMA_CH4;
#endif
#if BOARD_NR_SPI >= 3
_settings[2].spi_d = SPI3;
_settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock);
_settings[2].spiDmaDev = DMA2;
_settings[2].spiTxDmaChannel = DMA_CH2;
_settings[2].spiRxDmaChannel = DMA_CH1;
#endif
// added for DMA callbacks.
_currentSetting->state = SPI_STATE_IDLE;
}
/*
* Set up/tear down
*/
void SPIClass::updateSettings() {
uint32_t flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS);
spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags);
}
void SPIClass::begin() {
spi_init(_currentSetting->spi_d);
configure_gpios(_currentSetting->spi_d, 1);
updateSettings();
// added for DMA callbacks.
_currentSetting->state = SPI_STATE_READY;
}
void SPIClass::beginSlave() {
spi_init(_currentSetting->spi_d);
configure_gpios(_currentSetting->spi_d, 0);
uint32_t flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize);
spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags);
// added for DMA callbacks.
_currentSetting->state = SPI_STATE_READY;
}
void SPIClass::end() {
if (!spi_is_enabled(_currentSetting->spi_d))
return;
// Follows RM0008's sequence for disabling a SPI in master/slave
// full duplex mode.
while (spi_is_rx_nonempty(_currentSetting->spi_d)) {
// FIXME [0.1.0] remove this once you have an interrupt based driver
volatile uint16_t rx __attribute__((unused)) = spi_rx_reg(_currentSetting->spi_d);
}
while (!spi_is_tx_empty(_currentSetting->spi_d)) {};
while (spi_is_busy(_currentSetting->spi_d)) {};
spi_peripheral_disable(_currentSetting->spi_d);
// added for DMA callbacks.
// Need to add unsetting the callbacks for the DMA channels.
_currentSetting->state = SPI_STATE_IDLE;
}
/* Roger Clark added 3 functions */
void SPIClass::setClockDivider(uint32_t clockDivider) {
_currentSetting->clockDivider = clockDivider;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_BR);
_currentSetting->spi_d->regs->CR1 = cr1 | (clockDivider & SPI_CR1_BR);
}
void SPIClass::setBitOrder(BitOrder bitOrder) {
_currentSetting->bitOrder = bitOrder;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_LSBFIRST);
if (bitOrder == LSBFIRST) cr1 |= SPI_CR1_LSBFIRST;
_currentSetting->spi_d->regs->CR1 = cr1;
}
/* Victor Perez. Added to test changing datasize from 8 to 16 bit modes on the fly.
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
*
*/
void SPIClass::setDataSize(uint32_t datasize) {
_currentSetting->dataSize = datasize;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_DFF);
uint8_t en = spi_is_enabled(_currentSetting->spi_d);
spi_peripheral_disable(_currentSetting->spi_d);
_currentSetting->spi_d->regs->CR1 = cr1 | (datasize & SPI_CR1_DFF) | en;
}
void SPIClass::setDataMode(uint8_t dataMode) {
/* Notes:
As far as I can tell, the AVR numbers for dataMode appear to match the numbers required by the STM32
From the AVR doc http://www.atmel.com/images/doc2585.pdf section 2.4
SPI Mode CPOL CPHA Shift SCK-edge Capture SCK-edge
0 0 0 Falling Rising
1 0 1 Rising Falling
2 1 0 Rising Falling
3 1 1 Falling Rising
On the STM32 it appears to be
bit 1 - CPOL : Clock polarity
(This bit should not be changed when communication is ongoing)
0 : CLK to 0 when idle
1 : CLK to 1 when idle
bit 0 - CPHA : Clock phase
(This bit should not be changed when communication is ongoing)
0 : The first clock transition is the first data capture edge
1 : The second clock transition is the first data capture edge
If someone finds this is not the case or sees a logic error with this let me know ;-)
*/
_currentSetting->dataMode = dataMode;
uint32_t cr1 = _currentSetting->spi_d->regs->CR1 & ~(SPI_CR1_CPOL|SPI_CR1_CPHA);
_currentSetting->spi_d->regs->CR1 = cr1 | (dataMode & (SPI_CR1_CPOL|SPI_CR1_CPHA));
}
void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) {
setBitOrder(settings.bitOrder);
setDataMode(settings.dataMode);
setDataSize(settings.dataSize);
setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock));
begin();
}
void SPIClass::beginTransactionSlave(SPISettings settings) {
setBitOrder(settings.bitOrder);
setDataMode(settings.dataMode);
setDataSize(settings.dataSize);
beginSlave();
}
void SPIClass::endTransaction() { }
/*
* I/O
*/
uint16_t SPIClass::read() {
while ( spi_is_rx_nonempty(_currentSetting->spi_d)==0 ) ;
return (uint16)spi_rx_reg(_currentSetting->spi_d);
}
void SPIClass::read(uint8_t *buf, uint32_t len) {
if (len == 0) return;
spi_rx_reg(_currentSetting->spi_d); // clear the RX buffer in case a byte is waiting on it.
spi_reg_map * regs = _currentSetting->spi_d->regs;
// start sequence: write byte 0
regs->DR = 0x00FF; // write the first byte
// main loop
while ( (--len) ) {
while( !(regs->SR & SPI_SR_TXE) ); // wait for TXE flag
noInterrupts(); // go atomic level - avoid interrupts to surely get the previously received data
regs->DR = 0x00FF; // write the next data item to be transmitted into the SPI_DR register. This clears the TXE flag.
while ( !(regs->SR & SPI_SR_RXNE) ); // wait till data is available in the DR register
*buf++ = (uint8)(regs->DR); // read and store the received byte. This clears the RXNE flag.
interrupts(); // let systick do its job
}
// read remaining last byte
while ( !(regs->SR & SPI_SR_RXNE) ) {} // wait till data is available in the Rx register
*buf++ = (uint8)(regs->DR); // read and store the received byte
}
void SPIClass::write(uint16_t data) {
/* Added for 16bit data Victor Perez. Roger Clark
* Improved speed by just directly writing the single byte to the SPI data reg and wait for completion,
* by taking the Tx code from transfer(byte)
* This almost doubles the speed of this function.
*/
spi_tx_reg(_currentSetting->spi_d, data); // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
}
void SPIClass::write16(uint16_t data) {
// Added by stevestrong: write two consecutive bytes in 8 bit mode (DFF=0)
spi_tx_reg(_currentSetting->spi_d, data>>8); // write high byte
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // Wait until TXE=1
spi_tx_reg(_currentSetting->spi_d, data); // write low byte
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // Wait until TXE=1
while (spi_is_busy(_currentSetting->spi_d) != 0); // wait until BSY=0
}
void SPIClass::write(uint16_t data, uint32_t n) {
// Added by stevstrong: Repeatedly send same data by the specified number of times
spi_reg_map * regs = _currentSetting->spi_d->regs;
while ( (n--)>0 ) {
regs->DR = data; // write the data to be transmitted into the SPI_DR register (this clears the TXE flag)
while ( (regs->SR & SPI_SR_TXE)==0 ) ; // wait till Tx empty
}
while ( (regs->SR & SPI_SR_BSY) != 0); // wait until BSY=0 before returning
}
void SPIClass::write(const void *data, uint32_t length) {
spi_dev * spi_d = _currentSetting->spi_d;
spi_tx(spi_d, data, length); // data can be array of bytes or words
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
}
uint8_t SPIClass::transfer(uint8_t byte) const {
spi_dev * spi_d = _currentSetting->spi_d;
spi_rx_reg(spi_d); // read any previous data
spi_tx_reg(spi_d, byte); // Write the data item to be transmitted into the SPI_DR register
while (spi_is_tx_empty(spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
return (uint8)spi_rx_reg(spi_d); // "... and read the last received data."
}
uint16_t SPIClass::transfer16(uint16_t data) const {
// Modified by stevestrong: write & read two consecutive bytes in 8 bit mode (DFF=0)
// This is more effective than two distinct byte transfers
spi_dev * spi_d = _currentSetting->spi_d;
spi_rx_reg(spi_d); // read any previous data
spi_tx_reg(spi_d, data>>8); // write high byte
while (spi_is_tx_empty(spi_d) == 0); // wait until TXE=1
while (spi_is_busy(spi_d) != 0); // wait until BSY=0
uint16_t ret = spi_rx_reg(spi_d)<<8; // read and shift high byte
spi_tx_reg(spi_d, data); // write low byte
while (spi_is_tx_empty(spi_d) == 0); // wait until TXE=1
while (spi_is_busy(spi_d) != 0); // wait until BSY=0
ret += spi_rx_reg(spi_d); // read low byte
return ret;
}
/* Roger Clark and Victor Perez, 2015
* Performs a DMA SPI transfer with at least a receive buffer.
* If a TX buffer is not provided, FF is sent over and over for the lenght of the transfer.
* On exit TX buffer is not modified, and RX buffer cotains the received data.
* Still in progress.
*/
void SPIClass::dmaTransferSet(const void *transmitBuf, void *receiveBuf) {
dma_init(_currentSetting->spiDmaDev);
//spi_rx_dma_enable(_currentSetting->spi_d);
//spi_tx_dma_enable(_currentSetting->spi_d);
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, receiveBuf, dma_bit_size, (DMA_MINC_MODE | DMA_TRNS_CMPLT ));// receive buffer DMA
if (!transmitBuf) {
transmitBuf = &ff;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, (volatile void*)transmitBuf, dma_bit_size, (DMA_FROM_MEM));// Transmit FF repeatedly
}
else {
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, (volatile void*)transmitBuf, dma_bit_size, (DMA_MINC_MODE | DMA_FROM_MEM ));// Transmit buffer DMA
}
dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW);
dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, DMA_PRIORITY_VERY_HIGH);
}
uint8_t SPIClass::dmaTransferRepeat(uint16_t length) {
if (length == 0) return 0;
if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) spi_rx_reg(_currentSetting->spi_d);
_currentSetting->state = SPI_STATE_TRANSFER;
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length);
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
spi_rx_dma_enable(_currentSetting->spi_d);
spi_tx_dma_enable(_currentSetting->spi_d);
if (_currentSetting->receiveCallback)
return 0;
//uint32_t m = millis();
uint8_t b = 0;
uint32_t m = millis();
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1) == 0) {
//Avoid interrupts and just loop waiting for the flag to be set.
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
}
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
spi_tx_dma_disable(_currentSetting->spi_d);
spi_rx_dma_disable(_currentSetting->spi_d);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
_currentSetting->state = SPI_STATE_READY;
return b;
}
/* Roger Clark and Victor Perez, 2015
* Performs a DMA SPI transfer with at least a receive buffer.
* If a TX buffer is not provided, FF is sent over and over for the length of the transfer.
* On exit TX buffer is not modified, and RX buffer contains the received data.
* Still in progress.
*/
uint8_t SPIClass::dmaTransfer(const void *transmitBuf, void *receiveBuf, uint16_t length) {
dmaTransferSet(transmitBuf, receiveBuf);
return dmaTransferRepeat(length);
}
/* Roger Clark and Victor Perez, 2015
* Performs a DMA SPI send using a TX buffer.
* On exit TX buffer is not modified.
* Still in progress.
* 2016 - stevstrong - reworked to automatically detect bit size from SPI setting
*/
void SPIClass::dmaSendSet(const void * transmitBuf, bool minc) {
uint32_t flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
dma_init(_currentSetting->spiDmaDev);
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, dma_bit_size,
(volatile void*)transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
dma_set_priority(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, DMA_PRIORITY_LOW);
}
uint8_t SPIClass::dmaSendRepeat(uint16_t length) {
if (length == 0) return 0;
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
_currentSetting->state = SPI_STATE_TRANSMIT;
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
spi_tx_dma_enable(_currentSetting->spi_d);
if (_currentSetting->transmitCallback)
return 0;
uint32_t m = millis();
uint8_t b = 0;
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {
//Avoid interrupts and just loop waiting for the flag to be set.
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
}
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
spi_tx_dma_disable(_currentSetting->spi_d);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
_currentSetting->state = SPI_STATE_READY;
return b;
}
uint8_t SPIClass::dmaSend(const void * transmitBuf, uint16_t length, bool minc) {
dmaSendSet(transmitBuf, minc);
return dmaSendRepeat(length);
}
uint8_t SPIClass::dmaSendAsync(const void * transmitBuf, uint16_t length, bool minc) {
uint8_t b = 0;
if (_currentSetting->state != SPI_STATE_READY) {
uint32_t m = millis();
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & DMA_ISR_TCIF1)==0) {
//Avoid interrupts and just loop waiting for the flag to be set.
//delayMicroseconds(10);
if ((millis() - m) > DMA_TIMEOUT) { b = 2; break; }
}
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
spi_tx_dma_disable(_currentSetting->spi_d);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
_currentSetting->state = SPI_STATE_READY;
}
if (length == 0) return 0;
uint32_t flags = ( (DMA_MINC_MODE*minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
dma_init(_currentSetting->spiDmaDev);
// TX
dma_xfer_size dma_bit_size = (_currentSetting->dataSize==DATA_SIZE_16BIT) ? DMA_SIZE_16BITS : DMA_SIZE_8BITS;
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR,
dma_bit_size, (volatile void*)transmitBuf, dma_bit_size, flags);// Transmit buffer DMA
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
spi_tx_dma_enable(_currentSetting->spi_d);
_currentSetting->state = SPI_STATE_TRANSMIT;
return b;
}
/**
* New functions added to manage callbacks.
* Victor Perez 2017
*/
void SPIClass::onReceive(void(*callback)(void)) {
_currentSetting->receiveCallback = callback;
if (callback) {
switch (_currentSetting->spi_d->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default:
ASSERT(0);
}
}
else {
dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
}
}
void SPIClass::onTransmit(void(*callback)(void)) {
_currentSetting->transmitCallback = callback;
if (callback) {
switch (_currentSetting->spi_d->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi1EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi2EventCallback);
break;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3:
dma_attach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &SPIClass::_spi3EventCallback);
break;
#endif
default:
ASSERT(0);
}
}
else {
dma_detach_interrupt(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
}
}
/**
* TODO: check if better to first call the customer code, next disable the DMA requests.
* Also see if we need to check whether callbacks are set or not, may be better to be checked
* during the initial setup and only set the callback to EventCallback if they are set.
*/
void SPIClass::EventCallback() {
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0"
switch (_currentSetting->state) {
case SPI_STATE_TRANSFER:
while (spi_is_rx_nonempty(_currentSetting->spi_d));
_currentSetting->state = SPI_STATE_READY;
spi_tx_dma_disable(_currentSetting->spi_d);
spi_rx_dma_disable(_currentSetting->spi_d);
//dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
//dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
if (_currentSetting->receiveCallback)
_currentSetting->receiveCallback();
break;
case SPI_STATE_TRANSMIT:
_currentSetting->state = SPI_STATE_READY;
spi_tx_dma_disable(_currentSetting->spi_d);
//dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
if (_currentSetting->transmitCallback)
_currentSetting->transmitCallback();
break;
default:
break;
}
}
void SPIClass::attachInterrupt() {
// Should be enableInterrupt()
}
void SPIClass::detachInterrupt() {
// Should be disableInterrupt()
}
/*
* Pin accessors
*/
uint8_t SPIClass::misoPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->miso;
}
uint8_t SPIClass::mosiPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->mosi;
}
uint8_t SPIClass::sckPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->sck;
}
uint8_t SPIClass::nssPin() {
return dev_to_spi_pins(_currentSetting->spi_d)->nss;
}
/*
* Deprecated functions
*/
uint8_t SPIClass::send(uint8_t data) {
this->write(data);
return 1;
}
uint8_t SPIClass::send(uint8_t *buf, uint32_t len) {
this->write(buf, len);
return len;
}
uint8_t SPIClass::recv() {
return this->read();
}
/*
* DMA call back functions, one per port.
*/
#if BOARD_NR_SPI >= 1
void SPIClass::_spi1EventCallback() {
reinterpret_cast<class SPIClass*>(_spi1_this)->EventCallback();
}
#endif
#if BOARD_NR_SPI >= 2
void SPIClass::_spi2EventCallback() {
reinterpret_cast<class SPIClass*>(_spi2_this)->EventCallback();
}
#endif
#if BOARD_NR_SPI >= 3
void SPIClass::_spi3EventCallback() {
reinterpret_cast<class SPIClass*>(_spi3_this)->EventCallback();
}
#endif
/*
* Auxiliary functions
*/
static const spi_pins* dev_to_spi_pins(spi_dev *dev) {
switch (dev->clk_id) {
#if BOARD_NR_SPI >= 1
case RCC_SPI1: return board_spi_pins;
#endif
#if BOARD_NR_SPI >= 2
case RCC_SPI2: return board_spi_pins + 1;
#endif
#if BOARD_NR_SPI >= 3
case RCC_SPI3: return board_spi_pins + 2;
#endif
default: return NULL;
}
}
static void disable_pwm(const stm32_pin_info *i) {
if (i->timer_device)
timer_set_mode(i->timer_device, i->timer_channel, TIMER_DISABLED);
}
static void configure_gpios(spi_dev *dev, bool as_master) {
const spi_pins *pins = dev_to_spi_pins(dev);
if (!pins) return;
const stm32_pin_info *nssi = &PIN_MAP[pins->nss],
*scki = &PIN_MAP[pins->sck],
*misoi = &PIN_MAP[pins->miso],
*mosii = &PIN_MAP[pins->mosi];
disable_pwm(nssi);
disable_pwm(scki);
disable_pwm(misoi);
disable_pwm(mosii);
spi_config_gpios(dev, as_master, nssi->gpio_device, nssi->gpio_bit,
scki->gpio_device, scki->gpio_bit, misoi->gpio_bit,
mosii->gpio_bit);
}
static const spi_baud_rate baud_rates[8] __FLASH__ = {
SPI_BAUD_PCLK_DIV_2,
SPI_BAUD_PCLK_DIV_4,
SPI_BAUD_PCLK_DIV_8,
SPI_BAUD_PCLK_DIV_16,
SPI_BAUD_PCLK_DIV_32,
SPI_BAUD_PCLK_DIV_64,
SPI_BAUD_PCLK_DIV_128,
SPI_BAUD_PCLK_DIV_256,
};
/*
* Note: This assumes you're on a LeafLabs-style board
* (CYCLES_PER_MICROSECOND == 72, APB2 at 72MHz, APB1 at 36MHz).
*/
static spi_baud_rate determine_baud_rate(spi_dev *dev, uint32_t freq) {
uint32_t clock = 0;
switch (rcc_dev_clk(dev->clk_id)) {
case RCC_AHB:
case RCC_APB2: clock = STM32_PCLK2; break; // 72 Mhz
case RCC_APB1: clock = STM32_PCLK1; break; // 36 Mhz
}
clock >>= 1;
uint8_t i = 0;
while (i < 7 && freq < clock) { clock >>= 1; i++; }
return baud_rates[i];
}
SPIClass SPI(1);
#endif // __STM32F1__

@ -0,0 +1,409 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
#pragma once
#include <libmaple/libmaple_types.h>
#include <libmaple/spi.h>
#include <libmaple/dma.h>
#include <boards.h>
#include <stdint.h>
#include <wirish.h>
// SPI_HAS_TRANSACTION means SPI has
// - beginTransaction()
// - endTransaction()
// - usingInterrupt()
// - SPISetting(clock, bitOrder, dataMode)
//#define SPI_HAS_TRANSACTION
#define SPI_CLOCK_DIV2 SPI_BAUD_PCLK_DIV_2
#define SPI_CLOCK_DIV4 SPI_BAUD_PCLK_DIV_4
#define SPI_CLOCK_DIV8 SPI_BAUD_PCLK_DIV_8
#define SPI_CLOCK_DIV16 SPI_BAUD_PCLK_DIV_16
#define SPI_CLOCK_DIV32 SPI_BAUD_PCLK_DIV_32
#define SPI_CLOCK_DIV64 SPI_BAUD_PCLK_DIV_64
#define SPI_CLOCK_DIV128 SPI_BAUD_PCLK_DIV_128
#define SPI_CLOCK_DIV256 SPI_BAUD_PCLK_DIV_256
/*
* Roger Clark. 20150106
* Commented out redundant AVR defined
*
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
#if defined(EIMSK)
#define SPI_AVR_EIMSK EIMSK
#elif defined(GICR)
#define SPI_AVR_EIMSK GICR
#elif defined(GIMSK)
#define SPI_AVR_EIMSK GIMSK
#endif
*/
#ifndef STM32_LSBFIRST
#define STM32_LSBFIRST 0
#endif
#ifndef STM32_MSBFIRST
#define STM32_MSBFIRST 1
#endif
// PC13 or PA4
#define BOARD_SPI_DEFAULT_SS PA4
//#define BOARD_SPI_DEFAULT_SS PC13
#define SPI_MODE0 SPI_MODE_0
#define SPI_MODE1 SPI_MODE_1
#define SPI_MODE2 SPI_MODE_2
#define SPI_MODE3 SPI_MODE_3
#define DATA_SIZE_8BIT SPI_CR1_DFF_8_BIT
#define DATA_SIZE_16BIT SPI_CR1_DFF_16_BIT
typedef enum {
SPI_STATE_IDLE,
SPI_STATE_READY,
SPI_STATE_RECEIVE,
SPI_STATE_TRANSMIT,
SPI_STATE_TRANSFER
} spi_mode_t;
class SPISettings {
public:
SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) {
if (__builtin_constant_p(clock))
init_AlwaysInline(clock, bitOrder, dataMode, DATA_SIZE_8BIT);
else
init_MightInline(clock, bitOrder, dataMode, DATA_SIZE_8BIT);
}
SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) {
if (__builtin_constant_p(clock))
init_AlwaysInline(clock, bitOrder, dataMode, dataSize);
else
init_MightInline(clock, bitOrder, dataMode, dataSize);
}
SPISettings(uint32_t clock) {
if (__builtin_constant_p(clock))
init_AlwaysInline(clock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
else
init_MightInline(clock, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
}
SPISettings() {
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0, DATA_SIZE_8BIT);
}
private:
void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) {
init_AlwaysInline(clock, bitOrder, dataMode, dataSize);
}
void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode, uint32_t dataSize) __attribute__((__always_inline__)) {
this->clock = clock;
this->bitOrder = bitOrder;
this->dataMode = dataMode;
this->dataSize = dataSize;
}
uint32_t clock;
uint32_t dataSize;
uint32_t clockDivider;
BitOrder bitOrder;
uint8_t dataMode;
uint8_t _SSPin;
volatile spi_mode_t state;
spi_dev *spi_d;
dma_channel spiRxDmaChannel, spiTxDmaChannel;
dma_dev* spiDmaDev;
void (*receiveCallback)(void) = NULL;
void (*transmitCallback)(void) = NULL;
friend class SPIClass;
};
/*
* Kept for compat.
*/
static const uint8_t ff = 0xFF;
/**
* @brief Wirish SPI interface.
*
* This implementation uses software slave management, so the caller
* is responsible for controlling the slave select line.
*/
class SPIClass {
public:
/**
* @param spiPortNumber Number of the SPI port to manage.
*/
SPIClass(uint32_t spiPortNumber);
/**
* @brief Equivalent to begin(SPI_1_125MHZ, MSBFIRST, 0).
*/
void begin();
/**
* @brief Turn on a SPI port and set its GPIO pin modes for use as a slave.
*
* SPI port is enabled in full duplex mode, with software slave management.
*
* @param bitOrder Either LSBFIRST (little-endian) or MSBFIRST(big-endian)
* @param mode SPI mode to use
*/
void beginSlave(uint32_t bitOrder, uint32_t mode);
/**
* @brief Equivalent to beginSlave(MSBFIRST, 0).
*/
void beginSlave();
/**
* @brief Disables the SPI port, but leaves its GPIO pin modes unchanged.
*/
void end();
void beginTransaction(SPISettings settings) { beginTransaction(BOARD_SPI_DEFAULT_SS, settings); }
void beginTransaction(uint8_t pin, SPISettings settings);
void endTransaction();
void beginTransactionSlave(SPISettings settings);
void setClockDivider(uint32_t clockDivider);
void setBitOrder(BitOrder bitOrder);
void setDataMode(uint8_t dataMode);
// SPI Configuration methods
void attachInterrupt();
void detachInterrupt();
/* Victor Perez. Added to change datasize from 8 to 16 bit modes on the fly.
* Input parameter should be SPI_CR1_DFF set to 0 or 1 on a 32bit word.
* Requires an added function spi_data_size on STM32F1 / cores / maple / libmaple / spi.c
*/
void setDataSize(uint32_t ds);
/* Victor Perez 2017. Added to set and clear callback functions for callback
* on DMA transfer completion.
* onReceive used to set the callback in case of dmaTransfer (tx/rx), once rx is completed
* onTransmit used to set the callback in case of dmaSend (tx only). That function
* will NOT be called in case of TX/RX
*/
void onReceive(void(*)(void));
void onTransmit(void(*)(void));
/*
* I/O
*/
/**
* @brief Return the next unread byte/word.
*
* If there is no unread byte/word waiting, this function will block
* until one is received.
*/
uint16_t read();
/**
* @brief Read length bytes, storing them into buffer.
* @param buffer Buffer to store received bytes into.
* @param length Number of bytes to store in buffer. This
* function will block until the desired number of
* bytes have been read.
*/
void read(uint8_t *buffer, uint32_t length);
/**
* @brief Transmit one byte/word.
* @param data to transmit.
*/
void write(uint16_t data);
void write16(uint16_t data); // write 2 bytes in 8 bit mode (DFF=0)
/**
* @brief Transmit one byte/word a specified number of times.
* @param data to transmit.
*/
void write(uint16_t data, uint32_t n);
/**
* @brief Transmit multiple bytes/words.
* @param buffer Bytes/words to transmit.
* @param length Number of bytes/words in buffer to transmit.
*/
void write(const void * buffer, uint32_t length);
/**
* @brief Transmit a byte, then return the next unread byte.
*
* This function transmits before receiving.
*
* @param data Byte to transmit.
* @return Next unread byte.
*/
uint8_t transfer(uint8_t data) const;
uint16_t transfer16(uint16_t data) const;
/**
* @brief Sets up a DMA Transfer for "length" bytes.
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
*
* This function transmits and receives to buffers.
*
* @param transmitBuf buffer Bytes to transmit. If passed as 0, it sends FF repeatedly for "length" bytes
* @param receiveBuf buffer Bytes to save received data.
* @param length Number of bytes in buffer to transmit.
*/
uint8_t dmaTransfer(const void * transmitBuf, void * receiveBuf, uint16_t length);
void dmaTransferSet(const void *transmitBuf, void *receiveBuf);
uint8_t dmaTransferRepeat(uint16_t length);
/**
* @brief Sets up a DMA Transmit for SPI 8 or 16 bit transfer mode.
* The transfer mode (8 or 16 bit mode) is evaluated from the SPI peripheral setting.
*
* This function only transmits and does not care about the RX fifo.
*
* @param data buffer half words to transmit,
* @param length Number of bytes in buffer to transmit.
* @param minc Set to use Memory Increment mode, clear to use Circular mode.
*/
uint8_t dmaSend(const void * transmitBuf, uint16_t length, bool minc = 1);
void dmaSendSet(const void * transmitBuf, bool minc);
uint8_t dmaSendRepeat(uint16_t length);
uint8_t dmaSendAsync(const void * transmitBuf, uint16_t length, bool minc = 1);
/*
* Pin accessors
*/
/**
* @brief Return the number of the MISO (master in, slave out) pin
*/
uint8_t misoPin();
/**
* @brief Return the number of the MOSI (master out, slave in) pin
*/
uint8_t mosiPin();
/**
* @brief Return the number of the SCK (serial clock) pin
*/
uint8_t sckPin();
/**
* @brief Return the number of the NSS (slave select) pin
*/
uint8_t nssPin();
/* Escape hatch */
/**
* @brief Get a pointer to the underlying libmaple spi_dev for
* this HardwareSPI instance.
*/
spi_dev* c_dev(void) { return _currentSetting->spi_d; }
spi_dev* dev() { return _currentSetting->spi_d; }
/**
* @brief Sets the number of the SPI peripheral to be used by
* this HardwareSPI instance.
*
* @param spi_num Number of the SPI port. 1-2 in low density devices
* or 1-3 in high density devices.
*/
void setModule(int spi_num) {
_currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed
}
/* -- The following methods are deprecated --------------------------- */
/**
* @brief Deprecated.
*
* Use HardwareSPI::transfer() instead.
*
* @see HardwareSPI::transfer()
*/
uint8_t send(uint8_t data);
/**
* @brief Deprecated.
*
* Use HardwareSPI::write() in combination with
* HardwareSPI::read() (or HardwareSPI::transfer()) instead.
*
* @see HardwareSPI::write()
* @see HardwareSPI::read()
* @see HardwareSPI::transfer()
*/
uint8_t send(uint8_t *data, uint32_t length);
/**
* @brief Deprecated.
*
* Use HardwareSPI::read() instead.
*
* @see HardwareSPI::read()
*/
uint8_t recv();
private:
SPISettings _settings[BOARD_NR_SPI];
SPISettings *_currentSetting;
void updateSettings();
/*
* Functions added for DMA transfers with Callback.
* Experimental.
*/
void EventCallback();
#if BOARD_NR_SPI >= 1
static void _spi1EventCallback();
#endif
#if BOARD_NR_SPI >= 2
static void _spi2EventCallback();
#endif
#if BOARD_NR_SPI >= 3
static void _spi3EventCallback();
#endif
/*
spi_dev *spi_d;
uint8_t _SSPin;
uint32_t clockDivider;
uint8_t dataMode;
BitOrder bitOrder;
*/
};
extern SPIClass SPI;

@ -38,8 +38,8 @@
#define _SET_OUTPUT(IO) _SET_MODE(IO, GPIO_OUTPUT_PP)
#define _SET_OUTPUT_OD(IO) _SET_MODE(IO, GPIO_OUTPUT_OD)
#define OUT_WRITE(IO,V) do{ _SET_OUTPUT(IO); WRITE(IO,V); } while(0)
#define OUT_WRITE_OD(IO,V) do{ _SET_OUTPUT_OD(IO); WRITE(IO,V); } while(0)
#define OUT_WRITE(IO,V) do{ _SET_OUTPUT(IO); WRITE(IO,V); }while(0)
#define OUT_WRITE_OD(IO,V) do{ _SET_OUTPUT_OD(IO); WRITE(IO,V); }while(0)
#define SET_INPUT(IO) _SET_MODE(IO, GPIO_INPUT_FLOATING)
#define SET_INPUT_PULLUP(IO) _SET_MODE(IO, GPIO_INPUT_PU)

@ -42,7 +42,6 @@
// Store settings in the last two pages
// Flash pages must be erased before writing, so keep track.
bool firstWrite = false;
uint32_t pageBase = EEPROM_START_ADDRESS;
bool PersistentStore::access_start() {
firstWrite = true;
@ -67,42 +66,27 @@ bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, ui
firstWrite = false;
}
// First write full words
int i = 0;
int wordsToWrite = size / sizeof(uint16_t);
uint16_t* wordBuffer = (uint16_t *)value;
while (wordsToWrite) {
status = FLASH_ProgramHalfWord(pageBase + pos + (i * 2), wordBuffer[i]);
if (status != FLASH_COMPLETE) return true;
wordsToWrite--;
i++;
}
// Now, write any remaining single byte
const uint16_t odd = size & 1;
if (odd) {
uint16_t temp = value[size - 1];
status = FLASH_ProgramHalfWord(pageBase + pos + i, temp);
if (status != FLASH_COMPLETE) return true;
for (size_t i = 0; i < size; i++) {
if (FLASH_ProgramHalfWord(EEPROM_PAGE0_BASE + (pos + i) * 2, value[i]) != FLASH_COMPLETE)
return true;
}
crc16(crc, value, size);
pos += size + odd;
pos += size;
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uint16_t *crc, const bool writing/*=true*/) {
for (uint16_t i = 0; i < size; i++) {
byte* accessPoint = (byte*)(pageBase + pos + i);
uint8_t c = *accessPoint;
if (writing) value[i] = c;
crc16(crc, &c, 1);
for (size_t i = 0; i < size; i++) {
uint8_t v = *(uint16_t *)(EEPROM_PAGE0_BASE + (pos + i) * 2);
if (writing) value[i] = v;
crc16(crc, &v, 1);
}
pos += ((size + 1) & ~1); // i.e., size+(size&1), round up odd values
pos += size;
return false;
}
size_t PersistentStore::capacity() { return E2END + 1; }
size_t PersistentStore::capacity() { return size_t(E2END + 1); }
#endif // EEPROM_SETTINGS && EEPROM FLASH
#endif // __STM32F1__

@ -53,56 +53,40 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
switch (timer_num) {
case STEP_TIMER_NUM:
// STEPPER TIMER TIM5 - use a 32bit timer
#ifdef STM32GENERIC
__HAL_RCC_TIM5_CLK_ENABLE();
TimerHandle[timer_num].handle.Instance = TIM5;
TimerHandle[timer_num].handle.Init.Prescaler = step_prescaler;
TimerHandle[timer_num].handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimerHandle[timer_num].handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimerHandle[timer_num].callback = (uint32_t)TC5_Handler;
#else
TimerHandle[timer_num].timer = TIM5;
TimerHandle[timer_num].irqHandle = TC5_Handler;
TimerHandleInit(&TimerHandle[timer_num], (((HAL_TIMER_RATE) / step_prescaler) / frequency) - 1, step_prescaler);
#endif
__HAL_RCC_TIM5_CLK_ENABLE();
TimerHandle[timer_num].handle.Instance = TIM5;
TimerHandle[timer_num].handle.Init.Prescaler = step_prescaler;
TimerHandle[timer_num].handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimerHandle[timer_num].handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimerHandle[timer_num].callback = (uint32_t)TC5_Handler;
HAL_NVIC_SetPriority(STEP_TIMER_IRQ_ID, 1, 0);
break;
case TEMP_TIMER_NUM:
// TEMP TIMER TIM7 - any available 16bit Timer (1 already used for PWM)
#ifdef STM32GENERIC
__HAL_RCC_TIM7_CLK_ENABLE();
TimerHandle[timer_num].handle.Instance = TIM7;
TimerHandle[timer_num].handle.Init.Prescaler = temp_prescaler;
TimerHandle[timer_num].handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimerHandle[timer_num].handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimerHandle[timer_num].callback = (uint32_t)TC7_Handler;
#else
TimerHandle[timer_num].timer = TIM7;
TimerHandle[timer_num].irqHandle = TC7_Handler;
TimerHandleInit(&TimerHandle[timer_num], (((HAL_TIMER_RATE) / temp_prescaler) / frequency) - 1, temp_prescaler);
#endif
__HAL_RCC_TIM7_CLK_ENABLE();
TimerHandle[timer_num].handle.Instance = TIM7;
TimerHandle[timer_num].handle.Init.Prescaler = temp_prescaler;
TimerHandle[timer_num].handle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimerHandle[timer_num].handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TimerHandle[timer_num].callback = (uint32_t)TC7_Handler;
HAL_NVIC_SetPriority(TEMP_TIMER_IRQ_ID, 2, 0);
break;
}
timers_initialized[timer_num] = true;
}
#ifdef STM32GENERIC
TimerHandle[timer_num].handle.Init.Period = (((HAL_TIMER_RATE) / TimerHandle[timer_num].handle.Init.Prescaler) / frequency) - 1;
if (HAL_TIM_Base_Init(&TimerHandle[timer_num].handle) == HAL_OK)
HAL_TIM_Base_Start_IT(&TimerHandle[timer_num].handle);
#endif
TimerHandle[timer_num].handle.Init.Period = (((HAL_TIMER_RATE) / TimerHandle[timer_num].handle.Init.Prescaler) / frequency) - 1;
if (HAL_TIM_Base_Init(&TimerHandle[timer_num].handle) == HAL_OK)
HAL_TIM_Base_Start_IT(&TimerHandle[timer_num].handle);
}
#ifdef STM32GENERIC
extern "C" void TIM5_IRQHandler() {
((void(*)(void))TimerHandle[0].callback)();
}
extern "C" void TIM7_IRQHandler() {
((void(*)(void))TimerHandle[1].callback)();
}
#endif
extern "C" void TIM5_IRQHandler() {
((void(*)(void))TimerHandle[0].callback)();
}
extern "C" void TIM7_IRQHandler() {
((void(*)(void))TimerHandle[1].callback)();
}
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
switch (timer_num) {

@ -59,8 +59,9 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
timerConfig[0].IRQ_Id = TIM5_IRQn;
timerConfig[0].callback = (uint32_t)TC5_Handler;
HAL_NVIC_SetPriority(timerConfig[0].IRQ_Id, 1, 0);
SET_OUTPUT(STEPPER_ENABLE_PIN);
WRITE(STEPPER_ENABLE_PIN);
#if PIN_EXISTS(STEPPER_ENABLE)
OUT_WRITE(STEPPER_ENABLE_PIN, HIGH);
#endif
break;
case TEMP_TIMER_NUM:
//TEMP TIMER TIM7 // any available 16bit Timer (1 already used for PWM)

@ -189,7 +189,6 @@ void TMC26XStepper::start() {
pinMode(step_pin, OUTPUT);
pinMode(dir_pin, OUTPUT);
pinMode(cs_pin, OUTPUT);
//SET_OUTPUT(STEPPER_ENABLE_PIN);
extDigitalWrite(step_pin, LOW);
extDigitalWrite(dir_pin, LOW);
extDigitalWrite(cs_pin, HIGH);

@ -86,6 +86,8 @@ uint16_t EE_Initialize(void) {
pEraseInit.NbSectors = 1;
pEraseInit.VoltageRange = VOLTAGE_RANGE;
HAL_StatusTypeDef FlashStatus; // = HAL_OK
/* Check for invalid header states and repair if necessary */
uint32_t SectorError;
switch (PageStatus0) {
@ -135,7 +137,7 @@ uint16_t EE_Initialize(void) {
}
}
/* Mark Page0 as valid */
HAL_StatusTypeDef FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
FlashStatus = HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, PAGE0_BASE_ADDRESS, VALID_PAGE);
/* If program operation was failed, a Flash error code is returned */
if (FlashStatus != HAL_OK) return FlashStatus;
pEraseInit.Sector = PAGE1_ID;

@ -65,7 +65,7 @@
#include "feature/host_actions.h"
#endif
#if HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER)
#if USE_BEEPER
#include "libs/buzzer.h"
#endif
@ -290,6 +290,15 @@ void enable_all_steppers() {
enable_E5();
}
void enable_e_steppers() {
enable_E0();
enable_E1();
enable_E2();
enable_E3();
enable_E4();
enable_E5();
}
void disable_e_steppers() {
disable_E0();
disable_E1();
@ -539,28 +548,28 @@ void manage_inactivity(const bool ignore_stepper_queue/*=false*/) {
#if ENABLED(SWITCHING_EXTRUDER)
bool oldstatus;
switch (active_extruder) {
default: oldstatus = E0_ENABLE_READ; enable_E0(); break;
default: oldstatus = E0_ENABLE_READ(); enable_E0(); break;
#if E_STEPPERS > 1
case 2: case 3: oldstatus = E1_ENABLE_READ; enable_E1(); break;
case 2: case 3: oldstatus = E1_ENABLE_READ(); enable_E1(); break;
#if E_STEPPERS > 2
case 4: case 5: oldstatus = E2_ENABLE_READ; enable_E2(); break;
case 4: case 5: oldstatus = E2_ENABLE_READ(); enable_E2(); break;
#endif // E_STEPPERS > 2
#endif // E_STEPPERS > 1
}
#else // !SWITCHING_EXTRUDER
bool oldstatus;
switch (active_extruder) {
default: oldstatus = E0_ENABLE_READ; enable_E0(); break;
default: oldstatus = E0_ENABLE_READ(); enable_E0(); break;
#if E_STEPPERS > 1
case 1: oldstatus = E1_ENABLE_READ; enable_E1(); break;
case 1: oldstatus = E1_ENABLE_READ(); enable_E1(); break;
#if E_STEPPERS > 2
case 2: oldstatus = E2_ENABLE_READ; enable_E2(); break;
case 2: oldstatus = E2_ENABLE_READ(); enable_E2(); break;
#if E_STEPPERS > 3
case 3: oldstatus = E3_ENABLE_READ; enable_E3(); break;
case 3: oldstatus = E3_ENABLE_READ(); enable_E3(); break;
#if E_STEPPERS > 4
case 4: oldstatus = E4_ENABLE_READ; enable_E4(); break;
case 4: oldstatus = E4_ENABLE_READ(); enable_E4(); break;
#if E_STEPPERS > 5
case 5: oldstatus = E5_ENABLE_READ; enable_E5(); break;
case 5: oldstatus = E5_ENABLE_READ(); enable_E5(); break;
#endif // E_STEPPERS > 5
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3
@ -693,7 +702,7 @@ void idle(
print_job_timer.tick();
#endif
#if HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER) && DISABLED(PCA9632_BUZZER)
#if USE_BEEPER
buzzer.tick();
#endif
@ -877,6 +886,10 @@ void setup() {
runout.setup();
#endif
#if ENABLED(POWER_LOSS_RECOVERY)
recovery.setup();
#endif
setup_killpin();
#if HAS_TMC220x
@ -1117,6 +1130,10 @@ void setup() {
init_closedloop();
#endif
#ifdef STARTUP_COMMANDS
queue.inject_P(PSTR(STARTUP_COMMANDS));
#endif
#if ENABLED(INIT_SDCARD_ON_BOOT) && !HAS_SPI_LCD
card.beginautostart();
#endif

@ -316,6 +316,7 @@ void manage_inactivity(const bool ignore_stepper_queue=false);
/**
* The axis order in all axis related arrays is X, Y, Z, E
*/
void enable_e_steppers();
void enable_all_steppers();
void disable_e_stepper(const uint8_t e);
void disable_e_steppers();

@ -95,7 +95,7 @@
#define BOARD_Z_BOLT_X_SERIES 1141 // Z-Bolt X Series
#define BOARD_TT_OSCAR 1142 // TT OSCAR
#define BOARD_OVERLORD 1143 // Overlord/Overlord Pro
#define BOARD_ULTIMAKER 1144 // ADIMLab Granty v1
#define BOARD_HJC2560C_REV1 1144 // ADIMLab Granty v1
#define BOARD_HJC2560C_REV2 1145 // ADIMLab Granty v2
//
@ -115,24 +115,25 @@
#define BOARD_CNCONTROLS_11 1300 // Cartesio CN Controls V11
#define BOARD_CNCONTROLS_12 1301 // Cartesio CN Controls V12
#define BOARD_CHEAPTRONIC 1302 // Cheaptronic v1.0
#define BOARD_CHEAPTRONIC_V2 1303 // Cheaptronic v2.0
#define BOARD_MIGHTYBOARD_REVE 1304 // Makerbot Mightyboard Revision E
#define BOARD_MEGATRONICS 1305 // Megatronics
#define BOARD_MEGATRONICS_2 1306 // Megatronics v2.0
#define BOARD_MEGATRONICS_3 1307 // Megatronics v3.0
#define BOARD_MEGATRONICS_31 1308 // Megatronics v3.1
#define BOARD_MEGATRONICS_32 1309 // Megatronics v3.2
#define BOARD_ELEFU_3 1310 // Elefu Ra Board (v3)
#define BOARD_LEAPFROG 1311 // Leapfrog
#define BOARD_MEGACONTROLLER 1312 // Mega controller
#define BOARD_GT2560_REV_A 1313 // Geeetech GT2560 Rev. A
#define BOARD_GT2560_REV_A_PLUS 1314 // Geeetech GT2560 Rev. A+ (with auto level probe)
#define BOARD_GT2560_V3 1315 // Geeetech GT2560 Rev B for A10(M/D)
#define BOARD_GT2560_V3_MC2 1316 // Geeetech GT2560 Rev B for Mecreator2
#define BOARD_GT2560_V3_A20 1317 // Geeetech GT2560 Rev B for A20(M/D)
#define BOARD_EINSTART_S 1318 // Einstart retrofit
#define BOARD_WANHAO_ONEPLUS 1319 // Wanhao 0ne+ i3 Mini
#define BOARD_CNCONTROLS_15 1302 // Cartesio CN Controls V15
#define BOARD_CHEAPTRONIC 1303 // Cheaptronic v1.0
#define BOARD_CHEAPTRONIC_V2 1304 // Cheaptronic v2.0
#define BOARD_MIGHTYBOARD_REVE 1305 // Makerbot Mightyboard Revision E
#define BOARD_MEGATRONICS 1306 // Megatronics
#define BOARD_MEGATRONICS_2 1307 // Megatronics v2.0
#define BOARD_MEGATRONICS_3 1308 // Megatronics v3.0
#define BOARD_MEGATRONICS_31 1309 // Megatronics v3.1
#define BOARD_MEGATRONICS_32 1310 // Megatronics v3.2
#define BOARD_ELEFU_3 1311 // Elefu Ra Board (v3)
#define BOARD_LEAPFROG 1312 // Leapfrog
#define BOARD_MEGACONTROLLER 1313 // Mega controller
#define BOARD_GT2560_REV_A 1314 // Geeetech GT2560 Rev. A
#define BOARD_GT2560_REV_A_PLUS 1315 // Geeetech GT2560 Rev. A+ (with auto level probe)
#define BOARD_GT2560_V3 1316 // Geeetech GT2560 Rev B for A10(M/D)
#define BOARD_GT2560_V3_MC2 1317 // Geeetech GT2560 Rev B for Mecreator2
#define BOARD_GT2560_V3_A20 1318 // Geeetech GT2560 Rev B for A20(M/D)
#define BOARD_EINSTART_S 1319 // Einstart retrofit
#define BOARD_WANHAO_ONEPLUS 1320 // Wanhao 0ne+ i3 Mini
//
// ATmega1281, ATmega2561
@ -292,6 +293,7 @@
#define BOARD_BLACK_STM32F407ZE 4205 // BLACK_STM32F407ZE
#define BOARD_STEVAL 4206 // STEVAL-3DP001V1 3D PRINTER BOARD
#define BOARD_BIGTREE_SKR_PRO_V1_1 4207 // BigTreeTech SKR Pro v1.1 (STM32F407ZG)
#define BOARD_BIGTREE_BTT002_V1_0 4208 // BigTreeTech BTT002 v1.0 (STM32F407VE)
//
// ARM Cortex M7

@ -67,12 +67,14 @@
#define AXIS_DRIVER_TYPE(A,T) AXIS_DRIVER_TYPE_##A(T)
#define HAS_E_DRIVER(T) ( AXIS_DRIVER_TYPE_E0(T) || AXIS_DRIVER_TYPE_E1(T) \
|| AXIS_DRIVER_TYPE_E2(T) || AXIS_DRIVER_TYPE_E3(T) \
|| AXIS_DRIVER_TYPE_E4(T) || AXIS_DRIVER_TYPE_E5(T) )
#define HAS_DRIVER(T) ( AXIS_DRIVER_TYPE_X(T) || AXIS_DRIVER_TYPE_X2(T) \
|| AXIS_DRIVER_TYPE_Y(T) || AXIS_DRIVER_TYPE_Y2(T) \
|| AXIS_DRIVER_TYPE_Z(T) || AXIS_DRIVER_TYPE_Z2(T) || AXIS_DRIVER_TYPE_Z3(T) \
|| AXIS_DRIVER_TYPE_E0(T) || AXIS_DRIVER_TYPE_E1(T) \
|| AXIS_DRIVER_TYPE_E2(T) || AXIS_DRIVER_TYPE_E3(T) \
|| AXIS_DRIVER_TYPE_E4(T) || AXIS_DRIVER_TYPE_E5(T) )
|| HAS_E_DRIVER(T) )
// Test for supported TMC drivers that require advanced configuration
// Does not match standalone configurations

@ -118,24 +118,24 @@
// Using GCC extensions, but Travis GCC version does not like it and gives
// "error: statement-expressions are not allowed outside functions nor in template-argument lists"
#define NOLESS(v, n) \
do { \
do{ \
__typeof__(n) _n = (n); \
if (v < _n) v = _n; \
} while(0)
}while(0)
#define NOMORE(v, n) \
do { \
do{ \
__typeof__(n) _n = (n); \
if (v > _n) v = _n; \
} while(0)
}while(0)
#define LIMIT(v, n1, n2) \
do { \
do{ \
__typeof__(n1) _n1 = (n1); \
__typeof__(n2) _n2 = (n2); \
if (v < _n1) v = _n1; \
else if (v > _n2) v = _n2; \
} while(0)
}while(0)
#endif

@ -184,5 +184,5 @@ void print_bin(const uint16_t val);
void print_xyz(PGM_P const prefix, PGM_P const suffix, const float x, const float y, const float z);
void print_xyz(PGM_P const prefix, PGM_P const suffix, const float xyz[]);
#define SERIAL_POS(SUFFIX,VAR) do { print_xyz(PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n"), VAR); } while(0)
#define SERIAL_XYZ(PREFIX,V...) do { print_xyz(PSTR(PREFIX), nullptr, V); } while(0)
#define SERIAL_POS(SUFFIX,VAR) do { print_xyz(PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n"), VAR); }while(0)
#define SERIAL_XYZ(PREFIX,V...) do { print_xyz(PSTR(PREFIX), nullptr, V); }while(0)

@ -752,16 +752,15 @@
save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained
DEPLOY_PROBE();
uint8_t count = GRID_MAX_POINTS, current = 1;
uint8_t count = GRID_MAX_POINTS;
do {
current = (GRID_MAX_POINTS) - count + 1;
if (do_ubl_mesh_map) display_map(g29_map_type);
SERIAL_ECHOLNPAIR("\nProbing mesh point ", int(current), "/", int(GRID_MAX_POINTS), ".\n");
const int current = (GRID_MAX_POINTS) - count + 1;
SERIAL_ECHOLNPAIR("\nProbing mesh point ", current, "/", int(GRID_MAX_POINTS), ".\n");
#if HAS_DISPLAY
ui.status_printf_P(0, PSTR(MSG_PROBING_MESH " %i/%i"), int(current), int(GRID_MAX_POINTS));
ui.status_printf_P(0, PSTR(MSG_PROBING_MESH " %i/%i"), current, int(GRID_MAX_POINTS));
#endif
#if HAS_LCD_MENU
@ -1500,8 +1499,7 @@
DEBUG_ECHO_F(rx, 7);
DEBUG_CHAR(',');
DEBUG_ECHO_F(ry, 7);
DEBUG_ECHOPGM(") logical: ");
DEBUG_CHAR('(');
DEBUG_ECHOPGM(") logical: (");
DEBUG_ECHO_F(LOGICAL_X_POSITION(rx), 7);
DEBUG_CHAR(',');
DEBUG_ECHO_F(LOGICAL_Y_POSITION(ry), 7);

@ -36,35 +36,37 @@ void controllerfan_update() {
if (ELAPSED(ms, nextMotorCheck)) {
nextMotorCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s
const bool xory = X_ENABLE_READ() == X_ENABLE_ON || Y_ENABLE_READ() == Y_ENABLE_ON;
// If any of the drivers or the bed are enabled...
if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON
if (xory || Z_ENABLE_READ() == Z_ENABLE_ON
#if HAS_HEATED_BED
|| thermalManager.temp_bed.soft_pwm_amount > 0
#endif
#if HAS_X2_ENABLE
|| X2_ENABLE_READ == X_ENABLE_ON
|| X2_ENABLE_READ() == X_ENABLE_ON
#endif
#if HAS_Y2_ENABLE
|| Y2_ENABLE_READ == Y_ENABLE_ON
|| Y2_ENABLE_READ() == Y_ENABLE_ON
#endif
#if HAS_Z2_ENABLE
|| Z2_ENABLE_READ == Z_ENABLE_ON
|| Z2_ENABLE_READ() == Z_ENABLE_ON
#endif
#if HAS_Z3_ENABLE
|| Z3_ENABLE_READ == Z_ENABLE_ON
|| Z3_ENABLE_READ() == Z_ENABLE_ON
#endif
#if E_STEPPERS
|| E0_ENABLE_READ == E_ENABLE_ON
|| E0_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 1
|| E1_ENABLE_READ == E_ENABLE_ON
|| E1_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 2
|| E2_ENABLE_READ == E_ENABLE_ON
|| E2_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 3
|| E3_ENABLE_READ == E_ENABLE_ON
|| E3_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 4
|| E4_ENABLE_READ == E_ENABLE_ON
|| E4_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 5
|| E5_ENABLE_READ == E_ENABLE_ON
|| E5_ENABLE_READ() == E_ENABLE_ON
#endif // E_STEPPERS > 5
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3
@ -76,12 +78,17 @@ void controllerfan_update() {
}
// Fan off if no steppers have been enabled for CONTROLLERFAN_SECS seconds
uint8_t speed = (!lastMotorOn || ELAPSED(ms, lastMotorOn + (CONTROLLERFAN_SECS) * 1000UL)) ? 0 : CONTROLLERFAN_SPEED;
controllerfan_speed = speed;
controllerfan_speed = (!lastMotorOn || ELAPSED(ms, lastMotorOn + (CONTROLLERFAN_SECS) * 1000UL)) ? 0 : (
#ifdef CONTROLLERFAN_SPEED_Z_ONLY
xory ? CONTROLLERFAN_SPEED : CONTROLLERFAN_SPEED_Z_ONLY
#else
CONTROLLERFAN_SPEED
#endif
);
// allows digital or PWM fan output to be used (see M42 handling)
WRITE(CONTROLLER_FAN_PIN, speed);
analogWrite(pin_t(CONTROLLER_FAN_PIN), speed);
// Allow digital or PWM fan output (see M42 handling)
WRITE(CONTROLLER_FAN_PIN, controllerfan_speed);
analogWrite(pin_t(CONTROLLER_FAN_PIN), controllerfan_speed);
}
}

@ -125,7 +125,7 @@ void LEDLights::set_color(const LEDColor &incol
// If the pins can do PWM then their intensity will be set.
#define UPDATE_RGBW(C,c) do { if (PWM_PIN(RGB_LED_##C##_PIN)) \
analogWrite(pin_t(RGB_LED_##C##_PIN), incol.c); \
else WRITE(RGB_LED_##C##_PIN, incol.c ? HIGH : LOW); } while(0)
else WRITE(RGB_LED_##C##_PIN, incol.c ? HIGH : LOW); }while(0)
UPDATE_RGBW(R,r);
UPDATE_RGBW(G,g);
UPDATE_RGBW(B,b);

@ -137,13 +137,15 @@ void pca9632_set_led_color(const LEDColor &color) {
}
#if ENABLED(PCA9632_BUZZER)
void pca9632_buzz(uint16_t const f, uint16_t d) {
UNUSED(f); UNUSED(d);
void pca9632_buzz(const long duration, const uint16_t freq) {
UNUSED(duration); UNUSED(freq);
uint8_t data[] = PCA9632_BUZZER_DATA;
Wire.beginTransmission(I2C_ADDRESS(PCA9632_ADDRESS));
Wire.write(data, sizeof(data));
Wire.endTransmission();
}
#endif
#endif // PCA9632_BUZZER
#endif // PCA9632

@ -32,5 +32,6 @@ typedef LEDColor LEDColor;
void pca9632_set_led_color(const LEDColor &color);
#if ENABLED(PCA9632_BUZZER)
void pca9632_buzz(uint16_t const, uint16_t);
#include <stdint.h>
void pca9632_buzz(const long, const uint16_t);
#endif

@ -187,6 +187,9 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
host_action_prompt_button(PSTR("Continue"));
host_action_prompt_show();
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onStatusChanged(PSTR("Load Filament"));
#endif
while (wait_for_user) {
#if HAS_BUZZER
filament_change_beep(max_beep_count);
@ -239,6 +242,9 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
#if ENABLED(HOST_PROMPT_SUPPORT)
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Continuous Purge Running..."), PSTR("Continue"));
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onStatusChanged(PSTR("Continuous Purge Running..."));
#endif
for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count)
do_pause_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE);
wait_for_user = false;
@ -353,8 +359,8 @@ bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/,
planner.settings.retract_acceleration = saved_acceleration;
#endif
// Disable extruders steppers for manual filament changing (only on boards that have separate ENABLE_PINS)
#if (E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN) || AXIS_DRIVER_TYPE_E0(TMC2660) || AXIS_DRIVER_TYPE_E1(TMC2660) || AXIS_DRIVER_TYPE_E2(TMC2660) || AXIS_DRIVER_TYPE_E3(TMC2660) || AXIS_DRIVER_TYPE_E4(TMC2660) || AXIS_DRIVER_TYPE_E5(TMC2660)
// Disable E steppers for manual change
#if HAS_E_STEPPER_ENABLE
disable_e_stepper(active_extruder);
safe_delay(100);
#endif
@ -517,6 +523,9 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep
#if ENABLED(HOST_PROMPT_SUPPORT)
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Nozzle Parked"), PSTR("Continue"));
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onStatusChanged(PSTR("Nozzle Parked"));
#endif
while (wait_for_user) {
#if HAS_BUZZER
filament_change_beep(max_beep_count);
@ -538,6 +547,10 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("HeaterTimeout"), PSTR("Reheat"));
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onStatusChanged(PSTR("HeaterTimeout"));
#endif
// Wait for LCD click or M108
while (wait_for_user) idle(true);

@ -55,31 +55,31 @@ bool Power::is_power_needed() {
#endif
// If any of the drivers or the bed are enabled...
if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON
if (X_ENABLE_READ() == X_ENABLE_ON || Y_ENABLE_READ() == Y_ENABLE_ON || Z_ENABLE_READ() == Z_ENABLE_ON
#if HAS_HEATED_BED
|| thermalManager.temp_bed.soft_pwm_amount > 0
#endif
#if HAS_X2_ENABLE
|| X2_ENABLE_READ == X_ENABLE_ON
|| X2_ENABLE_READ() == X_ENABLE_ON
#endif
#if HAS_Y2_ENABLE
|| Y2_ENABLE_READ == Y_ENABLE_ON
|| Y2_ENABLE_READ() == Y_ENABLE_ON
#endif
#if HAS_Z2_ENABLE
|| Z2_ENABLE_READ == Z_ENABLE_ON
|| Z2_ENABLE_READ() == Z_ENABLE_ON
#endif
#if E_STEPPERS
|| E0_ENABLE_READ == E_ENABLE_ON
|| E0_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 1
|| E1_ENABLE_READ == E_ENABLE_ON
|| E1_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 2
|| E2_ENABLE_READ == E_ENABLE_ON
|| E2_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 3
|| E3_ENABLE_READ == E_ENABLE_ON
|| E3_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 4
|| E4_ENABLE_READ == E_ENABLE_ON
|| E4_ENABLE_READ() == E_ENABLE_ON
#if E_STEPPERS > 5
|| E5_ENABLE_READ == E_ENABLE_ON
|| E5_ENABLE_READ() == E_ENABLE_ON
#endif // E_STEPPERS > 5
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3

@ -26,12 +26,16 @@
*/
#include "../sd/cardreader.h"
#include "../inc/MarlinConfigPre.h"
#include "../inc/MarlinConfig.h"
#if ENABLED(MIXING_EXTRUDER)
#include "../feature/mixing.h"
#endif
#if !defined(POWER_LOSS_STATE) && PIN_EXISTS(POWER_LOSS)
#define POWER_LOSS_STATE HIGH
#endif
//#define DEBUG_POWER_LOSS_RECOVERY
//#define SAVE_EACH_CMD_MODE
//#define SAVE_INFO_INTERVAL_MS 0
@ -110,6 +114,20 @@ class PrintJobRecovery {
static void init();
static inline void setup() {
#if PIN_EXISTS(POWER_LOSS)
#if ENABLED(POWER_LOSS_PULL)
#if POWER_LOSS_STATE == LOW
SET_INPUT_PULLUP(POWER_LOSS_PIN);
#else
SET_INPUT_PULLDOWN(POWER_LOSS_PIN);
#endif
#else
SET_INPUT(POWER_LOSS_PIN);
#endif
#endif
}
static bool enabled;
static void enable(const bool onoff);
static void changed();

@ -42,6 +42,10 @@ MMU2 mmu2;
#include "../../feature/host_actions.h"
#endif
#if ENABLED(EXTENSIBLE_UI)
#include "../../lcd/extensible_ui/ui_api.h"
#endif
#define DEBUG_OUT ENABLED(MMU2_DEBUG)
#include "../../core/debug_out.h"
@ -711,6 +715,9 @@ void MMU2::filament_runout() {
#if ENABLED(HOST_PROMPT_SUPPORT)
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("MMU2 Eject Recover"), PSTR("Continue"));
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onStatusChanged(PSTR("MMU2 Eject Recover"));
#endif
while (wait_for_user) idle();
BUZZ(200, 404);
BUZZ(200, 404);

@ -249,6 +249,8 @@ class FilamentSensorBase {
&& (dual_x_carriage_mode == DXC_DUPLICATION_MODE || dual_x_carriage_mode == DXC_MIRRORED_MODE)
#elif ENABLED(MULTI_NOZZLE_DUPLICATION)
&& extruder_duplication_enabled
#else
&& false
#endif
#endif
) return runout_states; // Any extruder

@ -445,7 +445,7 @@ void GcodeSuite::G33() {
_tower_results = (_4p_calibration && towers_set) || probe_points >= 3,
_opposite_results = (_4p_calibration && !towers_set) || probe_points >= 3,
_endstop_results = probe_points != 1 && probe_points != -1 && probe_points != 0,
_angle_results = probe_points >= 3 && towers_set;
_angle_results = probe_points >= 3 && towers_set;
static const char save_message[] PROGMEM = "Save with M500 and/or copy to Configuration.h";
int8_t iterations = 0;
float test_precision,

@ -284,7 +284,7 @@ void GcodeSuite::G34() {
// Home Z after the alignment procedure
process_subcommands_now_P(PSTR("G28 Z"));
} while(0);
}while(0);
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("<<< G34");
}

@ -42,6 +42,10 @@
#include "../../feature/host_actions.h"
#endif
#if ENABLED(EXTENSIBLE_UI)
#include "../../lcd/extensible_ui/ui_api.h"
#endif
#ifndef GET_PIN_MAP_PIN_M43
#define GET_PIN_MAP_PIN_M43(Q) GET_PIN_MAP_PIN(Q)
#endif
@ -329,6 +333,9 @@ void GcodeSuite::M43() {
#if ENABLED(HOST_PROMPT_SUPPORT)
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("M43 Wait Called"), PSTR("Continue"));
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onStatusChanged(PSTR("M43 Wait Called"));
#endif
#endif
for (;;) {

@ -30,11 +30,21 @@
#endif
/**
* M17: Enable power on all stepper motors
* M17: Enable stepper motors
*/
void GcodeSuite::M17() {
LCD_MESSAGEPGM(MSG_NO_MOVE);
enable_all_steppers();
if (parser.seen("XYZE")) {
if (parser.seen('X')) enable_X();
if (parser.seen('Y')) enable_Y();
if (parser.seen('Z')) enable_Z();
#if HAS_E_STEPPER_ENABLE
if (parser.seen('E')) enable_e_steppers();
#endif
}
else {
LCD_MESSAGEPGM(MSG_NO_MOVE);
enable_all_steppers();
}
}
/**
@ -45,20 +55,17 @@ void GcodeSuite::M18_M84() {
stepper_inactive_time = parser.value_millis_from_seconds();
}
else {
bool all_axis = !(parser.seen('X') || parser.seen('Y') || parser.seen('Z') || parser.seen('E'));
if (all_axis) {
planner.finish_and_disable();
}
else {
if (parser.seen("XYZE")) {
planner.synchronize();
if (parser.seen('X')) disable_X();
if (parser.seen('Y')) disable_Y();
if (parser.seen('Z')) disable_Z();
// Only disable on boards that have separate ENABLE_PINS or another method for disabling the driver
#if (E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN) || AXIS_DRIVER_TYPE_E0(TMC2660) || AXIS_DRIVER_TYPE_E1(TMC2660) || AXIS_DRIVER_TYPE_E2(TMC2660) || AXIS_DRIVER_TYPE_E3(TMC2660) || AXIS_DRIVER_TYPE_E4(TMC2660) || AXIS_DRIVER_TYPE_E5(TMC2660)
#if HAS_E_STEPPER_ENABLE
if (parser.seen('E')) disable_e_steppers();
#endif
}
else
planner.finish_and_disable();
#if HAS_LCD_MENU && ENABLED(AUTO_BED_LEVELING_UBL)
if (ubl.lcd_map_control) {

@ -52,7 +52,7 @@ void GcodeSuite::M502() {
* M503: print settings currently in memory
*/
void GcodeSuite::M503() {
(void)settings.report(parser.boolval('S', true));
(void)settings.report(!parser.boolval('S', true));
}
#endif // !DISABLE_M503

@ -342,6 +342,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
case 12: M12(); break; // M12: Synchronize and optionally force a CLC set
#endif
#if ENABLED(EXPECTED_PRINTER_CHECK)
case 16: M16(); break; // M16: Expected printer check
#endif
case 17: M17(); break; // M17: Enable all stepper motors
#if ENABLED(SDSUPPORT)

@ -83,6 +83,7 @@
* M8 - Turn flood coolant ON. (Requires COOLANT_CONTROL)
* M9 - Turn coolant OFF. (Requires COOLANT_CONTROL)
* M12 - Set up closed loop control system. (Requires EXTERNAL_CLOSED_LOOP_CONTROLLER)
* M16 - Expected printer check. (Requires EXPECTED_PRINTER_CHECK)
* M17 - Enable/Power all stepper motors
* M18 - Disable all stepper motors; same as M84
* M20 - List SD card. (Requires SDSUPPORT)
@ -472,6 +473,10 @@ private:
static void M12();
#endif
#if ENABLED(EXPECTED_PRINTER_CHECK)
static void M16();
#endif
static void M17();
static void M18_M84();

@ -0,0 +1,40 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(EXPECTED_PRINTER_CHECK)
#include "../gcode.h"
#include "../../Marlin.h"
/**
* M16: Expected Printer Check
*/
void GcodeSuite::M16() {
if (strcmp_P(parser.string_arg, PSTR(MACHINE_NAME)))
kill(PSTR(MSG_EXPECTED_PRINTER));
}
#endif

@ -97,6 +97,9 @@ void GcodeSuite::M0_M1() {
#if ENABLED(HOST_PROMPT_SUPPORT)
host_prompt_do(PROMPT_USER_CONTINUE, PSTR("M0/1 Break Called"), PSTR("Continue"));
#endif
#if ENABLED(EXTENSIBLE_UI)
ExtUI::onStatusChanged(PSTR("M0/1 Break Called"));
#endif
if (ms > 0) {
ms += millis(); // wait until this time for a click

@ -225,6 +225,9 @@ void GCodeParser::parse(char *p) {
case 810: case 811: case 812: case 813: case 814:
case 815: case 816: case 817: case 818: case 819:
#endif
#if ENABLED(EXPECTED_PRINTER_CHECK)
case 16:
#endif
case 23: case 28: case 30: case 117: case 118: case 928: string_arg = p; return;
default: break;
}

@ -30,9 +30,9 @@
#define DOGLCD
#define IS_ULTIPANEL
#define DEFAULT_LCD_CONTRAST 90
#define LCD_CONTRAST_MIN 60
#define LCD_CONTRAST_MIN 60
#define LCD_CONTRAST_MAX 140
#define LCD_CONTRAST_INIT 90
#elif ENABLED(ZONESTAR_LCD)
@ -65,23 +65,23 @@
#if ENABLED(miniVIKI)
#define LCD_CONTRAST_MIN 75
#define LCD_CONTRAST_MAX 115
#define DEFAULT_LCD_CONTRAST 95
#define LCD_CONTRAST_INIT 95
#define U8GLIB_ST7565_64128N
#elif ENABLED(VIKI2)
#define LCD_CONTRAST_MIN 0
#define LCD_CONTRAST_MAX 255
#define DEFAULT_LCD_CONTRAST 140
#define LCD_CONTRAST_INIT 140
#define U8GLIB_ST7565_64128N
#elif ENABLED(ELB_FULL_GRAPHIC_CONTROLLER)
#define LCD_CONTRAST_MIN 90
#define LCD_CONTRAST_MAX 130
#define DEFAULT_LCD_CONTRAST 110
#define LCD_CONTRAST_INIT 110
#define U8GLIB_LM6059_AF
#define SD_DETECT_INVERTED
#elif ENABLED(AZSMZ_12864)
#define LCD_CONTRAST_MIN 120
#define LCD_CONTRAST_MAX 255
#define DEFAULT_LCD_CONTRAST 190
#define LCD_CONTRAST_INIT 190
#define U8GLIB_ST7565_64128N
#endif
@ -128,17 +128,17 @@
#elif ENABLED(MKS_MINI_12864)
#define MINIPANEL
#define DEFAULT_LCD_CONTRAST 150
#define LCD_CONTRAST_MAX 255
#define LCD_CONTRAST_MAX 255
#define LCD_CONTRAST_INIT 150
#elif ANY(FYSETC_MINI_12864_X_X, FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0, FYSETC_MINI_12864_2_1)
#define FYSETC_MINI_12864
#define DOGLCD
#define IS_ULTIPANEL
#define LCD_CONTRAST_MIN 0
#define LCD_CONTRAST_MAX 255
#define DEFAULT_LCD_CONTRAST 220
#define LCD_CONTRAST_MIN 0
#define LCD_CONTRAST_MAX 255
#define LCD_CONTRAST_INIT 220
#define LED_COLORS_REDUCE_GREEN
#if HAS_POWER_SWITCH && EITHER(FYSETC_MINI_12864_2_0, FYSETC_MINI_12864_2_1)
#define LED_BACKLIGHT_TIMEOUT 10000
@ -166,9 +166,9 @@
#define IS_ULTIPANEL
#define U8GLIB_SSD1309
#define LCD_RESET_PIN LCD_PINS_D6 // This controller need a reset pin
#define LCD_CONTRAST_MIN 0
#define LCD_CONTRAST_MAX 254
#define DEFAULT_LCD_CONTRAST 127
#define LCD_CONTRAST_MIN 0
#define LCD_CONTRAST_MAX 254
#define LCD_CONTRAST_INIT 127
#define ENCODER_PULSES_PER_STEP 2
#define ENCODER_STEPS_PER_MENU_ITEM 2
@ -190,8 +190,8 @@
#if ENABLED(MAKRPANEL)
#define U8GLIB_ST7565_64128N
#endif
#ifndef DEFAULT_LCD_CONTRAST
#define DEFAULT_LCD_CONTRAST 17
#ifndef LCD_CONTRAST_INIT
#define LCD_CONTRAST_INIT 17
#endif
#endif
@ -368,7 +368,7 @@
#endif
// Extensible UI serial touch screens. (See src/lcd/extensible_ui)
#if EITHER(MALYAN_LCD, DGUS_LCD)
#if ANY(MALYAN_LCD, DGUS_LCD, LULZBOT_TOUCH_UI)
#define IS_EXTUI
#define EXTENSIBLE_UI
#endif
@ -381,22 +381,6 @@
#define HAS_LCD_MENU (ENABLED(ULTIPANEL) && DISABLED(NO_LCD_MENUS))
#define HAS_ADC_BUTTONS ENABLED(ADC_KEYPAD)
/**
* Default LCD contrast for Graphical LCD displays
*/
#define HAS_LCD_CONTRAST (HAS_GRAPHICAL_LCD && defined(DEFAULT_LCD_CONTRAST))
#if HAS_LCD_CONTRAST
#ifndef LCD_CONTRAST_MIN
#define LCD_CONTRAST_MIN 0
#endif
#ifndef LCD_CONTRAST_MAX
#define LCD_CONTRAST_MAX 63
#endif
#ifndef DEFAULT_LCD_CONTRAST
#define DEFAULT_LCD_CONTRAST 32
#endif
#endif
/**
* Extruders have some combination of stepper motors and hotends
* so we separate these concepts into the defines:
@ -594,32 +578,6 @@
#define INVERT_E_DIR false
#endif
#if ENABLED(HOST_ACTION_COMMANDS)
#ifndef ACTION_ON_PAUSE
#define ACTION_ON_PAUSE "pause"
#endif
#ifndef ACTION_ON_RESUME
#define ACTION_ON_RESUME "resume"
#endif
#ifndef ACTION_ON_PAUSED
#define ACTION_ON_PAUSED "paused"
#endif
#ifndef ACTION_ON_RESUMED
#define ACTION_ON_RESUMED "resumed"
#endif
#ifndef ACTION_ON_CANCEL
#define ACTION_ON_CANCEL "cancel"
#endif
#if ENABLED(G29_RETRY_AND_RECOVER)
#ifndef ACTION_ON_G29_RECOVER
#define ACTION_ON_G29_RECOVER "probe_rewipe"
#endif
#ifndef ACTION_ON_G29_FAILURE
#define ACTION_ON_G29_FAILURE "probe_failed"
#endif
#endif
#endif
#if ENABLED(SLIM_LCD_MENUS)
#define BOOT_MARLIN_LOGO_SMALL
#endif

@ -99,3 +99,6 @@
#define LED_USER_PRESET_BRIGHTNESS 255
#endif
#endif
// Extensible UI pin mapping for RepRapDiscount
#define TOUCH_UI_ULTIPANEL ENABLED(LULZBOT_TOUCH_UI) && ANY(AO_EXP1_PINMAP, AO_EXP2_PINMAP, CR10_TFT_PINMAP)

@ -246,6 +246,22 @@
#define MAX_AUTORETRACT 99
#endif
/**
* Default LCD contrast for Graphical LCD displays
*/
#define HAS_LCD_CONTRAST defined(LCD_CONTRAST_INIT)
#if HAS_LCD_CONTRAST
#ifndef DEFAULT_LCD_CONTRAST
#define DEFAULT_LCD_CONTRAST LCD_CONTRAST_INIT
#endif
#ifndef LCD_CONTRAST_MIN
#define LCD_CONTRAST_MIN 0
#endif
#ifndef LCD_CONTRAST_MAX
#define LCD_CONTRAST_MAX MAX(63, LCD_CONTRAST_INIT)
#endif
#endif
/**
* Override here because this is set in Configuration_adv.h
*/
@ -927,6 +943,11 @@
#endif
#endif
#define HAS_E_STEPPER_ENABLE (HAS_E_DRIVER(TMC2660) \
|| ( E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != X_ENABLE_PIN \
&& E0_ENABLE_PIN != Y_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN ) \
)
// Endstops and bed probe
#define _HAS_STOP(A,M) (PIN_EXISTS(A##_##M) && !IS_X2_ENDSTOP(A,M) && !IS_Y2_ENDSTOP(A,M) && !IS_Z2_OR_PROBE(A,M))
#define HAS_X_MIN _HAS_STOP(X,MIN)
@ -996,7 +1017,21 @@
#define HAS_AUTO_FAN_4 (HOTENDS > 4 && PIN_EXISTS(E4_AUTO_FAN))
#define HAS_AUTO_FAN_5 (HOTENDS > 5 && PIN_EXISTS(E5_AUTO_FAN))
#define HAS_AUTO_CHAMBER_FAN (HAS_TEMP_CHAMBER && PIN_EXISTS(CHAMBER_AUTO_FAN))
#define HAS_AUTO_FAN (HAS_AUTO_FAN_0 || HAS_AUTO_FAN_1 || HAS_AUTO_FAN_2 || HAS_AUTO_FAN_3 || HAS_AUTO_FAN_4 || HAS_AUTO_FAN_5 || HAS_AUTO_CHAMBER_FAN)
#if HAS_AUTO_FAN
#define AUTO_CHAMBER_IS_0 (CHAMBER_AUTO_FAN_PIN == E0_AUTO_FAN_PIN)
#define AUTO_CHAMBER_IS_1 (CHAMBER_AUTO_FAN_PIN == E1_AUTO_FAN_PIN)
#define AUTO_CHAMBER_IS_2 (CHAMBER_AUTO_FAN_PIN == E2_AUTO_FAN_PIN)
#define AUTO_CHAMBER_IS_3 (CHAMBER_AUTO_FAN_PIN == E3_AUTO_FAN_PIN)
#define AUTO_CHAMBER_IS_4 (CHAMBER_AUTO_FAN_PIN == E4_AUTO_FAN_PIN)
#define AUTO_CHAMBER_IS_5 (CHAMBER_AUTO_FAN_PIN == E5_AUTO_FAN_PIN)
#define AUTO_CHAMBER_IS_E (AUTO_CHAMBER_IS_0 || AUTO_CHAMBER_IS_1 || AUTO_CHAMBER_IS_2 || AUTO_CHAMBER_IS_3 || AUTO_CHAMBER_IS_4 || AUTO_CHAMBER_IS_5)
#endif
#if !HAS_AUTO_CHAMBER_FAN || AUTO_CHAMBER_IS_E
#undef AUTO_POWER_CHAMBER_FAN
#endif
// Other fans
#define HAS_FAN0 (PIN_EXISTS(FAN))
@ -1029,7 +1064,8 @@
#define HAS_KILL (PIN_EXISTS(KILL))
#define HAS_SUICIDE (PIN_EXISTS(SUICIDE))
#define HAS_PHOTOGRAPH (PIN_EXISTS(PHOTOGRAPH))
#define HAS_BUZZER (PIN_EXISTS(BEEPER) || ENABLED(LCD_USE_I2C_BUZZER) || ENABLED(PCA9632_BUZZER))
#define HAS_BUZZER (PIN_EXISTS(BEEPER) || EITHER(LCD_USE_I2C_BUZZER, PCA9632_BUZZER))
#define USE_BEEPER (HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER, PCA9632_BUZZER))
#define HAS_CASE_LIGHT (PIN_EXISTS(CASE_LIGHT) && ENABLED(CASE_LIGHT_ENABLE))
// Digital control
@ -1551,7 +1587,7 @@
#ifndef LCD_FEEDBACK_FREQUENCY_DURATION_MS
#define LCD_FEEDBACK_FREQUENCY_DURATION_MS 100
#endif
#else
#elif HAS_BUZZER
#ifndef LCD_FEEDBACK_FREQUENCY_HZ
#define LCD_FEEDBACK_FREQUENCY_HZ 5000
#endif

@ -1892,6 +1892,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
+ ENABLED(OVERLORD_OLED) \
+ ENABLED(DGUS_LCD) \
+ ENABLED(MALYAN_LCD) \
+ ENABLED(LULZBOT_TOUCH_UI) \
+ ENABLED(FSMC_GRAPHICAL_TFT)
#error "Please select no more than one LCD controller option."
#endif

@ -51,7 +51,7 @@
* here we define this default string as the date where the latest release
* version was tagged.
*/
#define STRING_DISTRIBUTION_DATE "2019-08-08"
#define STRING_DISTRIBUTION_DATE "2019-08-21"
/**
* Required minimum Configuration.h and Configuration_adv.h file versions.

@ -877,7 +877,7 @@ static int pf_bsearch_cb_comp_hd4map_pgm(void *userdata, size_t idx, void * data
return hd44780_charmap_compare(&localval, (hd44780_charmap_t *)data_pin);
}
void lcd_moveto(const uint8_t col, const uint8_t row) { lcd.setCursor(col, row); }
void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) { lcd.setCursor(col, row); }
void lcd_put_int(const int i) { lcd.print(i); }

@ -269,7 +269,7 @@ void MarlinUI::set_custom_characters(const HD44780CharSet screen_charset/*=CHARS
#endif // LCD_PROGRESS_BAR
#if ENABLED(SDSUPPORT)
#if ENABLED(SDSUPPORT) && HAS_LCD_MENU
// CHARSET_MENU
const static PROGMEM byte refresh[8] = {
@ -319,7 +319,7 @@ void MarlinUI::set_custom_characters(const HD44780CharSet screen_charset/*=CHARS
#endif
{
createChar_P(LCD_STR_UPLEVEL[0], uplevel);
#if ENABLED(SDSUPPORT)
#if ENABLED(SDSUPPORT) && HAS_LCD_MENU
// SD Card sub-menu special characters
createChar_P(LCD_STR_REFRESH[0], refresh);
createChar_P(LCD_STR_FOLDER[0], folder);
@ -360,23 +360,48 @@ void MarlinUI::init_lcd() {
lcd.clear();
}
bool MarlinUI::detected() {
return true
#if EITHER(LCD_I2C_TYPE_MCP23017, LCD_I2C_TYPE_MCP23008) && defined(DETECT_DEVICE)
&& lcd.LcdDetected() == 1
#endif
;
}
#if HAS_SLOW_BUTTONS
uint8_t MarlinUI::read_slow_buttons() {
#if ENABLED(LCD_I2C_TYPE_MCP23017)
// Reading these buttons this is likely to be too slow to call inside interrupt context
// so they are called during normal lcd_update
uint8_t slow_bits = lcd.readButtons()
#if !BUTTON_EXISTS(ENC)
<< B_I2C_BTN_OFFSET
#endif
;
#if ENABLED(LCD_I2C_VIKI)
if ((slow_bits & (B_MI | B_RI)) && PENDING(millis(), next_button_update_ms)) // LCD clicked
slow_bits &= ~(B_MI | B_RI); // Disable LCD clicked buttons if screen is updated
#endif // LCD_I2C_VIKI
return slow_bits;
#endif // LCD_I2C_TYPE_MCP23017
}
#endif
void MarlinUI::clear_lcd() { lcd.clear(); }
#if ENABLED(SHOW_BOOTSCREEN)
void lcd_erase_line(const int16_t line) {
void lcd_erase_line(const lcd_uint_t line) {
lcd_moveto(0, line);
for (uint8_t i = LCD_WIDTH + 1; --i;)
lcd_put_wchar(' ');
}
// Scroll the PSTR 'text' in a 'len' wide field for 'time' milliseconds at position col,line
void lcd_scroll(const uint8_t col, const uint8_t line, PGM_P const text, const uint8_t len, const int16_t time) {
void lcd_scroll(const lcd_uint_t col, const lcd_uint_t line, PGM_P const text, const uint8_t len, const int16_t time) {
uint8_t slen = utf8_strlen_P(text);
if (slen < len) {
// Fits into,
lcd_moveto(col, line);
lcd_put_u8str_max_P(text, len);
lcd_put_u8str_max_P(col, line, text, len);
for (; slen < len; ++slen) lcd_put_wchar(' ');
safe_delay(time);
}
@ -385,11 +410,8 @@ void MarlinUI::clear_lcd() { lcd.clear(); }
int dly = time / _MAX(slen, 1);
for (uint8_t i = 0; i <= slen; i++) {
// Go to the correct place
lcd_moveto(col, line);
// Print the text
lcd_put_u8str_max_P(p, len);
// Print the text at the correct place
lcd_put_u8str_max_P(col, line, p, len);
// Fill with spaces
for (uint8_t ix = slen - i; ix < len; ++ix) lcd_put_wchar(' ');
@ -406,9 +428,9 @@ void MarlinUI::clear_lcd() { lcd.clear(); }
static void logo_lines(PGM_P const extra) {
int16_t indent = (LCD_WIDTH - 8 - utf8_strlen_P(extra)) / 2;
lcd_moveto(indent, 0); lcd_put_wchar('\x00'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x01');
lcd_moveto(indent, 1); lcd_put_u8str_P(PSTR("|Marlin|")); lcd_put_u8str_P(extra);
lcd_moveto(indent, 2); lcd_put_wchar('\x02'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x03');
lcd_put_wchar(indent, 0, '\x00'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x01');
lcd_put_u8str_P(indent, 1, PSTR("|Marlin|")); lcd_put_u8str_P(extra);
lcd_put_wchar(indent, 2, '\x02'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x03');
}
void MarlinUI::show_bootscreen() {
@ -420,8 +442,7 @@ void MarlinUI::clear_lcd() { lcd.clear(); }
#define CENTER_OR_SCROLL(STRING,DELAY) \
lcd_erase_line(3); \
if (utf8_strlen(STRING) <= LCD_WIDTH) { \
lcd_moveto((LCD_WIDTH - utf8_strlen_P(PSTR(STRING))) / 2, 3); \
lcd_put_u8str_P(PSTR(STRING)); \
lcd_put_u8str_P((LCD_WIDTH - utf8_strlen_P(PSTR(STRING))) / 2, 3, PSTR(STRING)); \
safe_delay(DELAY); \
} \
else { \
@ -491,16 +512,12 @@ void MarlinUI::clear_lcd() { lcd.clear(); }
#endif // SHOW_BOOTSCREEN
void MarlinUI::draw_kill_screen() {
lcd_moveto(0, 0);
lcd_put_u8str(status_message);
#if LCD_HEIGHT < 4
lcd_moveto(0, 2);
#else
lcd_moveto(0, 2);
lcd_put_u8str_P(PSTR(MSG_HALTED));
lcd_moveto(0, 3);
lcd_put_u8str(0, 0, status_message);
lcd_uint_t y = 2;
#if LCD_HEIGHT >= 4
lcd_put_u8str_P(0, y++, PSTR(MSG_HALTED));
#endif
lcd_put_u8str_P(PSTR(MSG_PLEASE_RESET));
lcd_put_u8str_P(0, y, PSTR(MSG_PLEASE_RESET));
}
//
@ -859,8 +876,7 @@ void MarlinUI::draw_status_screen() {
#if LCD_HEIGHT > 3
lcd_moveto(0, 2);
lcd_put_wchar(LCD_STR_FEEDRATE[0]);
lcd_put_wchar(0, 2, LCD_STR_FEEDRATE[0]);
lcd_put_u8str(i16tostr3(feedrate_percentage));
lcd_put_wchar('%');
@ -868,8 +884,7 @@ void MarlinUI::draw_status_screen() {
duration_t elapsed = print_job_timer.duration();
const uint8_t len = elapsed.toDigital(buffer),
timepos = LCD_WIDTH - len - 1;
lcd_moveto(timepos, 2);
lcd_put_wchar(LCD_STR_CLOCK[0]);
lcd_put_wchar(timepos, 2, LCD_STR_CLOCK[0]);
lcd_put_u8str(buffer);
#if LCD_WIDTH >= 20
@ -918,8 +933,7 @@ void MarlinUI::draw_status_screen() {
_draw_axis_value(Z_AXIS, ftostr52sp(LOGICAL_Z_POSITION(current_position[Z_AXIS])), blink);
#if HAS_LEVELING && (HOTENDS > 1 || !HAS_HEATED_BED)
lcd_moveto(LCD_WIDTH - 1, 0);
lcd_put_wchar(planner.leveling_active || blink ? '_' : ' ');
lcd_put_wchar(LCD_WIDTH - 1, 0, planner.leveling_active || blink ? '_' : ' ');
#endif
// ========== Line 2 ==========
@ -934,8 +948,7 @@ void MarlinUI::draw_status_screen() {
_draw_bed_status(blink);
#endif
lcd_moveto(LCD_WIDTH - 9, 1);
lcd_put_wchar(LCD_STR_FEEDRATE[0]);
lcd_put_wchar(LCD_WIDTH - 9, 1, LCD_STR_FEEDRATE[0]);
lcd_put_u8str(i16tostr3(feedrate_percentage));
lcd_put_wchar('%');
@ -1006,8 +1019,7 @@ void MarlinUI::draw_status_screen() {
void draw_menu_item(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) {
uint8_t n = LCD_WIDTH - 2;
lcd_moveto(0, row);
lcd_put_wchar(sel ? pre_char : ' ');
lcd_put_wchar(0, row, sel ? pre_char : ' ');
n -= lcd_put_u8str_max_P(pstr, n);
for (; n; --n) lcd_put_wchar(' ');
lcd_put_wchar(post_char);
@ -1015,8 +1027,7 @@ void MarlinUI::draw_status_screen() {
void _draw_menu_item_edit(const bool sel, const uint8_t row, PGM_P pstr, const char* const data, const bool pgm) {
uint8_t n = LCD_WIDTH - 2 - (pgm ? utf8_strlen_P(data) : utf8_strlen(data));
lcd_moveto(0, row);
lcd_put_wchar(sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
lcd_put_wchar(0, row, sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
n -= lcd_put_u8str_max_P(pstr, n);
lcd_put_wchar(':');
for (; n; --n) lcd_put_wchar(' ');
@ -1026,14 +1037,12 @@ void MarlinUI::draw_status_screen() {
void draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
ui.encoder_direction_normal();
lcd_moveto(0, 1);
lcd_put_u8str_P(pstr);
lcd_put_u8str_P(0, 1, pstr);
if (value != nullptr) {
lcd_put_wchar(':');
int len = utf8_strlen(value);
const uint8_t valrow = (utf8_strlen_P(pstr) + 1 + len + 1) > (LCD_WIDTH - 2) ? 2 : 1; // Value on the next row if it won't fit
lcd_moveto((LCD_WIDTH - 1) - (len + 1), valrow); // Right-justified, padded by spaces
lcd_put_wchar(' '); // Overwrite char if value gets shorter
const lcd_uint_t valrow = (utf8_strlen_P(pstr) + 1 + len + 1) > (LCD_WIDTH - 2) ? 2 : 1; // Value on the next row if it won't fit
lcd_put_wchar((LCD_WIDTH - 1) - (len + 1), valrow, ' '); // Right-justified, padded, add a leading space
lcd_put_u8str(value);
}
}
@ -1051,8 +1060,7 @@ void MarlinUI::draw_status_screen() {
void draw_sd_menu_item(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) {
UNUSED(pstr);
lcd_moveto(0, row);
lcd_put_wchar(sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
lcd_put_wchar(0, row, sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
constexpr uint8_t maxlen = LCD_WIDTH - 2;
uint8_t n = maxlen - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), maxlen);
for (; n; --n) lcd_put_wchar(' ');
@ -1063,7 +1071,7 @@ void MarlinUI::draw_status_screen() {
#if ENABLED(LCD_HAS_STATUS_INDICATORS)
static void MarlinUI::update_indicators() {
void MarlinUI::update_indicators() {
// Set the LEDS - referred to as backlights by the LiquidTWI2 library
static uint8_t ledsprev = 0;
uint8_t leds = 0;
@ -1144,9 +1152,9 @@ void MarlinUI::draw_status_screen() {
} custom_char;
typedef struct {
uint8_t column, row,
x_pixel_offset, y_pixel_offset,
x_pixel_mask;
lcd_uint_t column, row,
x_pixel_offset, y_pixel_offset;
uint8_t x_pixel_mask;
} coordinate;
void add_edges_to_custom_char(custom_char &custom, const coordinate &ul, const coordinate &lr, const coordinate &brc, const uint8_t cell_location);
@ -1174,22 +1182,21 @@ void MarlinUI::draw_status_screen() {
return ret_val;
}
inline coordinate pixel_location(const uint8_t x, const uint8_t y) { return pixel_location((int16_t)x, (int16_t)y); }
inline coordinate pixel_location(const lcd_uint_t x, const lcd_uint_t y) { return pixel_location((int16_t)x, (int16_t)y); }
void prep_and_put_map_char(custom_char &chrdata, const coordinate &ul, const coordinate &lr, const coordinate &brc, const uint8_t cl, const char c, const uint8_t x, const uint8_t y) {
void prep_and_put_map_char(custom_char &chrdata, const coordinate &ul, const coordinate &lr, const coordinate &brc, const uint8_t cl, const char c, const lcd_uint_t x, const lcd_uint_t y) {
add_edges_to_custom_char(chrdata, ul, lr, brc, cl);
lcd.createChar(c, (uint8_t*)&chrdata);
lcd_moveto(x, y);
lcd_put_wchar(c);
lcd_put_wchar(x, y, c);
}
void MarlinUI::ubl_plot(const uint8_t x, const uint8_t inverted_y) {
void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) {
#if LCD_WIDTH >= 20
#define _LCD_W_POS 12
#define _PLOT_X 1
#define _MAP_X 3
#define _LABEL(C,X,Y) lcd_moveto(X, Y); lcd_put_u8str(C)
#define _LABEL(C,X,Y) lcd_put_u8str(X, Y, C)
#define _XLABEL(X,Y) _LABEL("X:",X,Y)
#define _YLABEL(X,Y) _LABEL("Y:",X,Y)
#define _ZLABEL(X,Y) _LABEL("Z:",X,Y)
@ -1197,7 +1204,7 @@ void MarlinUI::draw_status_screen() {
#define _LCD_W_POS 8
#define _PLOT_X 0
#define _MAP_X 1
#define _LABEL(X,Y,C) lcd_moveto(X, Y); lcd_put_wchar(C)
#define _LABEL(X,Y,C) lcd_put_wchar(X, Y, C)
#define _XLABEL(X,Y) _LABEL('X',X,Y)
#define _YLABEL(X,Y) _LABEL('Y',X,Y)
#define _ZLABEL(X,Y) _LABEL('Z',X,Y)
@ -1209,10 +1216,10 @@ void MarlinUI::draw_status_screen() {
* Show X and Y positions
*/
_XLABEL(_PLOT_X, 0);
lcd_put_u8str(ftostr52(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x]))));
lcd_put_u8str(ftostr52(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]))));
_YLABEL(_LCD_W_POS, 0);
lcd_put_u8str(ftostr52(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[inverted_y]))));
lcd_put_u8str(ftostr52(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]))));
lcd_moveto(_PLOT_X, 0);
@ -1220,13 +1227,13 @@ void MarlinUI::draw_status_screen() {
coordinate upper_left, lower_right, bottom_right_corner;
custom_char new_char;
uint8_t i, j, k, l, m, n, n_rows, n_cols, y,
bottom_line, right_edge,
x_map_pixels, y_map_pixels,
pixels_per_x_mesh_pnt, pixels_per_y_mesh_pnt,
suppress_x_offset = 0, suppress_y_offset = 0;
uint8_t i, n, n_rows, n_cols;
lcd_uint_t j, k, l, m, bottom_line, right_edge,
x_map_pixels, y_map_pixels,
pixels_per_x_mesh_pnt, pixels_per_y_mesh_pnt,
suppress_x_offset = 0, suppress_y_offset = 0;
y = GRID_MAX_POINTS_Y - inverted_y - 1;
const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y - 1) - y_plot;
upper_left.column = 0;
upper_left.row = 0;
@ -1261,17 +1268,13 @@ void MarlinUI::draw_status_screen() {
n_cols = right_edge / (HD44780_CHAR_WIDTH) + 1;
for (i = 0; i < n_cols; i++) {
lcd_moveto(i, 0);
lcd_put_wchar(CHAR_LINE_TOP); // Box Top line
lcd_moveto(i, n_rows - 1);
lcd_put_wchar(CHAR_LINE_BOT); // Box Bottom line
lcd_put_wchar(i, 0, CHAR_LINE_TOP); // Box Top line
lcd_put_wchar(i, n_rows - 1, CHAR_LINE_BOT); // Box Bottom line
}
for (j = 0; j < n_rows; j++) {
lcd_moveto(0, j);
lcd_put_wchar(CHAR_EDGE_L); // Box Left edge
lcd_moveto(n_cols - 1, j);
lcd_put_wchar(CHAR_EDGE_R); // Box Right edge
lcd_put_wchar(0, j, CHAR_EDGE_L); // Box Left edge
lcd_put_wchar(n_cols - 1, j, CHAR_EDGE_R); // Box Right edge
}
/**
@ -1281,10 +1284,8 @@ void MarlinUI::draw_status_screen() {
k = pixels_per_y_mesh_pnt * (GRID_MAX_POINTS_Y) + 2;
l = (HD44780_CHAR_HEIGHT) * n_rows;
if (l > k && l - k >= (HD44780_CHAR_HEIGHT) / 2) {
lcd_moveto(0, n_rows - 1); // Box Left edge
lcd_put_wchar(' ');
lcd_moveto(n_cols - 1, n_rows - 1); // Box Right edge
lcd_put_wchar(' ');
lcd_put_wchar(0, n_rows - 1, ' '); // Box Left edge
lcd_put_wchar(n_cols - 1, n_rows - 1, ' '); // Box Right edge
}
clear_custom_char(&new_char);
@ -1310,12 +1311,12 @@ void MarlinUI::draw_status_screen() {
new_char.custom_char_bits[j] = (uint8_t)_BV(i); // Char #3 is used for the box right edge
lcd.createChar(CHAR_EDGE_R, (uint8_t*)&new_char);
i = x * pixels_per_x_mesh_pnt - suppress_x_offset;
j = y * pixels_per_y_mesh_pnt - suppress_y_offset;
i = x_plot * pixels_per_x_mesh_pnt - suppress_x_offset;
j = y_plot_inv * pixels_per_y_mesh_pnt - suppress_y_offset;
upper_left = pixel_location(i, j);
k = (x + 1) * pixels_per_x_mesh_pnt - 1 - suppress_x_offset;
l = (y + 1) * pixels_per_y_mesh_pnt - 1 - suppress_y_offset;
k = (x_plot + 1) * pixels_per_x_mesh_pnt - 1 - suppress_x_offset;
l = (y_plot_inv + 1) * pixels_per_y_mesh_pnt - 1 - suppress_y_offset;
lower_right = pixel_location(k, l);
bottom_right_corner = pixel_location(x_map_pixels, y_map_pixels);
@ -1327,7 +1328,7 @@ void MarlinUI::draw_status_screen() {
*/
clear_custom_char(&new_char);
const uint8_t ypix = _MIN(upper_left.y_pixel_offset + pixels_per_y_mesh_pnt, HD44780_CHAR_HEIGHT);
const lcd_uint_t ypix = _MIN(upper_left.y_pixel_offset + pixels_per_y_mesh_pnt, HD44780_CHAR_HEIGHT);
for (j = upper_left.y_pixel_offset; j < ypix; j++) {
i = upper_left.x_pixel_mask;
for (k = 0; k < pixels_per_x_mesh_pnt; k++) {
@ -1398,11 +1399,10 @@ void MarlinUI::draw_status_screen() {
/**
* Print plot position
*/
lcd_moveto(_LCD_W_POS, 0);
lcd_put_wchar('(');
lcd_put_u8str(ui8tostr3(x));
lcd_put_wchar(_LCD_W_POS, 0, '(');
lcd_put_u8str(ui8tostr3(x_plot));
lcd_put_wchar(',');
lcd_put_u8str(ui8tostr3(inverted_y));
lcd_put_u8str(ui8tostr3(y_plot));
lcd_put_wchar(')');
#if LCD_HEIGHT <= 3 // 16x2 or 20x2 display
@ -1411,8 +1411,8 @@ void MarlinUI::draw_status_screen() {
* Print Z values
*/
_ZLABEL(_LCD_W_POS, 1);
if (!isnan(ubl.z_values[x][inverted_y]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y]));
if (!isnan(ubl.z_values[x_plot][y_plot]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x_plot][y_plot]));
else
lcd_put_u8str_P(PSTR(" -----"));
@ -1422,16 +1422,16 @@ void MarlinUI::draw_status_screen() {
* Show all values at right of screen
*/
_XLABEL(_LCD_W_POS, 1);
lcd_put_u8str(ftostr52(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x]))));
lcd_put_u8str(ftostr52(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]))));
_YLABEL(_LCD_W_POS, 2);
lcd_put_u8str(ftostr52(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[inverted_y]))));
lcd_put_u8str(ftostr52(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]))));
/**
* Show the location value
*/
_ZLABEL(_LCD_W_POS, 3);
if (!isnan(ubl.z_values[x][inverted_y]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x][inverted_y]));
if (!isnan(ubl.z_values[x_plot][y_plot]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x_plot][y_plot]));
else
lcd_put_u8str_P(PSTR(" -----"));

@ -40,10 +40,14 @@
#define U8G_COM_ST7920_HAL_SW_SPI u8g_com_std_sw_spi_fn
#define U8G_COM_ST7920_HAL_HW_SPI u8g_com_stm32duino_hw_spi_fn
#elif defined(ARDUINO_ARCH_STM32)
uint8_t u8g_com_arduino_std_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_HAL_SW_SPI_FN u8g_com_arduino_std_sw_spi_fn
uint8_t u8g_com_stm32duino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_HAL_HW_SPI_FN u8g_com_stm32duino_hw_spi_fn
uint8_t u8g_com_arduino_st7920_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_ST7920_HAL_SW_SPI u8g_com_arduino_st7920_spi_fn
#define U8G_COM_ST7920_HAL_HW_SPI u8g_com_stm32duino_hw_spi_fn
uint8_t u8g_com_arduino_st7920_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_ST7920_HAL_HW_SPI u8g_com_arduino_st7920_hw_spi_fn
#elif defined(__AVR__)
uint8_t u8g_com_HAL_AVR_sw_sp_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
#define U8G_COM_HAL_SW_SPI_FN u8g_com_HAL_AVR_sw_sp_fn

@ -35,7 +35,7 @@
#include "../../../_Bootscreen.h"
#ifndef CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH
#define CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH ((CUSTOM_BOOTSCREEN_BMPWIDTH + 7) / 8)
#define CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH CEILING(CUSTOM_BOOTSCREEN_BMPWIDTH, 8)
#endif
#ifndef CUSTOM_BOOTSCREEN_BMPHEIGHT
#define CUSTOM_BOOTSCREEN_BMPHEIGHT (sizeof(custom_start_bmp) / (CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH))
@ -69,6 +69,142 @@
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
};
#if ENABLED(BOOT_MARLIN_LOGO_ANIMATED)
const unsigned char start_bmp1[] PROGMEM = {
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
};
const unsigned char start_bmp2[] PROGMEM = {
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B10000011,B11001111,B00000000,B00000000,B00000000,B00000000,B00111111,
B10000111,B11111111,B10000000,B00000000,B00000000,B00000000,B00011111,
B10000110,B01111001,B10000000,B00000000,B00000000,B00000000,B00001111,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000111,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000011,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000000,B00000000,B00000000,B00000000,B00000001,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
};
const unsigned char start_bmp3[] PROGMEM = {
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B10000011,B11001111,B00000000,B00000000,B00000000,B00000000,B00111111,
B10000111,B11111111,B10000000,B00000000,B00000000,B00000000,B00011111,
B10000110,B01111001,B10000000,B00000000,B00000000,B00000000,B00001111,
B10001100,B00110000,B11000111,B10000000,B00000000,B00000000,B00000111,
B10001100,B00110000,B11001111,B11000000,B00000000,B00000000,B00000011,
B10001100,B00110000,B11011100,B11100000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11011000,B01100000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11010000,B01100000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11011000,B01100000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11011100,B01100000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11001111,B01110000,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000111,B01110000,B00000000,B00000000,B00000001,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
};
const unsigned char start_bmp4[] PROGMEM = {
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B10000011,B11001111,B00000000,B00000000,B00000000,B00000000,B00111111,
B10000111,B11111111,B10000000,B00000000,B00000000,B00000000,B00011111,
B10000110,B01111001,B10000000,B00000000,B00000000,B00000000,B00001111,
B10001100,B00110000,B11000111,B10000011,B10000000,B00000000,B00000111,
B10001100,B00110000,B11001111,B11000111,B11000000,B00000000,B00000011,
B10001100,B00110000,B11011100,B11101100,B11100000,B00000000,B00000001,
B10001100,B00110000,B11011000,B01101100,B01100000,B00000000,B00000001,
B10001100,B00110000,B11010000,B01101100,B00000000,B00000000,B00000001,
B10001100,B00110000,B11011000,B01101100,B00000000,B00000000,B00000001,
B10001100,B00110000,B11011100,B01101100,B00000000,B00000000,B00000001,
B10001100,B00110000,B11001111,B01111100,B00000000,B00000000,B00000001,
B10001100,B00110000,B11000111,B01111100,B00000000,B00000000,B00000001,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
};
const unsigned char start_bmp5[] PROGMEM = {
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B10000011,B11001111,B00000000,B00000000,B00001100,B00000000,B00111111,
B10000111,B11111111,B10000000,B00000000,B00001100,B00000000,B00011111,
B10000110,B01111001,B10000000,B00000000,B00001100,B00000000,B00001111,
B10001100,B00110000,B11000111,B10000011,B10001100,B00000000,B00000111,
B10001100,B00110000,B11001111,B11000111,B11001100,B00000000,B00000011,
B10001100,B00110000,B11011100,B11101100,B11101100,B00000000,B00000001,
B10001100,B00110000,B11011000,B01101100,B01101100,B00000000,B00000001,
B10001100,B00110000,B11010000,B01101100,B00001100,B00000000,B00000001,
B10001100,B00110000,B11011000,B01101100,B00001100,B00000000,B00000001,
B10001100,B00110000,B11011100,B01101100,B00001110,B00000000,B00000001,
B10001100,B00110000,B11001111,B01111100,B00000111,B10000000,B00000001,
B10001100,B00110000,B11000111,B01111100,B00000011,B10000000,B00000001,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
};
const unsigned char start_bmp6[] PROGMEM = {
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B10000011,B11001111,B00000000,B00000000,B00001100,B00110000,B00111111,
B10000111,B11111111,B10000000,B00000000,B00001100,B00110000,B00011111,
B10000110,B01111001,B10000000,B00000000,B00001100,B00000000,B00001111,
B10001100,B00110000,B11000111,B10000011,B10001100,B00110000,B00000111,
B10001100,B00110000,B11001111,B11000111,B11001100,B00110000,B00000011,
B10001100,B00110000,B11011100,B11101100,B11101100,B00110000,B00000001,
B10001100,B00110000,B11011000,B01101100,B01101100,B00110000,B00000001,
B10001100,B00110000,B11010000,B01101100,B00001100,B00110000,B00000001,
B10001100,B00110000,B11011000,B01101100,B00001100,B00110000,B00000001,
B10001100,B00110000,B11011100,B01101100,B00001110,B00111000,B00000001,
B10001100,B00110000,B11001111,B01111100,B00000111,B10011100,B00000001,
B10001100,B00110000,B11000111,B01111100,B00000011,B10001100,B00000001,
B01000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B00011111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111000
};
#endif
#else
#define START_BMPWIDTH 112
@ -114,10 +250,269 @@
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
};
#if ENABLED(BOOT_MARLIN_LOGO_ANIMATED)
const unsigned char start_bmp1[] PROGMEM = {
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
};
const unsigned char start_bmp2[] PROGMEM = {
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,B11111111,
B11000000,B00001111,B11000000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,B11111111,
B11000000,B00111111,B11100001,B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,B11111111,
B11000000,B01111111,B11110011,B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,
B11000000,B11111111,B11111111,B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,
B11000001,B11111000,B01111111,B10000111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B11000001,B11110000,B00111111,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
};
const unsigned char start_bmp3[] PROGMEM = {
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,B11111111,
B11000000,B00001111,B11000000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,B11111111,
B11000000,B00111111,B11100001,B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,B11111111,
B11000000,B01111111,B11110011,B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,
B11000000,B11111111,B11111111,B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,
B11000001,B11111000,B01111111,B10000111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B11000001,B11110000,B00111111,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00011111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B11110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11110011,B11111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11100000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B01111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B01111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B00111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11100000,B00111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B00111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B00111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B11111111,B00111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B00111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
};
const unsigned char start_bmp4[] PROGMEM = {
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00111111,B11111111,
B11000000,B00001111,B11000000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,B11111111,
B11000000,B00111111,B11100001,B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001111,B11111111,
B11000000,B01111111,B11110011,B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,
B11000000,B11111111,B11111111,B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,
B11000001,B11111000,B01111111,B10000111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,
B11000001,B11110000,B00111111,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00011111,B00000000,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B01111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B11000000,B00001111,B11111000,B00000000,B00000000,B00000000,B00000000,B00111111,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B11100000,B00011111,B11111100,B00000000,B00000000,B00000000,B00000000,B00011111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B11110000,B00111111,B11111110,B00000000,B00000000,B00000000,B00000000,B00001111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11110011,B11111000,B00111111,B00111110,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11100000,B11111100,B01111100,B00011111,B00000000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B01111100,B01111100,B00001111,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B01111100,B01111000,B00001111,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B00111100,B01111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11100000,B00111100,B01111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B00111111,B11111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B00111111,B11111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B11111111,B00111111,B11111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B00111111,B11111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
};
const unsigned char start_bmp5[] PROGMEM = {
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00111111,B11111111,
B11000000,B00001111,B11000000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00011111,B11111111,
B11000000,B00111111,B11100001,B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00001111,B11111111,
B11000000,B01111111,B11110011,B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000111,B11111111,
B11000000,B11111111,B11111111,B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000011,B11111111,
B11000001,B11111000,B01111111,B10000111,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000001,B11111111,
B11000001,B11110000,B00111111,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000000,B11111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00011111,B00000000,B00000011,B11100000,B01111000,B00000000,B00000000,B00000000,B01111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B11000000,B00001111,B11111000,B01111000,B00000000,B00000000,B00000000,B00111111,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B11100000,B00011111,B11111100,B01111000,B00000000,B00000000,B00000000,B00011111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B11110000,B00111111,B11111110,B01111000,B00000000,B00000000,B00000000,B00001111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11110011,B11111000,B00111111,B00111110,B01111000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11100000,B11111100,B01111100,B00011111,B01111000,B00000000,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B01111100,B01111100,B00001111,B01111000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B01111100,B01111000,B00001111,B01111000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B00111100,B01111000,B00000000,B01111000,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11100000,B00111100,B01111000,B00000000,B01111100,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B00111111,B11111000,B00000000,B01111111,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B00111111,B11111000,B00000000,B00111111,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B11111111,B00111111,B11111000,B00000000,B00011111,B00000000,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B00111111,B11111000,B00000000,B00001111,B00000000,B00000000,B00000000,B00000011,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
};
const unsigned char start_bmp6[] PROGMEM = {
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,B11111111,B11111111,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000011,B11111111,B11111111,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B11111111,B11111111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111111,B11111111,
B11000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00111111,B11111111,
B11000000,B00001111,B11000000,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00011000,B00000000,B00011111,B11111111,
B11000000,B00111111,B11100001,B11111111,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00001111,B11111111,
B11000000,B01111111,B11110011,B11111111,B10000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00000111,B11111111,
B11000000,B11111111,B11111111,B11111111,B11000000,B00000000,B00000000,B00000000,B00000000,B01111000,B00111100,B00000000,B00000011,B11111111,
B11000001,B11111000,B01111111,B10000111,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000001,B11111111,
B11000001,B11110000,B00111111,B00000011,B11100000,B00000000,B00000000,B00000000,B00000000,B01111000,B00000000,B00000000,B00000000,B11111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B00011111,B00000000,B00000011,B11100000,B01111000,B00111100,B00000000,B00000000,B01111111,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B11000000,B00001111,B11111000,B01111000,B00111100,B00000000,B00000000,B00111111,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B11100000,B00011111,B11111100,B01111000,B00111100,B00000000,B00000000,B00011111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B11110000,B00111111,B11111110,B01111000,B00111100,B00000000,B00000000,B00001111,
B11000001,B11100000,B00011110,B00000001,B11100011,B11110011,B11111000,B00111111,B00111110,B01111000,B00111100,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11100000,B11111100,B01111100,B00011111,B01111000,B00111100,B00000000,B00000000,B00000111,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B01111100,B01111100,B00001111,B01111000,B00111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B01111100,B01111000,B00001111,B01111000,B00111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B10000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100111,B11000000,B00111100,B01111000,B00000000,B01111000,B00111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11100000,B00111100,B01111000,B00000000,B01111100,B00111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100011,B11111111,B00111111,B11111000,B00000000,B01111111,B10111100,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100001,B11111111,B00111111,B11111000,B00000000,B00111111,B10111111,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B11111111,B00111111,B11111000,B00000000,B00011111,B10111111,B00000000,B00000000,B00000011,
B11000001,B11100000,B00011110,B00000001,B11100000,B01111111,B00111111,B11111000,B00000000,B00001111,B10111111,B00000000,B00000000,B00000011,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000111,
B01100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000110,
B01110000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001110,
B00111000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011100,
B00011110,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B01111000,
B00001111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11110000,
B00000001,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B11111111,B10000000
};
#endif
#endif
#if ENABLED(BOOT_MARLIN_LOGO_ANIMATED)
#ifndef MARLIN_BOOTSCREEN_FRAME_TIME
#define MARLIN_BOOTSCREEN_FRAME_TIME 100 // (ms)
#endif
const unsigned char * const marlin_bootscreen_animation[] PROGMEM = {
start_bmp1, start_bmp2, start_bmp3, start_bmp4, start_bmp5, start_bmp6, start_bmp
};
#endif
#ifndef START_BMP_BYTEWIDTH
#define START_BMP_BYTEWIDTH ((START_BMPWIDTH + 7) / 8)
#define START_BMP_BYTEWIDTH CEILING(START_BMPWIDTH, 8)
#endif
#ifndef START_BMPHEIGHT
#define START_BMPHEIGHT (sizeof(start_bmp) / (START_BMP_BYTEWIDTH))

@ -1220,10 +1220,10 @@
#define STATUS_HOTEND4_WIDTH STATUS_HOTEND3_WIDTH
#endif
#ifndef STATUS_HOTEND5_WIDTH
#define STATUS_HOTEND5_WIDTH STATUS_HOTEND5_WIDTH
#define STATUS_HOTEND5_WIDTH STATUS_HOTEND4_WIDTH
#endif
#ifndef STATUS_HOTEND6_WIDTH
#define STATUS_HOTEND6_WIDTH STATUS_HOTEND6_WIDTH
#define STATUS_HOTEND6_WIDTH STATUS_HOTEND5_WIDTH
#endif
constexpr uint8_t status_hotend_width[HOTENDS] = ARRAY_N(HOTENDS, STATUS_HOTEND1_WIDTH, STATUS_HOTEND2_WIDTH, STATUS_HOTEND3_WIDTH, STATUS_HOTEND4_WIDTH, STATUS_HOTEND5_WIDTH, STATUS_HOTEND6_WIDTH);
@ -1264,10 +1264,10 @@
#define STATUS_HOTEND4_X STATUS_HOTEND3_X + STATUS_HEATERS_XSPACE
#endif
#ifndef STATUS_HOTEND5_X
#define STATUS_HOTEND5_X STATUS_HOTEND5_X + STATUS_HEATERS_XSPACE
#define STATUS_HOTEND5_X STATUS_HOTEND4_X + STATUS_HEATERS_XSPACE
#endif
#ifndef STATUS_HOTEND6_X
#define STATUS_HOTEND6_X STATUS_HOTEND6_X + STATUS_HEATERS_XSPACE
#define STATUS_HOTEND6_X STATUS_HOTEND5_X + STATUS_HEATERS_XSPACE
#endif
#if HOTENDS > 2
@ -1291,10 +1291,10 @@
#define STATUS_HOTEND4_TEXT_X STATUS_HOTEND3_TEXT_X + STATUS_HEATERS_XSPACE
#endif
#ifndef STATUS_HOTEND5_TEXT_X
#define STATUS_HOTEND5_TEXT_X STATUS_HOTEND5_TEXT_X + STATUS_HEATERS_XSPACE
#define STATUS_HOTEND5_TEXT_X STATUS_HOTEND4_TEXT_X + STATUS_HEATERS_XSPACE
#endif
#ifndef STATUS_HOTEND6_TEXT_X
#define STATUS_HOTEND6_TEXT_X STATUS_HOTEND6_TEXT_X + STATUS_HEATERS_XSPACE
#define STATUS_HOTEND6_TEXT_X STATUS_HOTEND5_TEXT_X + STATUS_HEATERS_XSPACE
#endif
constexpr uint8_t status_hotend_text_x[] = ARRAY_N(HOTENDS, STATUS_HOTEND1_TEXT_X, STATUS_HOTEND2_TEXT_X, STATUS_HOTEND3_TEXT_X, STATUS_HOTEND4_TEXT_X, STATUS_HOTEND5_TEXT_X, STATUS_HOTEND6_TEXT_X);
#define STATUS_HOTEND_TEXT_X(N) status_hotend_text_x[N]

@ -22,7 +22,7 @@
int lcd_glyph_height(void) { return u8g_GetFontBBXHeight(u8g.getU8g()); }
void lcd_moveto(const uint8_t col, const uint8_t row) { u8g.setPrintPos(col, row); }
void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) { u8g.setPrintPos(col, row); }
void lcd_put_int(const int i) { u8g.print(i); }
@ -33,26 +33,22 @@ int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
u8g.print((char)c);
return u8g_GetFontBBXWidth(u8g.getU8g());
}
unsigned int x = u8g.getPrintCol(),
y = u8g.getPrintRow(),
ret = uxg_DrawWchar(u8g.getU8g(), x, y, c, max_length);
u8g_uint_t x = u8g.getPrintCol(), y = u8g.getPrintRow(),
ret = uxg_DrawWchar(u8g.getU8g(), x, y, c, max_length);
u8g.setPrintPos(x + ret, y);
return ret;
}
int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
unsigned int x = u8g.getPrintCol(),
y = u8g.getPrintRow(),
ret = uxg_DrawUtf8Str(u8g.getU8g(), x, y, utf8_str, max_length);
u8g_uint_t x = u8g.getPrintCol(), y = u8g.getPrintRow(),
ret = uxg_DrawUtf8Str(u8g.getU8g(), x, y, utf8_str, max_length);
u8g.setPrintPos(x + ret, y);
return ret;
}
int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
unsigned int x = u8g.getPrintCol(),
y = u8g.getPrintRow(),
ret = uxg_DrawUtf8StrP(u8g.getU8g(), x, y, utf8_str_P, max_length);
u8g_uint_t x = u8g.getPrintCol(), y = u8g.getPrintRow(),
ret = uxg_DrawUtf8StrP(u8g.getU8g(), x, y, utf8_str_P, max_length);
u8g.setPrintPos(x + ret, y);
return ret;
}

@ -100,8 +100,7 @@
FORCE_INLINE void _draw_centered_temp(const int16_t temp, const uint8_t tx, const uint8_t ty) {
const char *str = i16tostr3(temp);
const uint8_t len = str[0] != ' ' ? 3 : str[1] != ' ' ? 2 : 1;
lcd_moveto(tx - len * (INFO_FONT_WIDTH) / 2 + 1, ty);
lcd_put_u8str(&str[3-len]);
lcd_put_u8str(tx - len * (INFO_FONT_WIDTH) / 2 + 1, ty, &str[3-len]);
lcd_put_wchar(LCD_STR_DEGREE[0]);
}
@ -264,8 +263,7 @@ FORCE_INLINE void _draw_heater_status(const heater_ind_t heater, const bool blin
//
FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const bool blink) {
const uint8_t offs = (XYZ_SPACING) * axis;
lcd_moveto(X_LABEL_POS + offs, XYZ_BASELINE);
lcd_put_wchar('X' + axis);
lcd_put_wchar(X_LABEL_POS + offs, XYZ_BASELINE, 'X' + axis);
lcd_moveto(X_VALUE_POS + offs, XYZ_BASELINE);
if (blink)
lcd_put_u8str(value);
@ -429,8 +427,7 @@ void MarlinUI::draw_status_screen() {
c = '*';
}
#endif
lcd_moveto(STATUS_FAN_TEXT_X, STATUS_FAN_TEXT_Y);
lcd_put_u8str(i16tostr3(thermalManager.fanPercent(spd)));
lcd_put_u8str(STATUS_FAN_TEXT_X, STATUS_FAN_TEXT_Y, i16tostr3(thermalManager.fanPercent(spd)));
lcd_put_wchar(c);
}
}
@ -488,8 +485,7 @@ void MarlinUI::draw_status_screen() {
#if ENABLED(DOGM_SD_PERCENT)
if (PAGE_CONTAINS(41, 48)) {
// Percent complete
lcd_moveto(55, 48);
lcd_put_u8str(ui8tostr3(progress));
lcd_put_u8str(55, 48, ui8tostr3(progress));
lcd_put_wchar('%');
}
#endif
@ -510,8 +506,7 @@ void MarlinUI::draw_status_screen() {
duration_t elapsed = print_job_timer.duration();
bool has_days = (elapsed.value >= 60*60*24L);
uint8_t len = elapsed.toDigital(buffer, has_days);
lcd_moveto(SD_DURATION_X, EXTRAS_BASELINE);
lcd_put_u8str(buffer);
lcd_put_u8str(SD_DURATION_X, EXTRAS_BASELINE, buffer);
}
#endif // HAS_PRINT_PROGRESS
@ -520,10 +515,6 @@ void MarlinUI::draw_status_screen() {
// XYZ Coordinates
//
#define X_LABEL_POS 3
#define X_VALUE_POS 11
#define XYZ_SPACING 37
#if ENABLED(XYZ_HOLLOW_FRAME)
#define XYZ_FRAME_TOP 29
#define XYZ_FRAME_HEIGHT INFO_FONT_ASCENT + 3
@ -550,8 +541,6 @@ void MarlinUI::draw_status_screen() {
// Two-component mix / gradient instead of XY
lcd_moveto(X_LABEL_POS, XYZ_BASELINE);
char mixer_messages[12];
const char *mix_label;
#if ENABLED(GRADIENT_MIX)
@ -566,7 +555,7 @@ void MarlinUI::draw_status_screen() {
mix_label = "Mx";
}
sprintf_P(mixer_messages, PSTR("%s %d;%d%% "), mix_label, int(mixer.mix[0]), int(mixer.mix[1]));
lcd_put_u8str(mixer_messages);
lcd_put_u8str(X_LABEL_POS, XYZ_BASELINE, mixer_messages);
#else
@ -591,28 +580,22 @@ void MarlinUI::draw_status_screen() {
if (PAGE_CONTAINS(EXTRAS_2_BASELINE - INFO_FONT_ASCENT, EXTRAS_2_BASELINE - 1)) {
set_font(FONT_MENU);
lcd_moveto(3, EXTRAS_2_BASELINE);
lcd_put_wchar(LCD_STR_FEEDRATE[0]);
lcd_put_wchar(3, EXTRAS_2_BASELINE, LCD_STR_FEEDRATE[0]);
set_font(FONT_STATUSMENU);
lcd_moveto(12, EXTRAS_2_BASELINE);
lcd_put_u8str(i16tostr3(feedrate_percentage));
lcd_put_u8str(12, EXTRAS_2_BASELINE, i16tostr3(feedrate_percentage));
lcd_put_wchar('%');
//
// Filament sensor display if SD is disabled
//
#if ENABLED(FILAMENT_LCD_DISPLAY) && DISABLED(SDSUPPORT)
lcd_moveto(56, EXTRAS_2_BASELINE);
lcd_put_u8str(wstring);
lcd_moveto(102, EXTRAS_2_BASELINE);
lcd_put_u8str(mstring);
lcd_put_u8str(56, EXTRAS_2_BASELINE, wstring);
lcd_put_u8str(102, EXTRAS_2_BASELINE, mstring);
lcd_put_wchar('%');
set_font(FONT_MENU);
lcd_moveto(47, EXTRAS_2_BASELINE);
lcd_put_wchar(LCD_STR_FILAM_DIA[0]); // lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA));
lcd_moveto(93, EXTRAS_2_BASELINE);
lcd_put_wchar(LCD_STR_FILAM_MUL[0]);
lcd_put_wchar(47, EXTRAS_2_BASELINE, LCD_STR_FILAM_DIA[0]); // lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA));
lcd_put_wchar(93, EXTRAS_2_BASELINE, LCD_STR_FILAM_MUL[0]);
#endif
}

@ -102,30 +102,29 @@ void MarlinUI::set_font(const MarlinFont font_nr) {
}
}
bool MarlinUI::detected() { return true; }
#if ENABLED(SHOW_BOOTSCREEN)
#if ENABLED(SHOW_CUSTOM_BOOTSCREEN)
// Draws a slice of a particular frame of the custom bootscreen, without the u8g loop
void MarlinUI::draw_custom_bootscreen(const uint8_t frame/*=0*/) {
constexpr u8g_uint_t left = u8g_uint_t((LCD_PIXEL_WIDTH - (CUSTOM_BOOTSCREEN_BMPWIDTH)) / 2),
top = u8g_uint_t((LCD_PIXEL_HEIGHT - (CUSTOM_BOOTSCREEN_BMPHEIGHT)) / 2);
top = u8g_uint_t((LCD_PIXEL_HEIGHT - (CUSTOM_BOOTSCREEN_BMPHEIGHT)) / 2);
#if ENABLED(CUSTOM_BOOTSCREEN_INVERTED)
constexpr u8g_uint_t right = left + CUSTOM_BOOTSCREEN_BMPWIDTH,
bottom = top + CUSTOM_BOOTSCREEN_BMPHEIGHT;
#endif
const u8g_pgm_uint8_t * const bmp =
#if ENABLED(ANIMATED_BOOTSCREEN)
#if ENABLED(CUSTOM_BOOTSCREEN_ANIMATED)
(u8g_pgm_uint8_t*)pgm_read_ptr(&custom_bootscreen_animation[frame])
#else
custom_start_bmp
#endif
;
u8g.drawBitmapP(
left, top,
CEILING(CUSTOM_BOOTSCREEN_BMPWIDTH, 8), CUSTOM_BOOTSCREEN_BMPHEIGHT, bmp
);
u8g.drawBitmapP(left, top, CUSTOM_BOOTSCREEN_BMP_BYTEWIDTH, CUSTOM_BOOTSCREEN_BMPHEIGHT, bmp);
#if ENABLED(CUSTOM_BOOTSCREEN_INVERTED)
if (frame == 0) {
@ -140,7 +139,7 @@ void MarlinUI::set_font(const MarlinFont font_nr) {
// Shows the custom bootscreen, with the u8g loop, animations and delays
void MarlinUI::show_custom_bootscreen() {
#if DISABLED(ANIMATED_BOOTSCREEN)
#if DISABLED(CUSTOM_BOOTSCREEN_ANIMATED)
constexpr millis_t d = 0;
constexpr uint8_t f = 0;
#else
@ -163,23 +162,22 @@ void MarlinUI::set_font(const MarlinFont font_nr) {
// Draws a slice of the Marlin bootscreen, without the u8g loop
void MarlinUI::draw_marlin_bootscreen() {
// Screen dimensions.
//const uint8_t width = u8g.getWidth(), height = u8g.getHeight();
constexpr uint8_t width = LCD_PIXEL_WIDTH, height = LCD_PIXEL_HEIGHT;
//const u8g_uint_t width = u8g.getWidth(), height = u8g.getHeight();
constexpr u8g_uint_t width = LCD_PIXEL_WIDTH, height = LCD_PIXEL_HEIGHT;
// Determine text space needed
#ifndef STRING_SPLASH_LINE2
constexpr uint8_t text_total_height = MENU_FONT_HEIGHT,
text_width_1 = uint8_t(sizeof(STRING_SPLASH_LINE1) - 1) * uint8_t(MENU_FONT_WIDTH),
text_width_2 = 0;
constexpr u8g_uint_t text_total_height = MENU_FONT_HEIGHT,
text_width_2 = 0;
#else
constexpr uint8_t text_total_height = uint8_t(MENU_FONT_HEIGHT) * 2,
text_width_1 = uint8_t(sizeof(STRING_SPLASH_LINE1) - 1) * uint8_t(MENU_FONT_WIDTH),
text_width_2 = uint8_t(sizeof(STRING_SPLASH_LINE2) - 1) * uint8_t(MENU_FONT_WIDTH);
constexpr u8g_uint_t text_total_height = (MENU_FONT_HEIGHT) * 2,
text_width_2 = u8g_uint_t((sizeof(STRING_SPLASH_LINE2) - 1) * (MENU_FONT_WIDTH));
#endif
constexpr uint8_t text_max_width = _MAX(text_width_1, text_width_2),
rspace = width - (START_BMPWIDTH);
constexpr u8g_uint_t text_width_1 = u8g_uint_t((sizeof(STRING_SPLASH_LINE1) - 1) * (MENU_FONT_WIDTH)),
text_max_width = _MAX(text_width_1, text_width_2),
rspace = width - (START_BMPWIDTH);
int8_t offx, offy, txt_base, txt_offx_1, txt_offx_2;
u8g_int_t offx, offy, txt_base, txt_offx_1, txt_offx_2;
// Can the text fit to the right of the bitmap?
if (text_max_width < rspace) {
@ -200,13 +198,29 @@ void MarlinUI::set_font(const MarlinFont font_nr) {
NOLESS(offx, 0);
NOLESS(offy, 0);
u8g.drawBitmapP(offx, offy, (START_BMPWIDTH + 7) / 8, START_BMPHEIGHT, start_bmp);
set_font(FONT_MENU);
#ifndef STRING_SPLASH_LINE2
u8g.drawStr(txt_offx_1, txt_base, STRING_SPLASH_LINE1);
auto draw_bootscreen_bmp = [&](const uint8_t *bitmap) {
u8g.drawBitmapP(offx, offy, START_BMP_BYTEWIDTH, START_BMPHEIGHT, bitmap);
set_font(FONT_MENU);
#ifndef STRING_SPLASH_LINE2
lcd_put_u8str_P(txt_offx_1, txt_base, PSTR(STRING_SPLASH_LINE1));
#else
lcd_put_u8str_P(txt_offx_1, txt_base - (MENU_FONT_HEIGHT), PSTR(STRING_SPLASH_LINE1));
lcd_put_u8str_P(txt_offx_2, txt_base, PSTR(STRING_SPLASH_LINE2));
#endif
};
#if DISABLED(BOOT_MARLIN_LOGO_ANIMATED)
draw_bootscreen_bmp(start_bmp);
#else
u8g.drawStr(txt_offx_1, txt_base - (MENU_FONT_HEIGHT), STRING_SPLASH_LINE1);
u8g.drawStr(txt_offx_2, txt_base, STRING_SPLASH_LINE2);
constexpr millis_t d = MARLIN_BOOTSCREEN_FRAME_TIME;
LOOP_L_N(f, COUNT(marlin_bootscreen_animation)) {
u8g.firstPage();
do {
const u8g_pgm_uint8_t * const bmp = (u8g_pgm_uint8_t*)pgm_read_ptr(&marlin_bootscreen_animation[f]);
draw_bootscreen_bmp(bmp);
} while (u8g.nextPage());
if (d) safe_delay(d);
}
#endif
}
@ -286,16 +300,13 @@ void MarlinUI::draw_kill_screen() {
#if ENABLED(LIGHTWEIGHT_UI)
ST7920_Lite_Status_Screen::clear_text_buffer();
#endif
const uint8_t h4 = u8g.getHeight() / 4;
const u8g_uint_t h4 = u8g.getHeight() / 4;
u8g.firstPage();
do {
set_font(FONT_MENU);
lcd_moveto(0, h4 * 1);
lcd_put_u8str(status_message);
lcd_moveto(0, h4 * 2);
lcd_put_u8str_P(PSTR(MSG_HALTED));
lcd_moveto(0, h4 * 3);
lcd_put_u8str_P(PSTR(MSG_PLEASE_RESET));
lcd_put_u8str(0, h4 * 1, status_message);
lcd_put_u8str_P(0, h4 * 2, PSTR(MSG_HALTED));
lcd_put_u8str_P(0, h4 * 3, PSTR(MSG_PLEASE_RESET));
} while (u8g.nextPage());
}
@ -303,7 +314,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
#if HAS_LCD_MENU
uint8_t row_y1, row_y2;
u8g_uint_t row_y1, row_y2;
#if ENABLED(ADVANCED_PAUSE_FEATURE)
@ -313,8 +324,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
if (!PAGE_CONTAINS(row_y1 + 1, row_y2 + 2)) return;
lcd_moveto(LCD_PIXEL_WIDTH - 11 * (MENU_FONT_WIDTH), row_y2);
lcd_put_wchar('E');
lcd_put_wchar(LCD_PIXEL_WIDTH - 11 * (MENU_FONT_WIDTH), row_y2, 'E');
lcd_put_wchar((char)('1' + extruder));
lcd_put_wchar(' ');
lcd_put_u8str(i16tostr3(thermalManager.degHotend(extruder)));
@ -360,7 +370,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
if (mark_as_selected(row, invert)) {
uint8_t n = LCD_PIXEL_WIDTH; // pixel width of string allowed
u8g_uint_t n = LCD_PIXEL_WIDTH; // pixel width of string allowed
if (center && !valstr) {
int8_t pad = (LCD_WIDTH - utf8_strlen_P(pstr)) / 2;
@ -377,11 +387,10 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
UNUSED(pre_char);
if (mark_as_selected(row, sel)) {
uint8_t n = (LCD_WIDTH - 2) * (MENU_FONT_WIDTH);
u8g_uint_t n = (LCD_WIDTH - 2) * (MENU_FONT_WIDTH);
n -= lcd_put_u8str_max_P(pstr, n);
while (n > MENU_FONT_WIDTH) n -= lcd_put_wchar(' ');
lcd_moveto(LCD_PIXEL_WIDTH - (MENU_FONT_WIDTH), row_y2);
lcd_put_wchar(post_char);
lcd_put_wchar(LCD_PIXEL_WIDTH - (MENU_FONT_WIDTH), row_y2, post_char);
lcd_put_wchar(' ');
}
}
@ -390,7 +399,7 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
void _draw_menu_item_edit(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
if (mark_as_selected(row, sel)) {
const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen((char*)data));
uint8_t n = (LCD_WIDTH - 2 - vallen) * (MENU_FONT_WIDTH);
u8g_uint_t n = (LCD_WIDTH - 2 - vallen) * (MENU_FONT_WIDTH);
n -= lcd_put_u8str_max_P(pstr, n);
lcd_put_wchar(':');
while (n > MENU_FONT_WIDTH) n -= lcd_put_wchar(' ');
@ -402,13 +411,13 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
void draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
ui.encoder_direction_normal();
const uint8_t labellen = utf8_strlen_P(pstr), vallen = utf8_strlen(value);
const u8g_uint_t labellen = utf8_strlen_P(pstr), vallen = utf8_strlen(value);
bool extra_row = labellen > LCD_WIDTH - 2 - vallen;
#if ENABLED(USE_BIG_EDIT_FONT)
// Use the menu font if the label won't fit on a single line
constexpr uint8_t lcd_edit_width = (LCD_PIXEL_WIDTH) / (EDIT_FONT_WIDTH);
uint8_t lcd_chr_fit, one_chr_width;
constexpr u8g_uint_t lcd_edit_width = (LCD_PIXEL_WIDTH) / (EDIT_FONT_WIDTH);
u8g_uint_t lcd_chr_fit, one_chr_width;
if (labellen <= lcd_edit_width - 1) {
if (labellen + vallen + 1 > lcd_edit_width) extra_row = true;
lcd_chr_fit = lcd_edit_width + 1;
@ -421,20 +430,17 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
ui.set_font(FONT_MENU);
}
#else
constexpr uint8_t lcd_chr_fit = LCD_WIDTH,
one_chr_width = MENU_FONT_WIDTH;
constexpr u8g_uint_t lcd_chr_fit = LCD_WIDTH,
one_chr_width = MENU_FONT_WIDTH;
#endif
// Center the label and value lines on the middle line
uint8_t baseline = extra_row ? (LCD_PIXEL_HEIGHT) / 2 - 1
: (LCD_PIXEL_HEIGHT + EDIT_FONT_ASCENT) / 2;
u8g_uint_t baseline = extra_row ? (LCD_PIXEL_HEIGHT) / 2 - 1
: (LCD_PIXEL_HEIGHT + EDIT_FONT_ASCENT) / 2;
// Assume the label is alpha-numeric (with a descender)
bool onpage = PAGE_CONTAINS(baseline - (EDIT_FONT_ASCENT - 1), baseline + EDIT_FONT_DESCENT);
if (onpage) {
lcd_moveto(0, baseline);
lcd_put_u8str_P(pstr);
}
if (onpage) lcd_put_u8str_P(0, baseline, pstr);
// If a value is included, print a colon, then print the value right-justified
if (value != nullptr) {
@ -445,23 +451,21 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
onpage = PAGE_CONTAINS(baseline - (EDIT_FONT_ASCENT - 1), baseline);
}
if (onpage) {
lcd_moveto(((lcd_chr_fit - 1) - (vallen + 1)) * one_chr_width, baseline); // Right-justified, leaving padded by spaces
lcd_put_wchar(' '); // overwrite char if value gets shorter
lcd_put_wchar(((lcd_chr_fit - 1) - (vallen + 1)) * one_chr_width, baseline, ' '); // Right-justified, padded, add a leading space
lcd_put_u8str(value);
}
}
}
inline void draw_boxed_string(const uint8_t x, const uint8_t y, PGM_P const pstr, const bool inv) {
const uint8_t len = utf8_strlen_P(pstr), bw = len * (MENU_FONT_WIDTH),
bx = x * (MENU_FONT_WIDTH), by = (y + 1) * (MENU_FONT_HEIGHT);
inline void draw_boxed_string(const u8g_uint_t x, const u8g_uint_t y, PGM_P const pstr, const bool inv) {
const u8g_uint_t len = utf8_strlen_P(pstr), bw = len * (MENU_FONT_WIDTH),
bx = x * (MENU_FONT_WIDTH), by = (y + 1) * (MENU_FONT_HEIGHT);
if (inv) {
u8g.setColorIndex(1);
u8g.drawBox(bx - 1, by - (MENU_FONT_ASCENT) + 1, bw + 2, MENU_FONT_HEIGHT - 1);
u8g.setColorIndex(0);
}
lcd_moveto(bx, by);
lcd_put_u8str_P(pstr);
lcd_put_u8str_P(bx, by, pstr);
if (inv) u8g.setColorIndex(1);
}
@ -479,8 +483,8 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
if (mark_as_selected(row, sel)) {
if (isDir) lcd_put_wchar(LCD_STR_FOLDER[0]);
constexpr uint8_t maxlen = LCD_WIDTH - 1;
const uint8_t pixw = maxlen * (MENU_FONT_WIDTH);
uint8_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), pixw);
const u8g_uint_t pixw = maxlen * (MENU_FONT_WIDTH);
u8g_uint_t n = pixw - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), pixw);
while (n > MENU_FONT_WIDTH) n -= lcd_put_wchar(' ');
}
}
@ -499,8 +503,8 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) {
// Scale the box pixels appropriately
uint8_t x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / (GRID_MAX_POINTS_X)) * (GRID_MAX_POINTS_X),
y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / (GRID_MAX_POINTS_Y)) * (GRID_MAX_POINTS_Y),
u8g_uint_t x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / (GRID_MAX_POINTS_X)) * (GRID_MAX_POINTS_X),
y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / (GRID_MAX_POINTS_Y)) * (GRID_MAX_POINTS_Y),
pixels_per_x_mesh_pnt = x_map_pixels / (GRID_MAX_POINTS_X),
pixels_per_y_mesh_pnt = y_map_pixels / (GRID_MAX_POINTS_Y),
@ -522,8 +526,8 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
// Display Mesh Point Locations
u8g.setColorIndex(1);
const uint8_t sx = x_offset + pixels_per_x_mesh_pnt / 2;
uint8_t y = y_offset + pixels_per_y_mesh_pnt / 2;
const u8g_uint_t sx = x_offset + pixels_per_x_mesh_pnt / 2;
u8g_uint_t y = y_offset + pixels_per_y_mesh_pnt / 2;
for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++, y += pixels_per_y_mesh_pnt)
if (PAGE_CONTAINS(y, y))
for (uint8_t i = 0, x = sx; i < GRID_MAX_POINTS_X; i++, x += pixels_per_x_mesh_pnt)
@ -531,10 +535,10 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
// Fill in the Specified Mesh Point
uint8_t inverted_y = GRID_MAX_POINTS_Y - y_plot - 1; // The origin is typically in the lower right corner. We need to
// invert the Y to get it to plot in the right location.
const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y - 1) - y_plot; // The origin is typically in the lower right corner. We need to
// invert the Y to get it to plot in the right location.
const uint8_t by = y_offset + inverted_y * pixels_per_y_mesh_pnt;
const u8g_uint_t by = y_offset + y_plot_inv * pixels_per_y_mesh_pnt;
if (PAGE_CONTAINS(by, by + pixels_per_y_mesh_pnt))
u8g.drawBox(
x_offset + x_plot * pixels_per_x_mesh_pnt, by,
@ -546,26 +550,22 @@ void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop
// Show X and Y positions at top of screen
u8g.setColorIndex(1);
if (PAGE_UNDER(7)) {
lcd_moveto(5, 7);
lcd_put_u8str("X:");
lcd_put_u8str(5, 7, "X:");
lcd_put_u8str(ftostr52(LOGICAL_X_POSITION(pgm_read_float(&ubl._mesh_index_to_xpos[x_plot]))));
lcd_moveto(74, 7);
lcd_put_u8str("Y:");
lcd_put_u8str(74, 7, "Y:");
lcd_put_u8str(ftostr52(LOGICAL_Y_POSITION(pgm_read_float(&ubl._mesh_index_to_ypos[y_plot]))));
}
// Print plot position
if (PAGE_CONTAINS(LCD_PIXEL_HEIGHT - (INFO_FONT_HEIGHT - 1), LCD_PIXEL_HEIGHT)) {
lcd_moveto(5, LCD_PIXEL_HEIGHT);
lcd_put_wchar('(');
lcd_put_wchar(5, LCD_PIXEL_HEIGHT, '(');
u8g.print(x_plot);
lcd_put_wchar(',');
u8g.print(y_plot);
lcd_put_wchar(')');
// Show the location value
lcd_moveto(74, LCD_PIXEL_HEIGHT);
lcd_put_u8str("Z:");
lcd_put_u8str(74, LCD_PIXEL_HEIGHT, "Z:");
if (!isnan(ubl.z_values[x_plot][y_plot]))
lcd_put_u8str(ftostr43sign(ubl.z_values[x_plot][y_plot]));
else

@ -0,0 +1,560 @@
/*********************
* flash_storage.cpp *
*********************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#include "../compat.h"
#if ENABLED(LULZBOT_TOUCH_UI)
#include "../ftdi_eve_lib/ftdi_eve_lib.h"
#include "media_file_reader.h"
#include "flash_storage.h"
// The following must be changed whenever the layout of the flash
// data is changed in a manner that would render the data invalid.
constexpr uint32_t flash_eeprom_version = 1;
/* SPI Flash Memory Map:
*
* The following offsets and sizes are specified in 4k erase units:
*
* Page Size Description
* 0 16 DATA STORAGE AREA
* 16 1 VERSIONING DATA
* 17 inf MEDIA STORAGE AREA
*
*/
#define DATA_STORAGE_SIZE_64K
using namespace FTDI::SPI;
using namespace FTDI::SPI::most_significant_byte_first;
bool UIFlashStorage::is_present = false;
#ifdef SPI_FLASH_SS
/************************** SPI Flash Chip Interface **************************/
void SPIFlash::wait_while_busy() {
uint8_t status;
safe_delay(1);
do {
spi_flash_select();
spi_write_8(READ_STATUS_1);
status = spi_read_8();
spi_flash_deselect();
safe_delay(1);
} while (status & 1);
}
void SPIFlash::erase_sector_4k(uint32_t addr) {
spi_flash_select();
spi_write_8(WRITE_ENABLE);
spi_flash_deselect();
spi_flash_select();
spi_write_8(ERASE_4K);
spi_write_24(addr);
spi_flash_deselect();
wait_while_busy();
}
void SPIFlash::erase_sector_64k(uint32_t addr) {
spi_flash_select();
spi_write_8(WRITE_ENABLE);
spi_flash_deselect();
spi_flash_select();
spi_write_8(ERASE_64K);
spi_write_24(addr);
spi_flash_deselect();
wait_while_busy();
}
void SPIFlash::spi_write_begin(uint32_t addr) {
spi_flash_select();
spi_write_8(WRITE_ENABLE);
spi_flash_deselect();
spi_flash_select();
spi_write_8(PAGE_PROGRAM);
spi_write_24(addr);
}
void SPIFlash::spi_write_end() {
spi_flash_deselect();
wait_while_busy();
}
void SPIFlash::spi_read_begin(uint32_t addr) {
spi_flash_select();
spi_write_8(READ_DATA);
spi_write_24(addr);
}
void SPIFlash::spi_read_end() {
spi_flash_deselect();
}
void SPIFlash::erase_chip() {
spi_flash_select();
spi_write_8(WRITE_ENABLE);
spi_flash_deselect();
spi_flash_select();
spi_write_8(ERASE_CHIP);
spi_flash_deselect();
wait_while_busy();
}
void SPIFlash::read_jedec_id(uint8_t &manufacturer_id, uint8_t &device_type, uint8_t &capacity) {
spi_flash_select();
spi_write_8(READ_JEDEC_ID);
manufacturer_id = spi_recv();
device_type = spi_recv();
capacity = spi_recv();
spi_flash_deselect ();
}
/* This function writes "size" bytes from "data" starting at addr, while properly
* taking into account the special case of writing across a 256 byte page boundary.
* Returns the addr directly after the write.
*/
uint32_t SPIFlash::write(uint32_t addr, const void *_data, size_t size) {
const uint8_t *data = (const uint8_t*) _data;
while (size) {
const uint32_t page_start = addr & 0xFFFF00ul;
const uint32_t page_end = page_start + 256;
const uint32_t write_size = min(page_end - addr, size);
spi_write_begin(addr);
spi_write_bulk<ram_write>(data, write_size);
spi_write_end();
addr += write_size;
size -= write_size;
data += write_size;
}
return addr;
}
uint32_t SPIFlash::read(uint32_t addr, void *data, size_t size) {
spi_read_begin(addr);
spi_read_bulk(data, size);
spi_read_end();
return addr + size;
}
/********************************** UTILITY ROUTINES *********************************/
bool UIFlashStorage::check_known_device() {
uint8_t manufacturer_id, device_type, capacity;
read_jedec_id(manufacturer_id, device_type, capacity);
const bool is_known =
((manufacturer_id == 0xEF) && (device_type == 0x40) && (capacity == 0x15)) || // unknown
((manufacturer_id == 0x01) && (device_type == 0x40) && (capacity == 0x15)) || // Cypress S25FL116K
((manufacturer_id == 0xEF) && (device_type == 0x14) && (capacity == 0x15)) || // Winbond W25Q16JV
((manufacturer_id == 0x1F) && (device_type == 0x86) && (capacity == 0x01)) ; // Adesto AT255F161
if (!is_known) {
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Unable to locate supported SPI Flash Memory.");
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" Manufacturer ID, got: ", manufacturer_id);
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" Device Type , got: ", device_type);
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" Capacity , got: ", capacity);
}
return is_known;
}
void UIFlashStorage::initialize() {
for(uint8_t i = 0; i < 10; i++) {
if (check_known_device()) {
is_present = true;
break;
}
safe_delay(1000);
}
}
/**************************** DATA STORAGE AREA (first 4K or 64k) ********************/
#ifdef DATA_STORAGE_SIZE_64K
constexpr uint32_t data_storage_area_size = 64 * 1024; // Large erase unit
#else
constexpr uint32_t data_storage_area_size = 4 * 1024; // Small erase unit
#endif
/* In order to provide some degree of wear leveling, each data write to the
* SPI Flash chip is appended to data that was already written before, until
* the data storage area is completely filled. New data is written preceeded
* with a 32-bit delimiter 'LULZ', so that we can distinguish written and
* unwritten data:
*
* 'LULZ' <--- 1st record delimiter
* <data_byte>
* <data_byte>
* <data_byte>
* 'LULZ' <--- 2nd record delimiter
* <data_byte>
* <data_byte>
* <data_byte>
* ...
* 'LULZ' <--- Last record delimiter
* <data_byte>
* <data_byte>
* <data_byte>
* 0xFF <--- Start of free space
* 0xFF
* ...
*
* This function walks down the data storage area, verifying that the
* delimiters are either 'LULZ' or 0xFFFFFFFF. In the case that an invalid
* delimiter is found, this function returns -1, indicating that the Flash
* data is invalid (this will happen if the block_size changed with respect
* to earlier firmware). Otherwise, it returns the offset of the last
* valid delimiter 'LULZ', indicating the most recently written data.
*/
int32_t UIFlashStorage::get_config_read_offset(uint32_t block_size) {
uint16_t stride = 4 + block_size;
int32_t read_offset = -1;
for(uint32_t offset = 0; offset < (data_storage_area_size - stride); offset += stride) {
uint32_t delim;
spi_read_begin(offset);
spi_read_bulk (&delim, sizeof(delim));
spi_read_end();
switch (delim) {
case 0xFFFFFFFFul: return read_offset;
case delimiter: read_offset = offset; break;
default:
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR("Invalid delimiter in Flash: ", delim);
return -1;
}
}
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("No LULZ delimiter found.");
return -1;
}
/* This function returns the offset at which new data should be
* appended, or -1 if the Flash needs to be erased */
int32_t UIFlashStorage::get_config_write_offset(uint32_t block_size) {
int32_t read_offset = get_config_read_offset(block_size);
if (read_offset == -1) return -1; // The SPI flash is invalid
int32_t write_offset = read_offset + 4 + block_size;
if ((write_offset + 4 + block_size) > data_storage_area_size) {
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Not enough free space in Flash.");
return -1; // Not enough free space
}
return write_offset;
}
bool UIFlashStorage::verify_config_data(const void *data, size_t size) {
if (!is_present) return false;
int32_t read_addr = get_config_read_offset(size);
if (read_addr == -1) return false;
uint32_t delim;
spi_read_begin(read_addr);
spi_read_bulk (&delim, sizeof(delim));
bool ok = spi_verify_bulk(data,size);
spi_read_end();
return ok && delim == delimiter;
}
bool UIFlashStorage::read_config_data(void *data, size_t size) {
if (!is_present) return false;
int32_t read_addr = get_config_read_offset(size);
if (read_addr == -1) return false;
uint32_t delim;
spi_read_begin(read_addr);
spi_read_bulk (&delim, sizeof(delim));
spi_read_bulk (data, size);
spi_read_end();
return delim == delimiter;
}
void UIFlashStorage::write_config_data(const void *data, size_t size) {
if (!is_present) {
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("SPI Flash chip not present. Not saving UI settings.");
return;
}
// Since Flash storage has a limited number of write cycles,
// make sure that the data is different before rewriting.
if (verify_config_data(data, size)) {
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("UI settings already written, skipping write.");
return;
}
int16_t write_addr = get_config_write_offset(size);
if (write_addr == -1) {
SERIAL_ECHO_START();
SERIAL_ECHOPGM("Erasing UI settings from SPI Flash... ");
#ifdef DATA_STORAGE_SIZE_64K
erase_sector_64k(0);
#else
erase_sector_4k(0);
#endif
write_addr = 0;
SERIAL_ECHOLNPGM("DONE");
}
SERIAL_ECHO_START();
SERIAL_ECHOPAIR("Writing UI settings to SPI Flash (offset ", write_addr);
SERIAL_ECHOPGM(")...");
const uint32_t delim = delimiter;
write_addr = write(write_addr, &delim, sizeof(delim));
write_addr = write(write_addr, data, size);
SERIAL_ECHOLNPGM("DONE");
}
/************************** VERSIONING INFO AREA ************************/
/* The version info area follows the data storage area. If the version
* is incorrect, the data on the chip is invalid and format_flash should
* be called.
*/
typedef struct {
uint32_t magic;
uint32_t version;
} flash_version_info;
constexpr uint32_t version_info_addr = data_storage_area_size;
constexpr uint32_t version_info_size = 4 * 1024; // Small erase unit
bool UIFlashStorage::is_valid() {
flash_version_info info;
spi_read_begin(version_info_addr);
spi_read_bulk (&info, sizeof(flash_version_info));
spi_read_end();
return info.magic == delimiter && info.version == flash_eeprom_version;
}
void UIFlashStorage::write_version_info() {
flash_version_info info;
info.magic = delimiter;
info.version = flash_eeprom_version;
spi_write_begin(version_info_addr);
spi_write_bulk<ram_write>(&info, sizeof(flash_version_info));
spi_write_end();
}
/**************************** MEDIA STORAGE AREA *****************************/
/* The media storage area follows the versioning info area. It consists
* of a file index followed by the data for one or more media files.
*
* The file index consists of an array of 32-bit file sizes. If a file
* is not present, the file's size will be set to 0xFFFFFFFF
*/
constexpr uint32_t media_storage_addr = version_info_addr + version_info_size;
constexpr uint8_t media_storage_slots = 4;
void UIFlashStorage::format_flash() {
SERIAL_ECHO_START(); SERIAL_ECHOPGM("Erasing SPI Flash...");
SPIFlash::erase_chip();
SERIAL_ECHOLNPGM("DONE");
write_version_info();
}
uint32_t UIFlashStorage::get_media_file_start(uint8_t slot) {
uint32_t addr = media_storage_addr + sizeof(uint32_t) * media_storage_slots;
spi_read_begin(media_storage_addr);
for(uint8_t i = 0; i < slot; i++) {
addr += spi_read_32();
}
spi_read_end();
return addr;
}
void UIFlashStorage::set_media_file_size(uint8_t slot, uint32_t size) {
spi_write_begin(media_storage_addr + sizeof(uint32_t) * slot);
spi_write_32(size);
spi_write_end();
}
uint32_t UIFlashStorage::get_media_file_size(uint8_t slot) {
spi_read_begin(media_storage_addr + sizeof(uint32_t) * slot);
uint32_t size = spi_read_32();
spi_read_end();
return size;
}
/* Writes a media file from the SD card/USB flash drive into a slot on the SPI Flash. Media
* files must be written sequentially following by a chip erase and it is not possible to
* overwrite files. */
UIFlashStorage::error_t UIFlashStorage::write_media_file(progmem_str filename, uint8_t slot) {
#if ENABLED(SDSUPPORT)
uint32_t addr;
uint8_t buff[write_page_size];
strcpy_P( (char*) buff, (const char*) filename);
MediaFileReader reader;
if (!reader.open((char*) buff)) {
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Unable to find media file");
return FILE_NOT_FOUND;
}
if (get_media_file_size(slot) != 0xFFFFFFFFUL) {
SERIAL_ECHO_START(); SERIAL_ECHOLNPGM("Media file already exists");
return WOULD_OVERWRITE;
}
SERIAL_ECHO_START(); SERIAL_ECHOPGM("Writing SPI Flash...");
set_media_file_size(slot, reader.size());
addr = get_media_file_start(slot);
// Write out the file itself
for(;;) {
const int16_t nBytes = reader.read(buff, write_page_size);
if (nBytes == -1) {
SERIAL_ECHOLNPGM("Failed to read from file");
return READ_ERROR;
}
addr = write(addr, buff, nBytes);
if (nBytes != write_page_size)
break;
#if ENABLED(EXTENSIBLE_UI)
ExtUI::yield();
#endif
}
SERIAL_ECHOLNPGM("DONE");
SERIAL_ECHO_START(); SERIAL_ECHOPGM("Verifying SPI Flash...");
bool verifyOk = true;
// Verify the file index
if (get_media_file_start(slot+1) != (get_media_file_start(slot) + reader.size())) {
SERIAL_ECHOLNPGM("File index verification failed. ");
verifyOk = false;
}
// Verify the file itself
addr = get_media_file_start(slot);
reader.rewind();
while (verifyOk) {
const int16_t nBytes = reader.read(buff, write_page_size);
if (nBytes == -1) {
SERIAL_ECHOPGM("Failed to read from file");
verifyOk = false;
break;
}
spi_read_begin(addr);
if (!spi_verify_bulk(buff, nBytes)) {
verifyOk = false;
spi_read_end();
break;
}
spi_read_end();
addr += nBytes;
if (nBytes != write_page_size) break;
#if ENABLED(EXTENSIBLE_UI)
ExtUI::yield();
#endif
};
if (verifyOk) {
SERIAL_ECHOLNPGM("DONE");
return SUCCESS;
} else {
SERIAL_ECHOLNPGM("FAIL");
return VERIFY_ERROR;
}
#else
return VERIFY_ERROR;
#endif // ENABLED(SDSUPPORT)
}
bool UIFlashStorage::BootMediaReader::isAvailable(uint32_t slot) {
if (!is_present) return false;
bytes_remaining = get_media_file_size(slot);
if (bytes_remaining != 0xFFFFFFFFUL) {
SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR("Boot media file size:", bytes_remaining);
addr = get_media_file_start(slot);
return true;
} else {
return false;
}
}
int16_t UIFlashStorage::BootMediaReader::read(void *data, const size_t size) {
if (bytes_remaining == 0xFFFFFFFFUL) return -1;
if (size > bytes_remaining)
return read(data, bytes_remaining);
if (size > 0) {
spi_read_begin(addr);
spi_read_bulk(data, size);
spi_read_end();
addr += size;
bytes_remaining -= size;
}
return size;
}
int16_t UIFlashStorage::BootMediaReader::read(void *obj, void *data, const size_t size) {
return reinterpret_cast<UIFlashStorage::BootMediaReader*>(obj)->read(data, size);
}
#else
void UIFlashStorage::initialize() {}
bool UIFlashStorage::is_valid() {return true;}
void UIFlashStorage::write_config_data(const void *, size_t) {}
bool UIFlashStorage::verify_config_data(const void *, size_t) {return false;}
bool UIFlashStorage::read_config_data(void *, size_t ) {return false;}
UIFlashStorage::error_t UIFlashStorage::write_media_file(progmem_str, uint8_t) {return FILE_NOT_FOUND;}
void UIFlashStorage::format_flash() {}
bool UIFlashStorage::BootMediaReader::isAvailable(uint32_t) {return false;}
int16_t UIFlashStorage::BootMediaReader::read(void *, const size_t) {return -1;}
int16_t UIFlashStorage::BootMediaReader::read(void *, void *, const size_t) {return -1;}
#endif // SPI_FLASH_SS
#endif // LULZBOT_TOUCH_UI

@ -0,0 +1,106 @@
/*******************
* flash_storage.h *
*******************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
class SPIFlash {
public:
static constexpr uint32_t erase_unit_size = 4 * 1024; // Minimum erase unit
static constexpr uint32_t write_page_size = 256; // Minimum page write unit
enum {
READ_STATUS_1 = 0x05,
READ_STATUS_2 = 0x35,
READ_STATUS_3 = 0x33,
WRITE_ENABLE = 0x06,
WRITE_DISABLE = 0x04,
READ_ID = 0x90,
READ_JEDEC_ID = 0x9F,
READ_DATA = 0x03,
PAGE_PROGRAM = 0x02,
ERASE_4K = 0x20,
ERASE_64K = 0xD8,
ERASE_CHIP = 0xC7
};
static void wait_while_busy();
static void erase_sector_4k(uint32_t addr);
static void erase_sector_64k(uint32_t addr);
static void erase_chip ();
static void read_jedec_id(uint8_t &manufacturer_id, uint8_t &device_type, uint8_t &capacity);
static void spi_read_begin(uint32_t addr);
static void spi_read_end();
static void spi_write_begin(uint32_t addr);
static void spi_write_end();
static uint32_t write(uint32_t addr, const void *data, size_t size);
static uint32_t read(uint32_t addr, void *data, size_t size);
};
class UIFlashStorage : private SPIFlash {
private:
static bool is_present;
static int32_t get_config_read_offset(uint32_t block_size);
static int32_t get_config_write_offset(uint32_t block_size);
static uint32_t get_media_file_start(uint8_t slot);
static void set_media_file_size(uint8_t slot, uint32_t size);
static uint32_t get_media_file_size(uint8_t slot);
static constexpr uint32_t delimiter = 0x4C554C5A; // 'LULZ'
public:
enum error_t {
SUCCESS,
FILE_NOT_FOUND,
READ_ERROR,
VERIFY_ERROR,
WOULD_OVERWRITE
};
static void initialize ();
static void format_flash ();
static bool check_known_device();
static bool is_valid ();
static void write_version_info();
static void write_config_data (const void *data, size_t size);
static bool verify_config_data (const void *data, size_t size);
static bool read_config_data (void *data, size_t size);
static error_t write_media_file (progmem_str filename, uint8_t slot = 0);
class BootMediaReader;
};
class UIFlashStorage::BootMediaReader {
private:
uint32_t addr;
uint32_t bytes_remaining;
public:
bool isAvailable(uint32_t slot = 0);
int16_t read(void *buffer, size_t const size);
static int16_t read(void *obj, void *buffer, const size_t size);
};

@ -0,0 +1,63 @@
/************************
* media_filereader.cpp *
************************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#include "../compat.h"
#if ENABLED(LULZBOT_TOUCH_UI)
#include "media_file_reader.h"
#if ENABLED(SDSUPPORT)
bool MediaFileReader::open(const char* filename) {
card.init(SPI_SPEED, SDSS);
volume.init(&card);
root.openRoot(&volume);
return file.open(&root, filename, O_READ);
}
int16_t MediaFileReader::read(void *buff, size_t bytes) {
return file.read(buff, bytes);
}
void MediaFileReader::close() {
file.close();
}
uint32_t MediaFileReader::size() {
return file.fileSize();
}
void MediaFileReader::rewind() {
file.rewind();
}
int16_t MediaFileReader::read(void *obj, void *buff, size_t bytes) {
return reinterpret_cast<MediaFileReader*>(obj)->read(buff, bytes);
}
#else
bool MediaFileReader::open(const char*) {return -1;}
int16_t MediaFileReader::read(void *, size_t) {return 0;}
void MediaFileReader::close() {}
uint32_t MediaFileReader::size() {return 0;}
void MediaFileReader::rewind() {}
int16_t MediaFileReader::read(void *, void *, size_t) {return 0;}
#endif
#endif // LULZBOT_TOUCH_UI

@ -0,0 +1,48 @@
/**********************
* media_filereader.h *
**********************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#pragma once
#include "../../../../../inc/MarlinConfigPre.h"
#if ENABLED(SDSUPPORT)
#include "../../../../../sd/SdFile.h"
#include "../../../../../sd/cardreader.h"
#endif
class MediaFileReader {
private:
#if ENABLED(SDSUPPORT)
Sd2Card card;
SdVolume volume;
SdFile root, file;
#endif
public:
bool open(const char* filename);
int16_t read(void *buff, size_t bytes);
uint32_t size();
void rewind();
void close();
static int16_t read(void *obj, void *buff, size_t bytes);
};

@ -0,0 +1,53 @@
/************
* compat.h *
************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
/**
* This following provides compatibility whether compiling
* as a part of Marlin or outside it
*/
#if defined __has_include
#if __has_include ("../../ui_api.h")
#include "../../ui_api.h"
#endif
#else
#include "../../ui_api.h"
#endif
#ifdef __MARLIN_FIRMWARE__
// __MARLIN_FIRMWARE__ exists when compiled within Marlin.
#include "pin_mappings.h"
#else
// Messages that are declared in Marlin
#define WELCOME_MSG "Printer Ready"
#define MSG_MEDIA_INSERTED "Media Inserted"
#define MSG_MEDIA_REMOVED "Media Removed"
namespace UI {
static inline uint32_t safe_millis() {return millis();};
static inline void yield() {};
};
#endif
class __FlashStringHelper;
typedef const __FlashStringHelper *progmem_str;

@ -0,0 +1,97 @@
/************
* config.h *
************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
#include "compat.h"
// Define the display board used (see "ftdi_eve_boards.h" for definitions)
//#define LCD_FTDI_VM800B35A // FTDI 3.5" 320x240 with FT800
//#define LCD_4DSYSTEMS_4DLCD_FT843 // 4D Systems 4.3" 480x272
//#define LCD_HAOYU_FT800CB // Haoyu with 4.3" or 5" 480x272
//#define LCD_HAOYU_FT810CB // Haoyu with 5" 800x480
//#define LCD_ALEPHOBJECTS_CLCD_UI // Aleph Objects Color LCD User Interface
// Leave the following commented out to use a board's default resolution.
// If you have changed the LCD panel, you may override the resolution
// below (see "ftdi_eve_resolutions.h" for definitions):
//#define TOUCH_UI_320x240
//#define TOUCH_UI_480x272
//#define TOUCH_UI_800x480
// Define the printer interface or pins used (see "ui_pin_mappings.h" for definitions):
//#define CR10_TFT_PINMAP
//#define AO_EXP1_DEPRECATED_PINMAP // UltraLCD EXP1 connector, old AlephObject's wiring
//#define AO_EXP1_PINMAP // UltraLCD EXP1 connector, new AlephObject's wiring
//#define AO_EXP2_PINMAP // UltraLCD EXP2 connector, new AlephObject's wiring
//#define OTHER_PIN_LAYOUT
// Otherwise. Define all the pins manually:
#ifdef OTHER_PIN_LAYOUT
// Select interfacing pins, the following pin specifiers are supported:
//
// ARDUINO_DIGITAL_1 - Arduino pin via digitalWrite/digitalRead
// AVR_A1 - Fast AVR port access via PORTA/PINA/DDRA
// 1 - When compiling Marlin, use Marlin pin IDs.
// The pins for CS and MOD_RESET (PD) must be chosen.
#define CLCD_MOD_RESET 9
#define CLCD_SPI_CS 10
// If using software SPI, specify pins for SCLK, MOSI, MISO
//#define CLCD_USE_SOFT_SPI
#ifdef CLCD_USE_SOFT_SPI
#define CLCD_SOFT_SPI_MOSI 11
#define CLCD_SOFT_SPI_MISO 12
#define CLCD_SOFT_SPI_SCLK 13
#endif
#endif
// Defines how to orient the display. An inverted (i.e. upside-down) display
// is supported on the FT800. The FT810 or better also support a portrait
// and mirrored orientation.
//#define TOUCH_UI_INVERTED
//#define TOUCH_UI_PORTRAIT
//#define TOUCH_UI_MIRRORED
// Use a numeric passcode for "Parental lock".
// This is a recommended for smaller displays.
//#define TOUCH_UI_PASSCODE
// The timeout (in ms) to return to the status screen from sub-menus
//#define LCD_TIMEOUT_TO_STATUS 15000
// Enable this to debug the event framework
//#define UI_FRAMEWORK_DEBUG
// Enable the developer's menu and screens
//#define DEVELOPER_SCREENS
// Maximum feed rate for manual extrusion (mm/s)
//#define MAX_MANUAL_FEEDRATE 240
// Sets the SPI speed in Hz
#define SPI_FREQUENCY 8000000 >> SPI_SPEED

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

@ -0,0 +1,28 @@
FTDI EVE Library
----------------
The FTDI EVE Library is a fully open-source library and UI framework for the FTDI
FT800 and FT810 graphics processor.
Although the library has been developed within Lulzbot for providing a user interface
for Marlin, the library has been written so that it can be used in any Arduino sketch.
The library is split into two parts. The "basic" API provides a shallow interface to
the underlying FTDI hardware and command FIFO and provides low-level access to the
hardware as closely as possible to the API described in the FTDI Programmer's Guide.
The "extended" API builds on top of the "basic" API to provide a GUI framework for
handling common challenges in building a usable GUI. The GUI framework provides the
following features:
- Macros for a resolution-independent placement of widgets based on a grid.
- Class-based UI screens, with press and unpress touch events, as well as touch repeat.
- Event loop with button debouncing and button push visual and auditory feedback.
- Easy screen-to-screen navigation including a navigation stack for going backwards.
- Visual feedback for disabled vs enabled buttons, and custom button styles.
- A sound player class for playing individual notes or complete sound sequences.
- Display list caching, for storing static background elements of a screen in RAM_G.
See the "examples" folder for Arduino sketches. Modify the "src/config.h" file in
each to suit your particular setup. The "sample_configs" contain sample configuration
files for running the sketches on our 3D printer boards.

@ -0,0 +1,183 @@
/************
* boards.h *
************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#pragma once
#define HAS_RESOLUTION (defined(TOUCH_UI_320x240) || defined(TOUCH_UI_480x272) || defined(TOUCH_UI_800x480))
#define IS_FT800 \
constexpr uint16_t ftdi_chip = 800; \
using namespace FTDI_FT800; \
namespace DL { \
using namespace FTDI_FT800_DL; \
} \
typedef ft800_memory_map ftdi_memory_map; \
typedef ft800_registers ftdi_registers;
#define IS_FT810 \
constexpr uint16_t ftdi_chip = 810; \
using namespace FTDI_FT810; \
namespace DL { \
using namespace FTDI_FT800_DL; \
using namespace FTDI_FT810_DL; \
} \
typedef ft810_memory_map ftdi_memory_map; \
typedef ft810_registers ftdi_registers;
#ifdef LCD_FTDI_VM800B35A
#if !HAS_RESOLUTION
#define TOUCH_UI_320x240
#endif
#ifndef FTDI_API_LEVEL
#define FTDI_API_LEVEL 800
#endif
namespace FTDI {
IS_FT800
constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
constexpr bool GPIO_0_Audio_Enable = false; /* 1 = does use GPIO00 for amplifier control, 0 = not in use for Audio */
constexpr bool GPIO_1_Audio_Shutdown = true; /* 1 = does use GPIO01 for amplifier control, 0 = not in use for Audio */
constexpr uint8_t Swizzle = 2;
constexpr uint8_t CSpread = 1;
constexpr uint16_t touch_threshold = 1200; /* touch-sensitivity */
}
/*
* Settings for the Haoyu Electronics, 4.3" Graphical LCD Touchscreen, 480x272, SPI, FT800 (FT800CB-HY43B)
* Haoyu Electronics, 5" Graphical LCD Touchscreen, 480x272, SPI, FT800 (FT800CB-HY50B)
*
* http://www.hotmcu.com/43-graphical-lcd-touchscreen-480x272-spi-ft800-p-111.html?cPath=6_16
* http://www.hotmcu.com/5-graphical-lcd-touchscreen-480x272-spi-ft800-p-124.html?cPath=6_16
*
* Datasheet:
*
* http://www.hantronix.com/files/data/1278363262430-3.pdf
* http://www.haoyuelectronics.com/Attachment/HY43-LCD/LCD%20DataSheet.pdf
* http://www.haoyuelectronics.com/Attachment/HY5-LCD-HD/KD50G21-40NT-A1.pdf
*
*/
#elif defined(LCD_HAOYU_FT800CB)
#if !HAS_RESOLUTION
#define TOUCH_UI_480x272
#endif
#ifndef FTDI_API_LEVEL
#define FTDI_API_LEVEL 800
#endif
namespace FTDI {
IS_FT800
constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
constexpr bool GPIO_0_Audio_Enable = false;
constexpr bool GPIO_1_Audio_Shutdown = false;
constexpr uint8_t Swizzle = 0;
constexpr uint8_t CSpread = 1;
constexpr uint16_t touch_threshold = 2000; /* touch-sensitivity */
}
/*
* Settings for the Haoyu Electronics, 5" Graphical LCD Touchscreen, 800x480, SPI, FT810
*
* http://www.hotmcu.com/5-graphical-lcd-touchscreen-800x480-spi-ft810-p-286.html
*
* Datasheet:
*
* http://www.haoyuelectronics.com/Attachment/HY5-LCD-HD/KD50G21-40NT-A1.pdf
*
*/
#elif defined(LCD_HAOYU_FT810CB)
#if !HAS_RESOLUTION
#define TOUCH_UI_800x480
#endif
#ifndef FTDI_API_LEVEL
#define FTDI_API_LEVEL 810
#endif
namespace FTDI {
IS_FT810
constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
constexpr bool GPIO_0_Audio_Enable = false;
constexpr bool GPIO_1_Audio_Shutdown = false;
constexpr uint8_t Swizzle = 0;
constexpr uint8_t CSpread = 1;
constexpr uint16_t touch_threshold = 2000; /* touch-sensitivity */
}
/*
* Settings for the 4D Systems, 4.3" Embedded SPI Display 480x272, SPI, FT800 (4DLCD-FT843)
*
* http://www.4dsystems.com.au/product/4DLCD_FT843/
*
* Datasheet:
*
* http://www.4dsystems.com.au/productpages/4DLCD-FT843/downloads/FT843-4.3-Display_datasheet_R_1_2.pdf
*
*/
#elif defined(LCD_4DSYSTEMS_4DLCD_FT843)
#if !HAS_RESOLUTION
#define TOUCH_UI_480x272
#endif
#ifndef FTDI_API_LEVEL
#define FTDI_API_LEVEL 800
#endif
namespace FTDI {
IS_FT800
constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
constexpr bool GPIO_0_Audio_Enable = false;
constexpr bool GPIO_1_Audio_Shutdown = true;
constexpr uint8_t Swizzle = 0;
constexpr uint8_t CSpread = 1;
constexpr uint16_t touch_threshold = 1200; /* touch-sensitivity */
}
/*
* Settings for the Aleph Objects Color LCD User Interface
*
* https://code.alephobjects.com/source/aotctl/
*
* Datasheet:
*
* http://www.hantronix.com/files/data/s1501799605s500-gh7.pdf
*
*/
#elif defined(LCD_ALEPHOBJECTS_CLCD_UI)
#if !HAS_RESOLUTION
#define TOUCH_UI_800x480
#endif
#ifndef FTDI_API_LEVEL
#define FTDI_API_LEVEL 810
#endif
namespace FTDI {
IS_FT810
constexpr bool Use_Crystal = false; // 0 = use internal oscillator, 1 = module has a crystal populated
constexpr bool GPIO_0_Audio_Enable = true; // The AO CLCD uses GPIO0 to enable audio
constexpr bool GPIO_1_Audio_Shutdown = false;
constexpr uint8_t Swizzle = 0;
constexpr uint8_t CSpread = 0;
constexpr uint16_t touch_threshold = 2000; /* touch-sensitivity */
}
#else
#error Unknown or no LULZBOT_TOUCH_UI board specified. To add a new board, modify "ftdi_eve_boards.h"
#endif

@ -0,0 +1,258 @@
/****************
* commands.cpp *
****************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
/****************************************************************************
* FUNCTION MAP *
* *
* SPI and FT800/810 Commands *
* *
* CLCD::spi_select() Set CS line to 0 *
* CLCD::spi_deselect() Set CS Line to 1 *
* CLCD::reset() Toggle FT800/810 Power Down Line 50 ms *
* CLCD::spi_init() Configure I/O Lines for SPI *
* CLCD::spi_transfer() Send/Receive 1 SPI Byte *
* CLCD::init() Set FT800/810 Registers *
* CLCD::enable() Turn On FT800/810 PCLK *
* CLCD::disable() Turn Off FT8880/810 PCLK *
* CLCD::set_backlight() Set LCD Backlight Level *
* *
* MEMORY READ FUNCTIONS *
* *
* CLCD::mem_read_addr() Send 32-Bit Address *
* CLCD::mem_read_8() Read 1 Byte *
* CLCD::mem_read_16() Read 2 Bytes *
* CLCD::mem_read_32() Read 4 Bytes *
* *
* MEMORY WRITE FUNCTIONS *
* *
* CLCD::mem_write_addr() Send 24-Bit Address *
* CLCD::mem_write_8() Write 1 Byte *
* CLCD::mem_write_16() Write 2 Bytes *
* CLCD::mem_write_32() Write 4 Bytes *
* *
* HOST COMMAND FUNCTION *
* *
* CLCD::host_cmd() Send 24-Bit Host Command *
* *
* COMMAND BUFFER FUNCTIONS *
* *
* CLCD::cmd() Send 32-Bit Value(4 Bytes)CMD Buffer *
* CLCD::cmd() Send Data Structure with 32-Bit Cmd *
* CLCD::str() Send Text String in 32-Bit Multiples *
* *
* FT800/810 GRAPHIC COMMANDS *
* *
* class CLCD:CommandFifo {} Class to control Cmd FIFO *
* CommandFifo::start() Wait for CP finish - Set FIFO Ptr *
* CommandFifo::execute() Set REG_CMD_WRITE and start CP *
* CommandFifo::reset() Set Cmd Buffer Pointers to 0 *
*
* CommandFifo::fgcolor Set Graphic Item Foreground Color *
* CommandFifo::bgcolor Set Graphic Item Background Color *
* CommandFifo::begin() Begin Drawing a Primative *
* CommandFifo::mem_copy() Copy a Block of Memory *
* CommandFifo::append() Append Commands to Current DL *
* CommandFifo::gradient_color() Set 3D Button Highlight Color *
* CommandFifo::button() Draw Button with Bulk Write *
* CommandFifo::text() Draw Text with Bulk Write *
*****************************************************************************/
/**************************************************
* RAM_G Graphics RAM Allocation *
* *
* Address Use *
* *
* 8000 Extruder Bitmap *
* 8100 Bed Heat Bitmap *
* 8200 Fan Bitmap *
* 8300 Thumb Drive Symbol Bitmap *
* 35000 Static DL Space (FT800) *
* F5000 Static DL Space (FT810) *
**************************************************/
#pragma once
typedef const __FlashStringHelper *progmem_str;
class UIStorage;
class CLCD {
friend class UIStorage;
public:
typedef FTDI::ftdi_registers REG;
typedef FTDI::ftdi_memory_map MAP;
static void spi_write_addr (uint32_t reg_address);
static void spi_read_addr (uint32_t reg_address);
static uint8_t mem_read_8 (uint32_t reg_address);
static uint16_t mem_read_16 (uint32_t reg_address);
static uint32_t mem_read_32 (uint32_t reg_address);
static void mem_read_bulk (uint32_t reg_address, uint8_t *data, uint16_t len);
static void mem_write_8 (uint32_t reg_address, uint8_t w_data);
static void mem_write_16 (uint32_t reg_address, uint16_t w_data);
static void mem_write_32 (uint32_t reg_address, uint32_t w_data);
static void mem_write_bulk (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0);
static void mem_write_pgm (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0);
static void mem_write_bulk (uint32_t reg_address, progmem_str str, uint16_t len, uint8_t padding = 0);
static void mem_write_xbm (uint32_t reg_address, progmem_str str, uint16_t len, uint8_t padding = 0);
public:
class CommandFifo;
class FontMetrics;
static void init (void);
static void default_touch_transform (void);
static void default_display_orientation (void);
static void turn_on_backlight (void);
static void enable (void);
static void disable (void);
static void set_brightness (uint8_t brightness);
static uint8_t get_brightness();
static void host_cmd (unsigned char host_command, unsigned char byte2);
static void get_font_metrics (uint8_t font, struct FontMetrics &fm);
static uint16_t get_text_width(const uint8_t font, const char *str);
static uint16_t get_text_width_P(const uint8_t font, const char *str);
static uint8_t get_tag () {return mem_read_8(REG::TOUCH_TAG);}
static bool is_touching () {return (mem_read_32(REG::TOUCH_DIRECT_XY) & 0x80000000) == 0;}
static uint8_t get_tracker (uint16_t &value) {
uint32_t tracker = mem_read_32(REG::TRACKER);
value = tracker >> 16;
return tracker & 0xFF;
}
};
/*************************** FT800/810 Font Metrics ****************************/
class CLCD::FontMetrics {
public:
uint8_t char_widths[128];
uint32_t format;
uint32_t stride;
uint32_t width;
uint32_t height;
uint32_t ptr;
FontMetrics(uint8_t font) {load(font);}
void load(uint8_t font);
// Returns width of string, up to a maximum of n characters.
uint16_t get_text_width(const char *str, size_t n = SIZE_MAX) const;
uint16_t get_text_width_P(const char *str, size_t n = SIZE_MAX) const;
};
/******************* FT800/810 Graphic Commands *********************************/
class CLCD::CommandFifo {
protected:
#if FTDI_API_LEVEL >= 810
uint32_t getRegCmdBSpace();
#else
static uint32_t command_write_ptr;
template <class T> bool _write_unaligned(T data, uint16_t len);
#endif
void start(void);
public:
template <class T> bool write(T data, uint16_t len);
public:
CommandFifo() {start();}
static void reset (void);
static bool is_processing();
static bool has_fault();
void execute(void);
void cmd(uint32_t cmd32);
void cmd(void* data, uint16_t len);
void dlstart() {cmd(FTDI::CMD_DLSTART);}
void swap() {cmd(FTDI::CMD_SWAP);}
void coldstart() {cmd(FTDI::CMD_COLDSTART);}
void screensaver() {cmd(FTDI::CMD_SCREENSAVER);}
void stop() {cmd(FTDI::CMD_STOP);}
void loadidentity() {cmd(FTDI::CMD_LOADIDENTITY);}
void setmatrix() {cmd(FTDI::CMD_SETMATRIX);}
void fgcolor (uint32_t rgb);
void bgcolor (uint32_t rgb);
void gradcolor (uint32_t rgb);
void track (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t tag);
void clock (int16_t x, int16_t y, int16_t r, uint16_t options, int16_t h, int16_t m, int16_t s, int16_t ms);
void gauge (int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t major, uint16_t minor, uint16_t val, uint16_t range);
void dial (int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t val);
void slider (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range);
void progress (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range);
void scrollbar (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t size, uint16_t range);
void number (int16_t x, int16_t y, int16_t font, uint16_t options, int32_t n);
void spinner (int16_t x, int16_t y, uint16_t style, uint16_t scale);
void sketch (int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t ptr, uint16_t format);
void gradient (int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1);
void snapshot (uint32_t ptr);
void loadimage (uint32_t ptr, uint32_t options);
void getprops (uint32_t ptr, uint32_t width, uint32_t height);
void scale (int32_t sx, int32_t sy);
void rotate (int32_t a);
void translate (int32_t tx, int32_t ty);
#if FTDI_API_LEVEL >= 810
void setbase (uint8_t base);
void setrotate (uint8_t rotation);
void setbitmap (uint32_t ptr, uint16_t fmt, uint16_t w, uint16_t h);
void snapshot2 (uint32_t fmt, uint32_t ptr, int16_t x, int16_t y, uint16_t w, uint16_t h);
void mediafifo (uint32_t ptr, uint32_t size);
void playvideo (uint32_t options);
void videostart();
void videoframe(uint32_t dst, uint32_t ptr);
#endif
// All the following must be followed by str()
void text (int16_t x, int16_t y, int16_t font, uint16_t options);
void button (int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t option);
void toggle (int16_t x, int16_t y, int16_t w, int16_t font, uint16_t options, bool state);
void keys (int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t options);
// Sends the string portion of text, button, toggle and keys.
void str (const char * data);
void str (progmem_str data);
void memzero (uint32_t ptr, uint32_t size);
void memset (uint32_t ptr, uint32_t value, uint32_t size);
void memcpy (uint32_t dst, uint32_t src, uint32_t size);
void memcrc (uint32_t ptr, uint32_t num, uint32_t result);
void memwrite (uint32_t ptr, uint32_t value);
void inflate (uint32_t ptr);
void getptr (uint32_t result);
void append (uint32_t ptr, uint32_t size);
};

@ -0,0 +1,411 @@
/***************
* constants.h *
***************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
/****************************************************************************
* This header defines constants and commands for the FTDI FT810 LCD Driver *
* chip. *
****************************************************************************/
#pragma once
// OPTIONS
namespace FTDI {
constexpr uint16_t OPT_3D = 0x0000;
constexpr uint16_t OPT_RGB565 = 0x0000;
constexpr uint16_t OPT_MONO = 0x0001;
constexpr uint16_t OPT_NODL = 0x0002;
constexpr uint16_t OPT_FLAT = 0x0100;
constexpr uint16_t OPT_SIGNED = 0x0100;
constexpr uint16_t OPT_CENTERX = 0x0200;
constexpr uint16_t OPT_CENTERY = 0x0400;
constexpr uint16_t OPT_CENTER = (OPT_CENTERX | OPT_CENTERY);
constexpr uint16_t OPT_RIGHTX = 0x0800;
constexpr uint16_t OPT_NOBACK = 0x1000;
constexpr uint16_t OPT_NOTICKS = 0x2000;
constexpr uint16_t OPT_NOHM = 0x4000;
constexpr uint16_t OPT_NOPOINTER = 0x4000;
constexpr uint16_t OPT_NOSECS = 0x8000;
constexpr uint16_t OPT_NOHANDS = (OPT_NOPOINTER | OPT_NOSECS);
}
namespace FTDI_FT810 {
constexpr uint16_t OPT_NOTEAR = 0x0004;
constexpr uint16_t OPT_FULLSCREEN = 0x0008;
constexpr uint16_t OPT_MEDIAFIFO = 0x0010;
constexpr uint16_t OPT_SOUND = 0x0020;
}
// GPIO Bits
namespace FTDI {
constexpr uint8_t GPIO_GP0 = 1 << 0;
constexpr uint8_t GPIO_GP1 = 1 << 1;
constexpr uint8_t GPIO_DISP = 1 << 7;
}
namespace FTDI_FT810 {
constexpr uint16_t GPIOX_GP0 = 1 << 0;
constexpr uint16_t GPIOX_GP1 = 1 << 1;
constexpr uint16_t GPIOX_DISP = 1 << 15;
}
// HOST COMMANDS
namespace FTDI {
constexpr uint8_t ACTIVE = 0x00;
constexpr uint8_t STANDBY = 0x41;
constexpr uint8_t SLEEP = 0x42;
constexpr uint8_t PWRDOWN = 0x50;
constexpr uint8_t CLKEXT = 0x44;
constexpr uint8_t CLKINT = 0x48;
constexpr uint8_t CORESET = 0x68;
}
namespace FTDI_FT800 {
constexpr uint8_t CLK48M = 0x62;
constexpr uint8_t CLK36M = 0x61;
}
namespace FTDI_FT810 {
constexpr uint8_t CLKSEL = 0x61;
}
// DISPLAY LIST COMMANDS
namespace FTDI {
constexpr uint8_t ARGB1555 = 0;
constexpr uint8_t L1 = 1;
constexpr uint8_t L4 = 2;
constexpr uint8_t L8 = 3;
constexpr uint8_t RGB332 = 4;
constexpr uint8_t ARGB2 = 5;
constexpr uint8_t ARGB4 = 6;
constexpr uint8_t RGB565 = 7;
constexpr uint8_t PALETTED = 8;
constexpr uint8_t TEXT8X8 = 9;
constexpr uint8_t TEXTVGA = 10;
constexpr uint8_t BARGRAPH = 11;
constexpr uint8_t ALPHA_FUNC_NEVER = 0;
constexpr uint8_t ALPHA_FUNC_LESS = 1;
constexpr uint8_t ALPHA_FUNC_LEQUAL = 2;
constexpr uint8_t ALPHA_FUNC_GREATER = 3;
constexpr uint8_t ALPHA_FUNC_GEQUAL = 4;
constexpr uint8_t ALPHA_FUNC_EQUAL = 5;
constexpr uint8_t ALPHA_FUNC_NOTEQUAL = 6;
constexpr uint8_t ALPHA_FUNC_ALWAYS = 7;
constexpr uint8_t NEAREST = 0;
constexpr uint8_t BILINEAR = 1;
constexpr uint8_t BORDER = 0;
constexpr uint8_t REPEAT = 1;
constexpr uint8_t BLEND_FUNC_ZERO = 0;
constexpr uint8_t BLEND_FUNC_ONE = 1;
constexpr uint8_t BLEND_FUNC_SRC_ALPHA = 2;
constexpr uint8_t BLEND_FUNC_DST_ALPHA = 3;
constexpr uint8_t BLEND_FUNC_ONE_MINUS_SRC_ALPHA = 4;
constexpr uint8_t BLEND_FUNC_ONE_MINUS_DST_ALPHA = 5;
constexpr uint32_t COLOR_MASK_RED = 8;
constexpr uint32_t COLOR_MASK_GRN = 4;
constexpr uint32_t COLOR_MASK_BLU = 2;
constexpr uint32_t COLOR_MASK_ALPHA = 1;
constexpr uint8_t STENCIL_FUNC_NEVER = 0;
constexpr uint8_t STENCIL_FUNC_LESS = 1;
constexpr uint8_t STENCIL_FUNC_LEQUAL = 2;
constexpr uint8_t STENCIL_FUNC_GREATER = 3;
constexpr uint8_t STENCIL_FUNC_GEQUAL = 4;
constexpr uint8_t STENCIL_FUNC_EQUAL = 5;
constexpr uint8_t STENCIL_FUNC_NOTEQUAL = 6;
constexpr uint8_t STENCIL_FUNC_ALWAYS = 7;
constexpr uint8_t STENCIL_OP_ZERO = 0;
constexpr uint8_t STENCIL_OP_KEEP = 1;
constexpr uint8_t STENCIL_OP_REPLACE = 2;
constexpr uint8_t STENCIL_OP_INCR = 3;
constexpr uint8_t STENCIL_OP_DECR = 4;
constexpr uint8_t STENCIL_OP_INVERT = 5;
typedef enum: uint32_t {
BITMAPS = 1,
POINTS = 2,
LINES = 3,
LINE_STRIP = 4,
EDGE_STRIP_R = 5,
EDGE_STRIP_L = 6,
EDGE_STRIP_A = 7,
EDGE_STRIP_B = 8,
RECTS = 9
} begin_t;
}
namespace FTDI_FT800_DL {
constexpr uint32_t ALPHA_FUNC = 0x09000000;
constexpr uint32_t BEGIN = 0x1F000000;
constexpr uint32_t BITMAP_HANDLE = 0x05000000;
constexpr uint32_t BITMAP_LAYOUT = 0x07000000;
constexpr uint32_t BITMAP_SIZE = 0x08000000;
constexpr uint32_t BITMAP_SOURCE = 0x01000000;
constexpr uint32_t BITMAP_TRANSFORM_A = 0x15000000;
constexpr uint32_t BITMAP_TRANSFORM_B = 0x16000000;
constexpr uint32_t BITMAP_TRANSFORM_C = 0x17000000;
constexpr uint32_t BITMAP_TRANSFORM_D = 0x18000000;
constexpr uint32_t BITMAP_TRANSFORM_E = 0x19000000;
constexpr uint32_t BITMAP_TRANSFORM_F = 0x1A000000;
constexpr uint32_t BLEND_FUNC = 0x0B000000;
constexpr uint32_t CALL = 0x1D000000;
constexpr uint32_t CELL = 0x06000000;
constexpr uint32_t CLEAR = 0x26000000;
constexpr uint32_t CLEAR_COLOR_BUFFER = 0x00000004;
constexpr uint32_t CLEAR_STENCIL_BUFFER = 0x00000002;
constexpr uint32_t CLEAR_TAG_BUFFER = 0x00000001;
constexpr uint32_t CLEAR_COLOR_A = 0x0F000000;
constexpr uint32_t CLEAR_COLOR_RGB = 0x02000000;
constexpr uint32_t CLEAR_STENCIL = 0x11000000;
constexpr uint32_t CLEAR_TAG = 0x12000000;
constexpr uint32_t COLOR_A = 0x10000000;
constexpr uint32_t COLOR_MASK = 0x20000000;
constexpr uint32_t COLOR_RGB = 0x04000000;
constexpr uint32_t DL_DISPLAY = 0x00000000;
constexpr uint32_t END = 0x21000000;
constexpr uint32_t JUMP = 0x1E000000;
constexpr uint32_t LINE_WIDTH = 0x0E000000;
constexpr uint32_t MACRO = 0x25000000;
constexpr uint32_t POINT_SIZE = 0x0D000000;
constexpr uint32_t RESTORE_CONTEXT = 0x23000000;
constexpr uint32_t RETURN = 0x24000000;
constexpr uint32_t SAVE_CONTEXT = 0x22000000;
constexpr uint32_t SCISSOR_SIZE = 0x1C000000;
constexpr uint32_t SCISSOR_XY = 0x1B000000;
constexpr uint32_t STENCIL_FUNC = 0x0A000000;
constexpr uint32_t STENCIL_MASK = 0x13000000;
constexpr uint32_t STENCIL_OP = 0x0C000000;
constexpr uint32_t TAG = 0x03000000;
constexpr uint32_t TAG_MASK = 0x14000000;
constexpr uint32_t VERTEX2F = 0x40000000;
constexpr uint32_t VERTEX2II = 0x80000000;
}
namespace FTDI_FT810_DL {
constexpr uint32_t NOP = 0x25000000;
constexpr uint32_t BITMAP_LAYOUT_H = 0x28000000;
constexpr uint32_t BITMAP_SIZE_H = 0x29000000;
constexpr uint32_t VERTEX_FORMAT = 0x27000000;
constexpr uint32_t VERTEX_TRANSLATE_X = 0x2B000000;
constexpr uint32_t VERTEX_TRANSLATE_Y = 0x2C000000;
}
// CO-PROCESSOR ENGINE COMMANDS
namespace FTDI {
constexpr uint32_t CMD_DLSTART = 0xFFFFFF00;
constexpr uint32_t CMD_SWAP = 0xFFFFFF01;
constexpr uint32_t CMD_COLDSTART = 0xFFFFFF32;
constexpr uint32_t CMD_INTERRUPT = 0xFFFFFF02;
constexpr uint32_t CMD_APPEND = 0xFFFFFF1E;
constexpr uint32_t CMD_REGREAD = 0xFFFFFF19;
constexpr uint32_t CMD_MEMWRITE = 0xFFFFFF1A;
constexpr uint32_t CMD_INFLATE = 0xFFFFFF22;
constexpr uint32_t CMD_LOADIMAGE = 0xFFFFFF24;
constexpr uint32_t CMD_MEMCRC = 0xFFFFFF18;
constexpr uint32_t CMD_MEMZERO = 0xFFFFFF1C;
constexpr uint32_t CMD_MEMSET = 0xFFFFFF1B;
constexpr uint32_t CMD_MEMCPY = 0xFFFFFF1D;
constexpr uint32_t CMD_BUTTON = 0xFFFFFF0D;
constexpr uint32_t CMD_CLOCK = 0xFFFFFF14;
constexpr uint32_t CMD_FGCOLOR = 0xFFFFFF0A;
constexpr uint32_t CMD_BGCOLOR = 0xFFFFFF09;
constexpr uint32_t CMD_GRADCOLOR = 0xFFFFFF34;
constexpr uint32_t CMD_GAUGE = 0xFFFFFF13;
constexpr uint32_t CMD_GRADIENT = 0xFFFFFF0B;
constexpr uint32_t CMD_KEYS = 0xFFFFFF0E;
constexpr uint32_t CMD_PROGRESS = 0xFFFFFF0F;
constexpr uint32_t CMD_SCROLLBAR = 0xFFFFFF11;
constexpr uint32_t CMD_SLIDER = 0xFFFFFF10;
constexpr uint32_t CMD_DIAL = 0xFFFFFF2D;
constexpr uint32_t CMD_TOGGLE = 0xFFFFFF12;
constexpr uint32_t CMD_TEXT = 0xFFFFFF0C;
constexpr uint32_t CMD_NUMBER = 0xFFFFFF2E;
constexpr uint32_t CMD_LOADIDENTITY = 0xFFFFFF26;
constexpr uint32_t CMD_SETMATRIX = 0xFFFFFF2A;
constexpr uint32_t CMD_GETMATRIX = 0xFFFFFF33;
constexpr uint32_t CMD_GETPTR = 0xFFFFFF23;
constexpr uint32_t CMD_GETPROPS = 0xFFFFFF25;
constexpr uint32_t CMD_SCALE = 0xFFFFFF28;
constexpr uint32_t CMD_ROTATE = 0xFFFFFF29;
constexpr uint32_t CMD_TRANSLATE = 0xFFFFFF27;
constexpr uint32_t CMD_CALIBRATE = 0xFFFFFF15;
constexpr uint32_t CMD_SPINNER = 0xFFFFFF16;
constexpr uint32_t CMD_SCREENSAVER = 0xFFFFFF2F;
constexpr uint32_t CMD_SKETCH = 0xFFFFFF30;
constexpr uint32_t CMD_STOP = 0xFFFFFF17;
constexpr uint32_t CMD_SETFONT = 0xFFFFFF2B;
constexpr uint32_t CMD_TRACK = 0xFFFFFF2C;
constexpr uint32_t CMD_SNAPSHOT = 0xFFFFFF1F;
constexpr uint32_t CMD_LOGO = 0xFFFFFF31;
}
namespace FTDI_FT810 {
constexpr uint32_t CMD_SETROTATE = 0xFFFFFF36;
constexpr uint32_t CMD_SNAPSHOT2 = 0xFFFFFF37;
constexpr uint32_t CMD_SETBASE = 0xFFFFFF38;
constexpr uint32_t CMD_MEDIAFIFO = 0xFFFFFF39;
constexpr uint32_t CMD_PLAYVIDEO = 0xFFFFFF3A;
constexpr uint32_t CMD_VIDEOSTART = 0xFFFFFF40;
constexpr uint32_t CMD_VIDEOFRAME = 0xFFFFFF41;
constexpr uint32_t CMD_SETBITMAP = 0xFFFFFF43;
}
namespace FTDI {
enum effect_t {
SILENCE = 0x00,
SQUARE_WAVE = 0x01,
SINE_WAVE = 0x02,
SAWTOOTH_WAVE = 0x03,
TRIANGLE_WAVE = 0x04,
BEEPING = 0x05,
ALARM = 0x06,
WARBLE = 0x07,
CAROUSEL = 0x08,
SHORT_PIPS_1 = 0x10,
SHORT_PIPS_2 = 0x11,
SHORT_PIPS_3 = 0x12,
SHORT_PIPS_4 = 0x13,
SHORT_PIPS_5 = 0x14,
SHORT_PIPS_6 = 0x15,
SHORT_PIPS_7 = 0x16,
SHORT_PIPS_8 = 0x17,
SHORT_PIPS_9 = 0x18,
SHORT_PIPS_10 = 0x19,
SHORT_PIPS_11 = 0x1A,
SHORT_PIPS_12 = 0x1B,
SHORT_PIPS_13 = 0x1C,
SHORT_PIPS_14 = 0x1D,
SHORT_PIPS_15 = 0x1E,
SHORT_PIPS_16 = 0x1F,
DTMF_POUND = 0x23,
DTMF_STAR = 0x2C,
DTMF_0 = 0x30,
DTMF_1 = 0x31,
DTMF_2 = 0x32,
DTMF_3 = 0x33,
DTMF_4 = 0x34,
DTMF_5 = 0x35,
DTMF_6 = 0x36,
DTMF_7 = 0x37,
DTMF_8 = 0x38,
DTMF_9 = 0x39,
HARP = 0x40,
XYLOPHONE = 0x41,
TUBA = 0x42,
GLOCKENSPIEL = 0x43,
ORGAN = 0x44,
TRUMPET = 0x45,
PIANO = 0x46,
CHIMES = 0x47,
MUSIC_BOX = 0x48,
BELL = 0x49,
CLICK = 0x50,
SWITCH = 0x51,
COWBELL = 0x52,
NOTCH = 0x53,
HIHAT = 0x54,
KICKDRUM = 0x55,
POP = 0x56,
CLACK = 0x57,
CHACK = 0x58,
MUTE = 0x60,
UNMUTE = 0x61
};
enum note_t {
END_SONG = 0xFF,
REST = 0x00,
NOTE_C1 = 0x18, // 24
NOTE_C1S = 0x19,
NOTE_D1 = 0x1A,
NOTE_D1S = 0x1B,
NOTE_E1 = 0x1C,
NOTE_F1 = 0x1D,
NOTE_F1S = 0x1E,
NOTE_G1 = 0x1F,
NOTE_G1S = 0x20,
NOTE_A1 = 0x21,
NOTE_A1S = 0x22,
NOTE_B1 = 0x23,
NOTE_C2 = 0x24, //36
NOTE_C2S = 0x25,
NOTE_D2 = 0x26,
NOTE_D2S = 0x27,
NOTE_E2 = 0x28,
NOTE_F2 = 0x29,
NOTE_F2S = 0x2A,
NOTE_G2 = 0x2B,
NOTE_G2S = 0x2C,
NOTE_A2 = 0x2D,
NOTE_A2S = 0x2E,
NOTE_B2 = 0x2F,
NOTE_C3 = 0x30,
NOTE_C3S = 0x31,
NOTE_D3 = 0x32,
NOTE_D3S = 0x33,
NOTE_E3 = 0x34,
NOTE_F3 = 0x35,
NOTE_F3S = 0x36,
NOTE_G3 = 0x37,
NOTE_G3S = 0x38,
NOTE_A3 = 0x39,
NOTE_A3S = 0x3A,
NOTE_B3 = 0x3B,
NOTE_C4 = 0x3C,
NOTE_C4S = 0x3D,
NOTE_D4 = 0x3E,
NOTE_D4S = 0x3F,
NOTE_E4 = 0x40,
NOTE_F4 = 0x41,
NOTE_F4S = 0x42,
NOTE_G4 = 0x43,
NOTE_G4S = 0x44,
NOTE_A4 = 0x45,
NOTE_A4S = 0x46,
NOTE_B4 = 0x47,
NOTE_C5 = 0x48,
NOTE_C5S = 0x49,
NOTE_D5 = 0x4A,
NOTE_D5S = 0x4B,
NOTE_E5 = 0x4C,
NOTE_F5 = 0x4D,
NOTE_F5S = 0x4E,
NOTE_G5 = 0x4F,
NOTE_G5S = 0x50,
NOTE_A5 = 0x51,
NOTE_A5S = 0x52,
NOTE_B5 = 0x53,
};
}

@ -0,0 +1,118 @@
/******************
* display_list.h *
*****************/
/**********************************************************************************
* Adapted from: *
* https://github.com/RudolphRiedel/FT800-FT813 *
* By Rudolph Riedel *
* *
* MIT License *
* *
* Copyright (c) 2017 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy *
* of this software and associated documentation files (the "Software"), to deal *
* in the Software without restriction, including without limitation the rights *
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in all *
* copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
* SOFTWARE. *
* *
**********************************************************************************/
#pragma once
namespace FTDI {
/* FT8xx graphics engine specific macros useful for static display list generation */
inline uint32_t ALPHA_FUNC(uint8_t func, uint8_t ref) {return DL::ALPHA_FUNC|((func&7UL)<<8)|(ref&255UL);}
inline uint32_t BEGIN(begin_t prim) {return DL::BEGIN|(prim&15UL);}
inline uint32_t BITMAP_SOURCE(uint32_t ram_g_addr) {return DL::BITMAP_SOURCE|(ram_g_addr & (FTDI::ftdi_memory_map::RAM_G_SIZE-1));}
inline uint32_t BITMAP_HANDLE(uint8_t handle) {return DL::BITMAP_HANDLE|(handle&31UL);}
inline uint32_t BITMAP_LAYOUT(uint8_t format, uint16_t linestride, uint16_t height)
{return DL::BITMAP_LAYOUT|((format&31UL)<<19)|((linestride&1023UL)<<9)|(height&511UL);}
inline uint32_t BITMAP_SIZE(uint8_t filter, uint8_t wrapx, uint8_t wrapy, uint16_t width, uint16_t height)
{return DL::BITMAP_SIZE|((filter&1UL)<<20)|((wrapx&1UL)<<19)|((wrapy&1UL)<<18)|((width&511UL)<<9)|(height&511UL);}
#if FTDI_API_LEVEL >= 810
inline uint32_t BITMAP_LAYOUT_H(uint8_t linestride, uint8_t height)
{return DL::BITMAP_LAYOUT_H|((linestride&3UL)<<2)|(height&3UL);}
inline uint32_t BITMAP_SIZE_H(uint8_t width, uint8_t height)
{return DL::BITMAP_SIZE_H|((width&3UL)<<2)|(height&3UL);}
#endif
inline uint32_t BITMAP_TRANSFORM_A(uint16_t a) {return DL::BITMAP_TRANSFORM_A|(a&131071UL);}
inline uint32_t BITMAP_TRANSFORM_B(uint16_t b) {return DL::BITMAP_TRANSFORM_B|(b&131071UL);}
inline uint32_t BITMAP_TRANSFORM_C(uint32_t c) {return DL::BITMAP_TRANSFORM_C|(c&16777215UL);}
inline uint32_t BITMAP_TRANSFORM_D(uint16_t d) {return DL::BITMAP_TRANSFORM_D|(d&131071UL);}
inline uint32_t BITMAP_TRANSFORM_E(uint16_t e) {return DL::BITMAP_TRANSFORM_E|(e&131071UL);}
inline uint32_t BITMAP_TRANSFORM_F(uint32_t f) {return DL::BITMAP_TRANSFORM_F|(f&16777215UL);}
inline uint32_t BLEND_FUNC(uint8_t src,uint8_t dst) {return DL::BLEND_FUNC|((src&7UL)<<3)|(dst&7UL);}
inline uint32_t CALL(uint16_t dest) {return DL::CALL|(dest&65535UL);}
inline uint32_t CELL(uint8_t cell) {return DL::CELL|(cell&127UL);}
inline uint32_t CLEAR(bool c,bool s,bool t) {return DL::CLEAR|((c?1UL:0UL)<<2)|((s?1UL:0UL)<<1)|(t?1UL:0UL);}
inline uint32_t CLEAR_COLOR_A(uint8_t alpha) {return DL::CLEAR_COLOR_A|(alpha&255UL);}
inline uint32_t CLEAR_COLOR_RGB(uint8_t red, uint8_t green, uint8_t blue)
{return DL::CLEAR_COLOR_RGB|((red&255UL)<<16)|((green&255UL)<<8)|(blue&255UL);}
inline uint32_t CLEAR_COLOR_RGB(uint32_t rgb) {return DL::CLEAR_COLOR_RGB|rgb;}
inline uint32_t CLEAR_STENCIL(uint8_t s) {return DL::CLEAR_STENCIL|(s&255UL);}
inline uint32_t CLEAR_TAG(uint8_t s) {return DL::CLEAR_TAG|(s&255UL);}
inline uint32_t COLOR_A(uint8_t alpha) {return DL::COLOR_A|(alpha&255UL);}
inline uint32_t COLOR_MASK(bool r, bool g, bool b, bool a) {return DL::COLOR_MASK|((r?1UL:0UL)<<3)|((g?1UL:0UL)<<2)|((b?1UL:0UL)<<1)|(a?1UL:0UL);}
inline uint32_t COLOR_RGB(uint8_t red,uint8_t green,uint8_t blue)
{return DL::COLOR_RGB|((red&255UL)<<16)|((green&255UL)<<8)|(blue&255UL);}
inline uint32_t COLOR_RGB(uint32_t rgb) {return DL::COLOR_RGB|rgb;}
/* inline uint32_t DISPLAY() {return (0UL<<24)) */
inline uint32_t END() {return DL::END;}
inline uint32_t JUMP(uint16_t dest) {return DL::JUMP|(dest&65535UL);}
inline uint32_t LINE_WIDTH(uint16_t width) {return DL::LINE_WIDTH|(width&4095UL);}
inline uint32_t MACRO(uint8_t m) {return DL::MACRO|(m&1UL);}
inline uint32_t POINT_SIZE(uint16_t size) {return DL::POINT_SIZE|(size&8191UL);}
inline uint32_t RESTORE_CONTEXT() {return DL::RESTORE_CONTEXT;}
inline uint32_t RETURN () {return DL::RETURN;}
inline uint32_t SAVE_CONTEXT() {return DL::SAVE_CONTEXT;}
inline uint32_t SCISSOR_XY(uint16_t x,uint16_t y) {
return DL::SCISSOR_XY |
(FTDI::ftdi_chip >= 810
? ((x&2047UL)<<11)|(y&2047UL)
: ((x& 511UL)<<10)|(y&511UL));
}
inline uint32_t SCISSOR_SIZE(uint16_t w,uint16_t h) {
return DL::SCISSOR_SIZE |
(FTDI::ftdi_chip >= 810
? ((w&4095UL)<<12)|(h&4095UL)
: ((w&1023UL)<<10)|(h&1023UL));
}
inline uint32_t SCISSOR_XY() {return DL::SCISSOR_XY;}
inline uint32_t SCISSOR_SIZE() {
return DL::SCISSOR_SIZE |
(FTDI::ftdi_chip >= 810
? (2048UL<<12)|(2048UL)
: ( 512UL<<10)|( 512UL));
}
inline uint32_t STENCIL_FUNC(uint16_t func, uint8_t ref, uint8_t mask)
{return DL::STENCIL_FUNC|((func&7UL)<<16)|((ref&255UL)<<8)|(mask&255UL);}
inline uint32_t STENCIL_MASK(uint8_t mask) {return DL::STENCIL_MASK|(mask&255UL);}
inline uint32_t STENCIL_OP(uint8_t sfail, uint8_t spass) {return DL::STENCIL_OP|(((sfail)&7UL)<<3)|(spass&7UL);}
inline uint32_t TAG(uint8_t s) {return DL::TAG|(s&255UL);}
inline uint32_t TAG_MASK(bool mask) {return DL::TAG_MASK|(mask?1:0);}
inline uint32_t VERTEX2F(uint16_t x, uint16_t y) {return DL::VERTEX2F|((x&32767UL)<<15)|(y&32767UL);}
inline uint32_t VERTEX2II(uint16_t x,uint16_t y, uint8_t handle = 0, uint8_t cell = 0)
{return DL::VERTEX2II|((x&511UL)<<21)|((y&511UL)<<12)|((handle&31UL)<<7)|(cell&127UL);}
#if FTDI_API_LEVEL >= 810
inline uint32_t VERTEX_FORMAT(uint8_t frac) {return DL::VERTEX_FORMAT|(frac&7UL);}
inline uint32_t VERTEX_TRANSLATE_X(int32_t x) {return DL::VERTEX_TRANSLATE_X|(x&131071UL);}
inline uint32_t VERTEX_TRANSLATE_Y(int32_t y) {return DL::VERTEX_TRANSLATE_Y|(y&131071UL);}
#endif
}

@ -0,0 +1,40 @@
/****************
* ftdi_basic.h *
****************/
/****************************************************************************
* Written By Mark Pelletier 2019 - Aleph Objects, Inc. *
* Written By Marcio Teixeira 2019 - 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/>. *
****************************************************************************/
#pragma once
#include "../compat.h"
#if !defined(__MARLIN_FIRMWARE__)
#define FTDI_BASIC
#endif
#ifdef FTDI_BASIC
#include "registers_ft800.h"
#include "registers_ft810.h"
#include "constants.h"
#include "boards.h"
#include "commands.h"
#include "spi.h"
#include "display_list.h"
#include "resolutions.h"
#endif

@ -0,0 +1,150 @@
/*********************
* registers_ft800.h *
*********************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
/****************************************************************************
* This header defines registers for the FTDI FT800 LCD Driver chip. *
****************************************************************************/
/*******************************************************************************
* FT810 *
* *
* START END ADDR SIZE NAME DESCRIPTION *
* *
* 0x000000 0x03FFFF 256 kB RAM_G Main Graphics RAM *
* *
* 0x0C0000 0x0C0003 4 B ROM_CHIPID [0:1] 0x800 Chip Id *
* [1:2] 0x0100 Vers ID *
* *
* 0x0BB23C 0x0FFFFB 275 kB ROM_FONT Font table and bitmap *
* *
* 0x0FFFFC 0x0FFFFF 4 B ROM_FONT_ADDR Font table pointer address *
* *
* 0x100000 0x101FFF 8 kB RAM_DL Display List RAM *
* *
* 0x102000 0x1023FF 1 kB RAM_PAL Palette RAM *
* *
* 0x102400 0x10257F 380 B * Registers *
* *
* 0x108000 0x108FFF 4 kB RAM_CMD Command Buffer *
* *
*******************************************************************************/
#pragma once
namespace FTDI {
struct ft800_memory_map {
// MEMORY LOCATIONS FT800
static constexpr uint32_t RAM_G = 0x000000; // Main Graphics RAM
static constexpr uint32_t ROM_CHIPID = 0x0C0000; // Chip ID/Version ID
static constexpr uint32_t ROM_FONT = 0x0BB23C; // Font ROM
static constexpr uint32_t ROM_FONT_ADDR = 0x0FFFFC; // Font Table Pointer
static constexpr uint32_t RAM_DL = 0x100000; // Display List RAM
static constexpr uint32_t RAM_PAL = 0x102000; // Palette RAM
static constexpr uint32_t RAM_REG = 0x102400; // Registers
static constexpr uint32_t RAM_CMD = 0x108000; // Command Buffer
static constexpr uint32_t RAM_G_SIZE = 256*1024l; // 256k
};
struct ft800_registers {
// REGISTERS AND ADDRESSES FT800
// REGISTER ADDRESS SIZE RESET VALUE TYPE DESCRIPTION
static constexpr uint32_t ID = 0x102400; // 8 0x7C r Identification Register, Always 0x7C
static constexpr uint32_t FRAMES = 0x102404; // 32 0x00000000 r Frame Counter, Since Reset
static constexpr uint32_t CLOCK = 0x102408; // 32 0x00000000 r Clock cycles, Since Reset
static constexpr uint32_t FREQUENCY = 0x10240C; // 28 0x03938700 r/w Main Clock Frequency
static constexpr uint32_t RENDERMODE = 0x102410; // 1 0x00 r/w Rendering Mode: 0 = normal, 1 = single-line
static constexpr uint32_t SNAPY = 0x102414; // 11 0x0000 r/w Scan Line Select for RENDERMODE 1
static constexpr uint32_t SNAPSHOT = 0x102418; // 1 - r Trigger for RENDERMODE 1
static constexpr uint32_t CPURESET = 0x10241C; // 3 0x02 r/w RESET Bit2 Audio - Bit1 Touch - Bit0 Graphics
static constexpr uint32_t TAP_CRC = 0x102420; // 32 - r Live Video Tap
static constexpr uint32_t TAP_MASK = 0x102424; // 32 0xFFFFFFFF r/w Live Video Tap Mask
static constexpr uint32_t HCYCLE = 0x102428; // 12 0x224 r/w Horizontal Total Cycle Count
static constexpr uint32_t HOFFSET = 0x10242C; // 12 0x02B r/w Horizontal Display Start Offset
static constexpr uint32_t HSIZE = 0x102430; // 12 0x1E0 r/w Horizontal Display Pixel Count
static constexpr uint32_t HSYNC0 = 0x102434; // 12 0x000 r/w Horizontal Sync Fall Offset
static constexpr uint32_t HSYNC1 = 0x102438; // 12 0x029 r/w Horizontal Sync Rise Offset
static constexpr uint32_t VCYCLE = 0x10243C; // 12 0x124 r/w Vertical Total Cycle Count
static constexpr uint32_t VOFFSET = 0x102440; // 12 0x00C r/w Vertical Display Start Offset
static constexpr uint32_t VSIZE = 0x102444; // 12 0x110 r/w Vertical Display Line Count
static constexpr uint32_t VSYNC0 = 0x102448; // 10 0x000 r/w Vertical Sync Fall Offset
static constexpr uint32_t VSYNC1 = 0x10244C; // 10 0x00A r/w Vertical Sync Rise Offset
static constexpr uint32_t DLSWAP = 0x102450; // 2 0x00 r/w Display List Swap Control
static constexpr uint32_t ROTATE = 0x102454; // 3 0x00 r/w Screen 90,180, 270 degree rotate
static constexpr uint32_t OUTBITS = 0x102458; // 9 0x1B6 r/w Output Resolution, 3x3x3 Bits
static constexpr uint32_t DITHER = 0x10245C; // 1 0x01 r/w Output Dither Enable
static constexpr uint32_t SWIZZLE = 0x102460; // 4 0x00 r/w Output RGB Swizzle, Pin Change for PCB Routing
static constexpr uint32_t CSPREAD = 0x102464; // 1 0x01 r/w Output Clock Spreading Enable
static constexpr uint32_t PCLK_POL = 0x102468; // 1 0x00 r/w PCLK Polarity: 0 = Rising Edge, 1 = Falling Edge
static constexpr uint32_t PCLK = 0x10246C; // 8 0x00 r/w PCLK Frequency Divider, 0 = Disable Clock
static constexpr uint32_t TAG_X = 0x102470; // 11 0x000 r/w Tag Query X Coordinate
static constexpr uint32_t TAG_Y = 0x102474; // 11 0x000 r/w Tag Query Y Coordinate
static constexpr uint32_t TAG = 0x102478; // 8 0x00 r Tag Query Result
static constexpr uint32_t VOL_PB = 0x10247C; // 8 0xFF r/w Audio Playback Volume
static constexpr uint32_t VOL_SOUND = 0x102480; // 8 0xFF r/w Audio Synthesizer Volume
static constexpr uint32_t SOUND = 0x102484; // 16 0x0000 r/w Audio Sound Effect Select
static constexpr uint32_t PLAY = 0x102488; // 1 0x00 r/w Audio Start Effect Playback
static constexpr uint32_t GPIO_DIR = 0x10248C; // 8 0x80 r/w GPIO Pin Direction: 0 = Input , 1 = Output
static constexpr uint32_t GPIO = 0x102490; // 8 0x00 r/w GPIO Pin Values for 0, 1, 7 Drive Strength 2, 3, 4, 5, 6
static constexpr uint32_t INT_FLAGS = 0x102498; // 8 0x00 r Interrupt Flags, Clear by Reading
static constexpr uint32_t INT_EN = 0x10249C; // 1 0x00 r/w Global Interrupt Enable
static constexpr uint32_t INT_MASK = 0x1024A0; // 8 0xFF r/w Interrupt Enable Mask
static constexpr uint32_t PLAYBACK_START = 0x1024A4; // 20 0x00000 r/w Audio Playback RAM Start Address
static constexpr uint32_t PLAYBACK_LENGTH = 0x1024A8; // 20 0x00000 r/w Audio Playback Sample Length (Bytes)
static constexpr uint32_t PLAYBACK_READPTR = 0x1024AC; // 20 - r Audio Playback Read Pointer
static constexpr uint32_t PLAYBACK_FREQ = 0x1024B0; // 16 0x1F40 r/w Audio Playback Frequency (Hz)
static constexpr uint32_t PLAYBACK_FORMAT = 0x1024B4; // 2 0x00 r/w Audio Playback Format
static constexpr uint32_t PLAYBACK_LOOP = 0x1024B8; // 1 0x00 r/w Audio Playback Loop Enable
static constexpr uint32_t PLAYBACK_PLAY = 0x1024BC; // 1 0x00 r Audio Start Playback
static constexpr uint32_t PWM_HZ = 0x1024C0; // 14 0x00FA r/w Backlight PWM Frequency (Hz)
static constexpr uint32_t PWM_DUTY = 0x1024C4; // 8 0x80 r/w Backlight PWM Duty Cycle: 0 = 0%, 128 = 100%
static constexpr uint32_t MACRO_0 = 0x1024C8; // 32 0x00000000 r/w Display List Macro Command 0
static constexpr uint32_t MACRO_1 = 0x1024CC; // 32 0x00000000 r/w Display List Macro Command 1
static constexpr uint32_t CMD_READ = 0x1024E4; // 12 0x000 r/w Command Buffer Read Pointer
static constexpr uint32_t CMD_WRITE = 0x1024E8; // 12 0x000 r/w Command Buffer Write Pointer
static constexpr uint32_t CMD_DL = 0x1024EC; // 13 0x0000 r/w Command Display List Offset
static constexpr uint32_t TOUCH_MODE = 0x1024F0; // 2 0x03 r/w Touch-Screen Sampling Mode
static constexpr uint32_t TOUCH_ADC_MODE = 0x1024F4; // 1 0x01 r/w Select Single Ended or Differential Sampling
static constexpr uint32_t TOUCH_CHARGE = 0x1024F8; // 16 0x1770 r/w Touch Screen Charge Time, n x 6 Clocks
static constexpr uint32_t TOUCH_SETTLE = 0x1024FC; // 4 0x03 r/w Touch-Screen Settle Time, n x 6 Clocks
static constexpr uint32_t TOUCH_OVERSAMPLE = 0x102500; // 4 0x07 r/w Touch-Screen Oversample Factor
static constexpr uint32_t TOUCH_RZTHRESH = 0x102504; // 16 0xFFFF r/w Touch-Screen Resistance Threshold
static constexpr uint32_t TOUCH_RAW_XY = 0x102508; // 32 - r Touch-Screen Raw (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_RZ = 0x10250C; // 16 - r Touch-Screen Resistance
static constexpr uint32_t TOUCH_SCREEN_XY = 0x102510; // 32 - r Touch-Screen Screen (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_TAG_XY = 0x102514; // 32 - r Touch-Screen Tag 0 Lookup (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_TAG = 0x102518; // 8 - r Touch-Screen Tag 0 Result
static constexpr uint32_t TOUCH_TRANSFORM_A = 0x10251C; // 32 0x00010000 r/w Touch-Screen Transform Coefficient A (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_B = 0x102520; // 32 0x00000000 r/w Touch-Screen Transform Coefficient B (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_C = 0x102524; // 32 0x00000000 r/w Touch-Screen Transform Coefficient C (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_D = 0x102528; // 32 0x00000000 r/w Touch-Screen Transform Coefficient D (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_E = 0x10252C; // 32 0x00010000 r/w Touch-Screen Transform Coefficient E (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_F = 0x102530; // 32 0x00000000 r/w Touch-Screen Transform Coefficient F (s15.16)
// Reserved Addresses 0x102434 - 0x102470
static constexpr uint32_t TOUCH_DIRECT_XY = 0x102574; // 32 - r Touch-Screen Direct Conversions XY (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_DIRECT_Z1Z2 = 0x102578; // 32 - r Touch-Screen Direct Conversions Z (z1-MSB16; z2-LSB16)
static constexpr uint32_t TRACKER = 0x109000; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
};
}

@ -0,0 +1,185 @@
/*********************
* registers_ft810.h *
*********************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
/****************************************************************************
* This header defines registers for the FTDI FT810 LCD Driver chip. *
****************************************************************************/
/*******************************************************************************
* FT810 *
* *
* START END ADDR SIZE NAME DESCRIPTION *
* *
* 0x000000 0x0FFFFF 1024 kB RAM_G Main Graphics RAM (0 to 1048572) *
* *
* 0x0C0000 0x0C0003 4 B ROM_CHIPID [0:1] 0x800 Chip Id *
* [1:2] 0x0100 Vers ID *
* *
* 0x1E0000 0x2FFFFB 1152 kB ROM_FONT Font table and bitmap *
* *
* 0x2FFFFC 0x2FFFFF 4 B ROM_FONT_ADDR Font table pointer address *
* *
* 0x300000 0x301FFF 8 kB RAM_DL Display List RAM *
* *
* 0x302000 0x302FFF 4 kB * Registers *
* *
* 0x308000 0x308FFF 4 kB RAM_CMD Command Buffer *
* *
*******************************************************************************/
#pragma once
namespace FTDI {
struct ft810_memory_map {
// MEMORY LOCATIONS FT810
static constexpr uint32_t RAM_G = 0x000000; // Main Graphics RAM
static constexpr uint32_t ROM_CHIPID = 0x0C0000; // Chip ID/Version ID
static constexpr uint32_t ROM_FONT = 0x1E0000; // Font ROM
static constexpr uint32_t ROM_FONT_ADDR = 0x2FFFFC; // Font Table Pointer
static constexpr uint32_t RAM_DL = 0x300000; // Display List RAM
static constexpr uint32_t RAM_REG = 0x302000; // Registers
static constexpr uint32_t RAM_CMD = 0x308000; // Command Buffer
static constexpr uint32_t RAM_G_SIZE = 1024*1024l; // 1024k
};
struct ft810_registers {
// REGISTERS AND ADDRESSES FT810
// REGISTER ADDRESS SIZE RESET VALUE TYPE DESCRIPTION
static constexpr uint32_t ID = 0x302000; // 8 0x7C r Identification Register, Always 0x7C
static constexpr uint32_t FRAMES = 0x302004; // 32 0x00000000 r Frame Counter, Since Reset
static constexpr uint32_t CLOCK = 0x302008; // 32 0x00000000 r Clock cycles, Since Reset
static constexpr uint32_t FREQUENCY = 0x30200C; // 28 0x03938700 r/w Main Clock Frequency
static constexpr uint32_t RENDERMODE = 0x302010; // 1 0x00 r/w Rendering Mode: 0 = normal, 1 = single-line
static constexpr uint32_t SNAPY = 0x302014; // 11 0x0000 r/w Scan Line Select for RENDERMODE 1
static constexpr uint32_t SNAPSHOT = 0x302018; // 1 - r Trigger for RENDERMODE 1
static constexpr uint32_t SNAPFORMAT = 0x30201C; // 6 0x20 r/w Pixel Format for Scanline Readout
static constexpr uint32_t CPURESET = 0x302020; // 3 0x02 r/w RESET Bit2 Audio - Bit1 Touch - Bit0 Graphics
static constexpr uint32_t TAP_CRC = 0x302024; // 32 - r Live Video Tap
static constexpr uint32_t TAP_MASK = 0x302028; // 32 0xFFFFFFFF r/w Live Video Tap Mask
static constexpr uint32_t HCYCLE = 0x30202C; // 12 0x224 r/w Horizontal Total Cycle Count
static constexpr uint32_t HOFFSET = 0x302030; // 12 0x02B r/w Horizontal Display Start Offset
static constexpr uint32_t HSIZE = 0x302034; // 12 0x1E0 r/w Horizontal Display Pixel Count
static constexpr uint32_t HSYNC0 = 0x302038; // 12 0x000 r/w Horizontal Sync Fall Offset
static constexpr uint32_t HSYNC1 = 0x30203C; // 12 0x029 r/w Horizontal Sync Rise Offset
static constexpr uint32_t VCYCLE = 0x302040; // 12 0x124 r/w Vertical Total Cycle Count
static constexpr uint32_t VOFFSET = 0x302044; // 12 0x00C r/w Vertical Display Start Offset
static constexpr uint32_t VSIZE = 0x302048; // 12 0x110 r/w Vertical Display Line Count
static constexpr uint32_t VSYNC0 = 0x30204C; // 10 0x000 r/w Vertical Sync Fall Offset
static constexpr uint32_t VSYNC1 = 0x302050; // 10 0x00A r/w Vertical Sync Rise Offset
static constexpr uint32_t DLSWAP = 0x302054; // 2 0x00 r/w Display List Swap Control
static constexpr uint32_t ROTATE = 0x302058; // 3 0x00 r/w Screen 90,180, 270 degree rotate
static constexpr uint32_t OUTBITS = 0x30205C; // 9 0x1B6 r/w Output Resolution, 3x3x3 Bits
static constexpr uint32_t DITHER = 0x302060; // 1 0x01 r/w Output Dither Enable
static constexpr uint32_t SWIZZLE = 0x302064; // 4 0x00 r/w Output RGB Swizzle, Pin Change for PCB Routing
static constexpr uint32_t CSPREAD = 0x302068; // 1 0x01 r/w Output Clock Spreading Enable
static constexpr uint32_t PCLK_POL = 0x30206C; // 1 0x00 r/w PCLK Polarity: 0 = Rising Edge, 1 = Falling Edge
static constexpr uint32_t PCLK = 0x302070; // 8 0x00 r/w PCLK Frequency Divider, 0 = Disable Clock
static constexpr uint32_t TAG_X = 0x302074; // 11 0x000 r/w Tag Query X Coordinate
static constexpr uint32_t TAG_Y = 0x302078; // 11 0x000 r/w Tag Query Y Coordinate
static constexpr uint32_t TAG = 0x30207C; // 8 0x00 r Tag Query Result
static constexpr uint32_t VOL_PB = 0x302080; // 8 0xFF r/w Audio Playback Volume
static constexpr uint32_t VOL_SOUND = 0x302084; // 8 0xFF r/w Audio Synthesizer Volume
static constexpr uint32_t SOUND = 0x302088; // 16 0x0000 r/w Audio Sound Effect Select
static constexpr uint32_t PLAY = 0x30208C; // 1 0x00 r/w Audio Start Effect Playback
static constexpr uint32_t GPIO_DIR = 0x302090; // 8 0x80 r/w GPIO Pin Direction: 0 = Input , 1 = Output
static constexpr uint32_t GPIO = 0x302094; // 8 0x00 r/w GPIO Pin Values for 0, 1, 7 Drive Strength 2, 3, 4, 5, 6
static constexpr uint32_t GPIOX_DIR = 0x302098; // 16 0x8000 r/w Extended GPIO Pin Direction
static constexpr uint32_t GPIOX = 0x30209C; // 16 0x0080 r/w Extended GPIO Pin Values
// Reserved Addr 0x3020A0
// Reserved Addr 0x3020A4
static constexpr uint32_t INT_FLAGS = 0x3020A8; // 8 0x00 r Interrupt Flags, Clear by Reading
static constexpr uint32_t INT_EN = 0x3020AC; // 1 0x00 r/w Global Interrupt Enable
static constexpr uint32_t INT_MASK = 0x3020B0; // 8 0xFF r/w Interrupt Enable Mask
static constexpr uint32_t PLAYBACK_START = 0x3020B4; // 20 0x00000 r/w Audio Playback RAM Start Address
static constexpr uint32_t PLAYBACK_LENGTH = 0x3020B8; // 20 0x00000 r/w Audio Playback Sample Length (Bytes)
static constexpr uint32_t PLAYBACK_READPTR = 0x3020BC; // 20 - r Audio Playback Read Pointer
static constexpr uint32_t PLAYBACK_FREQ = 0x3020C0; // 16 0x1F40 r/w Audio Playback Frequency (Hz)
static constexpr uint32_t PLAYBACK_FORMAT = 0x3020C4; // 2 0x00 r/w Audio Playback Format
static constexpr uint32_t PLAYBACK_LOOP = 0x3020C8; // 1 0x00 r/w Audio Playback Loop Enable
static constexpr uint32_t PLAYBACK_PLAY = 0x3020CC; // 1 0x00 r Audio Start Playback
static constexpr uint32_t PWM_HZ = 0x3020D0; // 14 0x00FA r/w Backlight PWM Frequency (Hz)
static constexpr uint32_t PWM_DUTY = 0x3020D4; // 8 0x80 r/w Backlight PWM Duty Cycle: 0 = 0%, 128 = 100%
static constexpr uint32_t MACRO_0 = 0x3020D8; // 32 0x00000000 r/w Display List Macro Command 0
static constexpr uint32_t MACRO_1 = 0x3020DC; // 32 0x00000000 r/w Display List Macro Command 1
// Reserved Addr 0x3020E0
// Reserved Addr 0x3020E4
// Reserved Addr 0x3020E8
// Reserved Addr 0x3020EC
// Reserved Addr 0x3020F0
// Reserved Addr 0x3020F4
static constexpr uint32_t CMD_READ = 0x3020F8; // 12 0x000 r/w Command Buffer Read Pointer
static constexpr uint32_t CMD_WRITE = 0x3020FC; // 12 0x000 r/w Command Buffer Write Pointer
static constexpr uint32_t CMD_DL = 0x302100; // 13 0x0000 r/w Command Display List Offset
static constexpr uint32_t TOUCH_MODE = 0x302104; // 2 0x03 r/w Touch-Screen Sampling Mode
static constexpr uint32_t TOUCH_ADC_MODE = 0x302108; // 1 0x01 r/w Select Single Ended or Differential Sampling
static constexpr uint32_t TOUCH_CHARGE = 0x30210C; // 16 0x1770 r/w Touch Screen Charge Time, n x 6 Clocks
static constexpr uint32_t TOUCH_SETTLE = 0x302110; // 4 0x03 r/w Touch-Screen Settle Time, n x 6 Clocks
static constexpr uint32_t TOUCH_OVERSAMPLE = 0x302114; // 4 0x07 r/w Touch-Screen Oversample Factor
static constexpr uint32_t TOUCH_RZTHRESH = 0x302118; // 16 0xFFFF r/w Touch-Screen Resistance Threshold
static constexpr uint32_t TOUCH_RAW_XY = 0x30211C; // 32 - r Touch-Screen Raw (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_RZ = 0x302120; // 16 - r Touch-Screen Resistance
static constexpr uint32_t TOUCH_SCREEN_XY = 0x302124; // 32 - r Touch-Screen Screen (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_TAG_XY = 0x302128; // 32 - r Touch-Screen Tag 0 Lookup (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_TAG = 0x30212C; // 8 - r Touch-Screen Tag 0 Result
static constexpr uint32_t TOUCH_TAG1_XY = 0x302130; // 32 - r Touch-Screen Tag 1 Lookup
static constexpr uint32_t TOUCH_TAG1 = 0x302134; // 8 - r Touch-Screen Tag 1 Result
static constexpr uint32_t TOUCH_TAG2_XY = 0x302138; // 32 - r Touch-Screen Tag 2 Lookup
static constexpr uint32_t TOUCH_TAG2 = 0x30213C; // 8 - r Touch-Screen Tag 2 Result
static constexpr uint32_t TOUCH_TAG3_XY = 0x302140; // 32 - r Touch-Screen Tag 3 Lookup
static constexpr uint32_t TOUCH_TAG3 = 0x302144; // 8 - r Touch-Screen Tag 3 Result
static constexpr uint32_t TOUCH_TAG4_XY = 0x302148; // 32 - r Touch-Screen Tag 4 Lookup
static constexpr uint32_t TOUCH_TAG4 = 0x30214C; // 8 - r Touch-Screen Tag 4 Result
static constexpr uint32_t TOUCH_TRANSFORM_A = 0x302150; // 32 0x00010000 r/w Touch-Screen Transform Coefficient A (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_B = 0x302154; // 32 0x00000000 r/w Touch-Screen Transform Coefficient B (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_C = 0x302158; // 32 0x00000000 r/w Touch-Screen Transform Coefficient C (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_D = 0x30215C; // 32 0x00000000 r/w Touch-Screen Transform Coefficient D (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_E = 0x302160; // 32 0x00010000 r/w Touch-Screen Transform Coefficient E (s15.16)
static constexpr uint32_t TOUCH_TRANSFORM_F = 0x302164; // 32 0x00000000 r/w Touch-Screen Transform Coefficient F (s15.16)
static constexpr uint32_t TOUCH_CONFIG = 0x302168; // 16 0x8381 r/w Touch Configuration
static constexpr uint32_t CTOUCH_TOUCH4_X = 0x30216C; // 16 - r Extended Mode Touch Screen
// Reserved Addresses 0x302170
static constexpr uint32_t BIST_EN = 0x302174; // 1 0 r/w BIST Memory Mapping Enable
// Reserved Addr 0x302178
// Reserved Addr 0x30217C
static constexpr uint32_t TRIM = 0x302180; // 8 0 r/w Internal Clock Trimming
static constexpr uint32_t ANA_COMP = 0x302184; // 8 0 r/w Analog Control Register
static constexpr uint32_t SPI_WIDTH = 0x302188; // 3 0 r/w QSPI Bus Width Setting
static constexpr uint32_t TOUCH_DIRECT_XY = 0x30218C; // 32 - r Touch-Screen Direct Conversions XY (x-MSB16; y-LSB16)
static constexpr uint32_t TOUCH_DIRECT_Z1Z2 = 0x302190; // 32 - r Touch-Screen Direct Conversions Z (z1-MSB16; z2-LSB16)
// Reserved Addresses 0x302194 - 0x302560
static constexpr uint32_t DATESTAMP = 0x320564; // 128 - r Stamp Date Code
static constexpr uint32_t CMDB_SPACE = 0x302574; // 12 0xFFC r/w Command DL Space Available
static constexpr uint32_t CMDB_WRITE = 0x302578; // 32 0 w Command DL Write
static constexpr uint32_t TRACKER = 0x309000; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
static constexpr uint32_t TRACKER_1 = 0x309004; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
static constexpr uint32_t TRACKER_2 = 0x309008; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
static constexpr uint32_t TRACKER_3 = 0x30900C; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
static constexpr uint32_t TRACKER_4 = 0x309010; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
static constexpr uint32_t MEDIAFIFO_READ = 0x309014; // 32 0x00000000 r/w Media FIFO read pointer
static constexpr uint32_t MEDIAFIFO_WRITE = 0x309018; // 32 0x00000000 r/w Media FIFO write pointer
};
}

@ -0,0 +1,128 @@
/*****************
* resolutions.h *
*****************/
/****************************************************************************
* Written By Mark Pelletier 2019 - Aleph Objects, Inc. *
* Written By Marcio Teixeira 2019 - 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/>. *
****************************************************************************/
#pragma once
/***
* The FT8xx has odd registers that don't correspond to timing values in
* display datasheets. This macro computes the register values using the
* formulas given in the document:
*
* Bridgetek Application Note
* AN_336 FT8xx
* Selecting an LCD Display
* Version 2.1
* Issue Date: 2017-11-14
*
*/
#define COMPUTE_REGS_FROM_DATASHEET \
constexpr uint16_t Hoffset = thfp + thb - 1; \
constexpr uint16_t Hcycle = th; \
constexpr uint16_t Hsync0 = thfp - 1 ; \
constexpr uint16_t Hsync1 = thfp + thpw - 1; \
constexpr uint16_t Voffset = tvfp + tvb - 1; \
constexpr uint16_t Vcycle = tv; \
constexpr uint16_t Vsync0 = tvfp - 1; \
constexpr uint16_t Vsync1 = tvfp + tvpw - 1; \
static_assert(thfp + thb + Hsize == th, "Mismatch in display th"); \
static_assert(tvfp + tvb + Vsize == tv, "Mismatch in display tv");
#ifdef TOUCH_UI_320x240
namespace FTDI {
constexpr uint8_t Pclk = 8;
constexpr uint8_t Pclkpol = 0;
constexpr uint16_t Hsize = 320;
constexpr uint16_t Vsize = 240;
constexpr uint16_t Vsync0 = 0;
constexpr uint16_t Vsync1 = 2;
constexpr uint16_t Voffset = 13;
constexpr uint16_t Vcycle = 263;
constexpr uint16_t Hsync0 = 0;
constexpr uint16_t Hsync1 = 10;
constexpr uint16_t Hoffset = 70;
constexpr uint16_t Hcycle = 408;
constexpr uint32_t default_transform_a = 0x000054ad;
constexpr uint32_t default_transform_b = 0xffffff52;
constexpr uint32_t default_transform_c = 0xfff7f6e4;
constexpr uint32_t default_transform_d = 0x00000065;
constexpr uint32_t default_transform_e = 0xffffbe3b;
constexpr uint32_t default_transform_f = 0x00f68e75;
}
#elif defined(TOUCH_UI_480x272)
namespace FTDI {
constexpr uint8_t Pclk = 7;
constexpr uint8_t Pclkpol = 1;
constexpr uint16_t Hsize = 480;
constexpr uint16_t Vsize = 272;
constexpr uint16_t th = 525; // One horizontal line
constexpr uint16_t thfp = 43; // HS Front porch
constexpr uint16_t thb = 2; // HS Back porch (blanking)
constexpr uint16_t thpw = 41; // HS pulse width
constexpr uint16_t tv = 286; // Vertical period time
constexpr uint16_t tvfp = 12; // VS Front porch
constexpr uint16_t tvb = 2; // VS Back porch (blanking)
constexpr uint16_t tvpw = 10; // VS pulse width
COMPUTE_REGS_FROM_DATASHEET
constexpr uint32_t default_transform_a = 0x00008100;
constexpr uint32_t default_transform_b = 0x00000000;
constexpr uint32_t default_transform_c = 0xFFF18000;
constexpr uint32_t default_transform_d = 0x00000000;
constexpr uint32_t default_transform_e = 0xFFFFB100;
constexpr uint32_t default_transform_f = 0x0120D000;
}
#elif defined(TOUCH_UI_800x480)
namespace FTDI {
constexpr uint8_t Pclk = 3;
constexpr uint8_t Pclkpol = 1;
constexpr uint16_t Hsize = 800;
constexpr uint16_t Vsize = 480;
constexpr uint16_t th = 1056; // One horizontal line
constexpr uint16_t thfp = 210; // HS Front porch
constexpr uint16_t thb = 46; // HS Back porch (blanking)
constexpr uint16_t thpw = 23; // HS pulse width
constexpr uint16_t tv = 525; // Vertical period time
constexpr uint16_t tvfp = 22; // VS Front porch
constexpr uint16_t tvb = 23; // VS Back porch (blanking)
constexpr uint16_t tvpw = 10; // VS pulse width
COMPUTE_REGS_FROM_DATASHEET
constexpr uint32_t default_transform_a = 0x0000D8B9;
constexpr uint32_t default_transform_b = 0x00000124;
constexpr uint32_t default_transform_c = 0xFFE23926;
constexpr uint32_t default_transform_d = 0xFFFFFF51;
constexpr uint32_t default_transform_e = 0xFFFF7E4F;
constexpr uint32_t default_transform_f = 0x01F0AF70;
}
#else
#error Unknown or no LULZBOT_TOUCH_UI display resolution specified. To add a display resolution, modify "ftdi_eve_resolutions.h"
#endif

@ -0,0 +1,178 @@
/***********
* spi.cpp *
***********/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#include "ftdi_basic.h"
#ifdef FTDI_BASIC
/********************************* SPI Functions *********************************/
namespace FTDI {
#if !defined(CLCD_USE_SOFT_SPI)
SPISettings SPI::spi_settings(SPI_FREQUENCY, MSBFIRST, SPI_MODE0);
#endif
void SPI::spi_init (void) {
SET_OUTPUT(CLCD_MOD_RESET); // Module Reset (a.k.a. PD, not SPI)
WRITE(CLCD_MOD_RESET, 0); // start with module in power-down
SET_OUTPUT(CLCD_SPI_CS);
WRITE(CLCD_SPI_CS, 1);
#ifdef SPI_FLASH_SS
SET_OUTPUT(SPI_FLASH_SS);
WRITE(SPI_FLASH_SS, 1);
#endif
#ifdef CLCD_USE_SOFT_SPI
SET_OUTPUT(CLCD_SOFT_SPI_MOSI);
WRITE(CLCD_SOFT_SPI_MOSI, 1);
SET_OUTPUT(CLCD_SOFT_SPI_SCLK);
WRITE(CLCD_SOFT_SPI_SCLK, 0);
SET_INPUT_PULLUP(CLCD_SOFT_SPI_MISO);
#else
::SPI.begin();
#endif
}
#ifdef CLCD_USE_SOFT_SPI
uint8_t SPI::_soft_spi_xfer (uint8_t spiOutByte) {
uint8_t spiIndex = 0x80;
uint8_t spiInByte = 0;
uint8_t k;
noInterrupts();
for(k = 0; k <8; k++) { // Output and Read each bit of spiOutByte and spiInByte
if (spiOutByte & spiIndex) { // Output MOSI Bit
WRITE(CLCD_SOFT_SPI_MOSI, 1);
}
else {
WRITE(CLCD_SOFT_SPI_MOSI, 0);
}
WRITE(CLCD_SOFT_SPI_SCLK, 1); // Pulse Clock
WRITE(CLCD_SOFT_SPI_SCLK, 0);
if (READ(CLCD_SOFT_SPI_MISO)) {
spiInByte |= spiIndex;
}
spiIndex >>= 1;
}
interrupts();
return spiInByte;
}
#endif
#ifdef CLCD_USE_SOFT_SPI
void SPI::_soft_spi_send (uint8_t spiOutByte) {
uint8_t spiIndex = 0x80;
uint8_t k;
noInterrupts();
for(k = 0; k <8; k++) { // Output each bit of spiOutByte
if (spiOutByte & spiIndex) { // Output MOSI Bit
WRITE(CLCD_SOFT_SPI_MOSI, 1);
}
else {
WRITE(CLCD_SOFT_SPI_MOSI, 0);
}
WRITE(CLCD_SOFT_SPI_SCLK, 1); // Pulse Clock
WRITE(CLCD_SOFT_SPI_SCLK, 0);
spiIndex >>= 1;
}
interrupts();
}
#endif
void SPI::spi_read_bulk (void *data, uint16_t len) {
uint8_t* p = (uint8_t *)data;
#if !defined(CLCD_USE_SOFT_SPI)
::SPI.transfer(p, len);
#else
while (len--) *p++ = spi_recv();
#endif
}
bool SPI::spi_verify_bulk (const void *data, uint16_t len) {
const uint8_t* p = (const uint8_t *)data;
while (len--) if (*p++ != spi_recv()) return false;
return true;
}
// CLCD SPI - Chip Select
void SPI::spi_ftdi_select (void) {
#if !defined(CLCD_USE_SOFT_SPI)
::SPI.beginTransaction(spi_settings);
#endif
WRITE(CLCD_SPI_CS, 0);
delayMicroseconds(1);
}
// CLCD SPI - Chip Deselect
void SPI::spi_ftdi_deselect (void) {
WRITE(CLCD_SPI_CS, 1);
#if !defined(CLCD_USE_SOFT_SPI)
::SPI.endTransaction();
#endif
}
#ifdef SPI_FLASH_SS
// Serial SPI Flash SPI - Chip Select
void SPI::spi_flash_select () {
#if !defined(CLCD_USE_SOFT_SPI)
::SPI.beginTransaction(spi_settings);
#endif
WRITE(SPI_FLASH_SS, 0);
delayMicroseconds(1);
}
// Serial SPI Flash SPI - Chip Deselect
void SPI::spi_flash_deselect () {
WRITE(SPI_FLASH_SS, 1);
#if !defined(CLCD_USE_SOFT_SPI)
::SPI.endTransaction();
#endif
}
#endif
// Not really a SPI signal...
void SPI::ftdi_reset (void) {
WRITE(CLCD_MOD_RESET, 0);
delay(6); /* minimum time for power-down is 5ms */
WRITE(CLCD_MOD_RESET, 1);
delay(21); /* minimum time to allow from rising PD_N to first access is 20ms */
}
// Not really a SPI signal...
void SPI::test_pulse(void)
{
#ifdef CLCD_AUX_0
WRITE(CLCD_AUX_0, 1);
delayMicroseconds(10);
WRITE(CLCD_AUX_0, 0);
#endif
}
}
#endif // FTDI_BASIC

@ -0,0 +1,128 @@
/*********
* spi.h *
*********/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#pragma once
#if !defined(CLCD_USE_SOFT_SPI)
#include <SPI.h>
#endif
namespace FTDI {
namespace SPI {
#if !defined(CLCD_USE_SOFT_SPI)
extern SPISettings spi_settings;
#endif
uint8_t _soft_spi_xfer (uint8_t val);
void _soft_spi_send (uint8_t val);
void spi_init ();
void spi_ftdi_select ();
void spi_ftdi_deselect ();
void spi_flash_select ();
void spi_flash_deselect ();
inline uint8_t spi_recv() {
#ifdef CLCD_USE_SOFT_SPI
return _soft_spi_xfer(0x00);
#else
return ::SPI.transfer(0x00);
#endif
};
inline void spi_send (uint8_t val) {
#ifdef CLCD_USE_SOFT_SPI
_soft_spi_send(val);
#else
::SPI.transfer(val);
#endif
};
inline void spi_write_8 (uint8_t val) {spi_send(val);};
inline uint8_t spi_read_8 () {return spi_recv();};
namespace least_significant_byte_first {
inline void spi_write_16 (uint16_t val) {spi_send(val >> 0);
spi_send(val >> 8);};
inline void spi_write_32 (uint32_t val) {spi_send(val >> 0);
spi_send(val >> 8);
spi_send(val >> 16);
spi_send(val >> 24);};
inline uint8_t spi_read_8 () {return spi_recv();};
inline uint16_t spi_read_16 () {return (((uint16_t) spi_recv()) << 0) |
(((uint16_t) spi_recv()) << 8);};
inline uint32_t spi_read_32 () {return (((uint32_t) spi_recv()) << 0) |
(((uint32_t) spi_recv()) << 8) |
(((uint32_t) spi_recv()) << 16) |
(((uint32_t) spi_recv()) << 24);};
}
namespace most_significant_byte_first {
inline void spi_write_16 (uint16_t val) {spi_send(val >> 8);
spi_send(val >> 0);};
inline void spi_write_24 (uint32_t val) {spi_send(val >> 16);
spi_send(val >> 8);
spi_send(val >> 0);};
inline void spi_write_32 (uint32_t val) {spi_send(val >> 24);
spi_send(val >> 16);
spi_send(val >> 8);
spi_send(val >> 0);};
inline uint16_t spi_read_16 () {return (((uint16_t) spi_recv()) << 8) |
(((uint16_t) spi_recv()) << 0);};
inline uint32_t spi_read_32 () {return (((uint32_t) spi_recv()) << 24) |
(((uint32_t) spi_recv()) << 16) |
(((uint32_t) spi_recv()) << 8) |
(((uint32_t) spi_recv()) << 0);};
}
inline uint8_t ram_write(const uint8_t *p) {return *p;}
inline uint8_t pgm_write(const uint8_t *p) {return pgm_read_byte(p);}
typedef uint8_t (*bulk_write_op)(const uint8_t*);
// Generic template for function for writing multiple bytes, plus padding bytes.
// The template parameter op is an inlineable function which is applied to each byte.
template<bulk_write_op byte_op>
void spi_write_bulk(const void *data, uint16_t len, uint8_t padding) {
const uint8_t* p = (const uint8_t *)data;
while (len--) spi_send(byte_op(p++));
while (padding--) spi_send(0);
}
template<bulk_write_op byte_op>
void spi_write_bulk(const void *data, uint16_t len) {
const uint8_t* p = (const uint8_t *)data;
while (len--) spi_send(byte_op(p++));
}
void spi_read_bulk( void *data, uint16_t len);
bool spi_verify_bulk(const void *data, uint16_t len);
void ftdi_reset(void);
void test_pulse(void);
}
}

@ -0,0 +1,222 @@
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
#include "../config.h"
#ifdef __MARLIN_FIRMWARE__
// Marlin will define the I/O functions for us
#if ENABLED(LULZBOT_TOUCH_UI)
#define FTDI_BASIC
#define FTDI_EXTENDED
#endif
#else // !__MARLIN_FIRMWARE__
#include "Arduino.h"
#if !defined(CLCD_USE_SOFT_SPI)
#include "SPI.h"
#endif
namespace fast_io {
template<typename port_t,uint8_t bits>
struct port_pin {
typedef port_t port;
static inline void set_high() {port::port() = (port::port() | bits);}
static inline void set_low() {port::port() = (port::port() & (~bits));}
static inline void set_input() {port::ddr() = (port::ddr() & (~bits));}
static inline void set_input_pullup() {set_input(); set_high();}
static inline void set_output() {port::ddr() = (port::ddr() | bits);}
static inline uint8_t read() {return port::pin() & bits;}
static inline void write(bool v) {if (v) set_high(); else set_low();}
};
#define MAKE_AVR_PORT_PINS(ID) \
struct port_##ID { \
static volatile uint8_t &pin() {return PIN##ID;}; \
static volatile uint8_t &port() {return PORT##ID;}; \
static volatile uint8_t &ddr() {return DDR##ID;}; \
}; \
typedef port_pin<port_##ID, 0b00000001> AVR_##ID##0; \
typedef port_pin<port_##ID, 0b00000010> AVR_##ID##1; \
typedef port_pin<port_##ID, 0b00000100> AVR_##ID##2; \
typedef port_pin<port_##ID, 0b00001000> AVR_##ID##3; \
typedef port_pin<port_##ID, 0b00010000> AVR_##ID##4; \
typedef port_pin<port_##ID, 0b00100000> AVR_##ID##5; \
typedef port_pin<port_##ID, 0b01000000> AVR_##ID##6; \
typedef port_pin<port_##ID, 0b10000000> AVR_##ID##7;
#ifdef PORTA
MAKE_AVR_PORT_PINS(A);
#endif
#ifdef PORTB
MAKE_AVR_PORT_PINS(B);
#endif
#ifdef PORTC
MAKE_AVR_PORT_PINS(C);
#endif
#ifdef PORTD
MAKE_AVR_PORT_PINS(D);
#endif
#ifdef PORTE
MAKE_AVR_PORT_PINS(E);
#endif
#ifdef PORTF
MAKE_AVR_PORT_PINS(F);
#endif
#ifdef PORTG
MAKE_AVR_PORT_PINS(G);
#endif
#ifdef PORTH
MAKE_AVR_PORT_PINS(H);
#endif
#ifdef PORTJ
MAKE_AVR_PORT_PINS(J);
#endif
#ifdef PORTK
MAKE_AVR_PORT_PINS(K);
#endif
#ifdef PORTL
MAKE_AVR_PORT_PINS(L);
#endif
#ifdef PORTQ
MAKE_AVR_PORT_PINS(Q);
#endif
#ifdef PORTR
MAKE_AVR_PORT_PINS(R);
#endif
#undef MAKE_AVR_PORT_PINS
template<uint8_t p>
struct arduino_digital_pin {
static constexpr uint8_t pin = p;
static inline void set_high() {digitalWrite(p, HIGH);}
static inline void set_low() {digitalWrite(p, LOW);}
static inline void set_input() {pinMode(p, INPUT);}
static inline void set_input_pullup() {pinMode(p, INPUT_PULLUP);}
static inline void set_output() {pinMode(p, OUTPUT);}
static inline uint8_t read() {return digitalRead(p);}
static inline void write(bool v) {digitalWrite(p, v ? HIGH : LOW);}
};
#define MAKE_ARDUINO_PINS(ID) typedef arduino_digital_pin<ID> ARDUINO_DIGITAL_##ID;
MAKE_ARDUINO_PINS( 0);
MAKE_ARDUINO_PINS( 1);
MAKE_ARDUINO_PINS( 2);
MAKE_ARDUINO_PINS( 3);
MAKE_ARDUINO_PINS( 4);
MAKE_ARDUINO_PINS( 5);
MAKE_ARDUINO_PINS( 6);
MAKE_ARDUINO_PINS( 7);
MAKE_ARDUINO_PINS( 8);
MAKE_ARDUINO_PINS( 9);
MAKE_ARDUINO_PINS(10);
MAKE_ARDUINO_PINS(11);
MAKE_ARDUINO_PINS(12);
MAKE_ARDUINO_PINS(13);
MAKE_ARDUINO_PINS(14);
MAKE_ARDUINO_PINS(15);
MAKE_ARDUINO_PINS(16);
MAKE_ARDUINO_PINS(17);
MAKE_ARDUINO_PINS(18);
MAKE_ARDUINO_PINS(19);
MAKE_ARDUINO_PINS(10);
MAKE_ARDUINO_PINS(21);
MAKE_ARDUINO_PINS(22);
MAKE_ARDUINO_PINS(23);
MAKE_ARDUINO_PINS(24);
MAKE_ARDUINO_PINS(25);
MAKE_ARDUINO_PINS(26);
MAKE_ARDUINO_PINS(27);
MAKE_ARDUINO_PINS(28);
MAKE_ARDUINO_PINS(29);
MAKE_ARDUINO_PINS(30);
MAKE_ARDUINO_PINS(31);
MAKE_ARDUINO_PINS(32);
MAKE_ARDUINO_PINS(33);
MAKE_ARDUINO_PINS(34);
MAKE_ARDUINO_PINS(35);
MAKE_ARDUINO_PINS(36);
MAKE_ARDUINO_PINS(37);
MAKE_ARDUINO_PINS(38);
MAKE_ARDUINO_PINS(39);
MAKE_ARDUINO_PINS(40);
MAKE_ARDUINO_PINS(41);
MAKE_ARDUINO_PINS(42);
MAKE_ARDUINO_PINS(43);
MAKE_ARDUINO_PINS(44);
MAKE_ARDUINO_PINS(45);
MAKE_ARDUINO_PINS(46);
MAKE_ARDUINO_PINS(47);
MAKE_ARDUINO_PINS(48);
MAKE_ARDUINO_PINS(49);
MAKE_ARDUINO_PINS(50);
MAKE_ARDUINO_PINS(51);
MAKE_ARDUINO_PINS(52);
MAKE_ARDUINO_PINS(53);
#undef MAKE_ARDUINO_PINS
} // namespace fast_io
#define SET_INPUT(pin) fast_io::pin::set_input()
#define SET_INPUT_PULLUP(pin) fast_io::pin::set_input(); fast_io::pin::set_high()
#define SET_OUTPUT(pin) fast_io::pin::set_output()
#define READ(pin) fast_io::pin::read()
#define WRITE(pin, value) fast_io::pin::write(value)
#ifndef pgm_read_word_far
#define pgm_read_word_far pgm_read_word
#endif
#ifndef pgm_read_dword_far
#define pgm_read_dword_far pgm_read_dword
#endif
#ifndef pgm_read_ptr_far
#define pgm_read_ptr_far pgm_read_ptr
#endif
#define SERIAL_ECHO_START()
#define SERIAL_ECHOLNPGM(str) Serial.println(F(str))
#define SERIAL_ECHOPGM(str) Serial.print(F(str))
#define SERIAL_ECHOLNPAIR(str, val) {Serial.print(F(str)); Serial.println(val);}
#define SERIAL_ECHOPAIR(str, val) {Serial.print(F(str)); Serial.print(val);}
#define safe_delay delay
// Define macros for compatibility
#define _CAT(a, ...) a ## __VA_ARGS__
#define SWITCH_ENABLED_ 1
#define ENABLED(b) _CAT(SWITCH_ENABLED_, b)
#define DISABLED(b) !ENABLED(b)
#define ANY(A,B) ENABLED(A) || ENABLED(B)
// Remove compiler warning on an unused variable
#ifndef UNUSED
#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
#define UNUSED(X) (void)X
#else
#define UNUSED(x) ((void)(x))
#endif
#endif
#endif // !__MARLIN_FIRMWARE__

@ -0,0 +1,49 @@
/*****************
* bitmap_info.h *
*****************/
/****************************************************************************
* Written By Marcio Teixeira 2019 - 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/>. *
****************************************************************************/
#pragma once
#ifndef FORCEDINLINE
#define FORCEDINLINE __attribute__((always_inline)) inline
#endif
namespace FTDI {
// The following functions *must* be inlined since we are relying on the compiler to do
// substitution of the constants from the data structure rather than actually storing
// it in PROGMEM (which would fail, since we are not using pgm_read to read them).
// Plus, by inlining, all the equations are evaluated at compile-time as everything
// should be a constant.
typedef struct {
const uint8_t format;
const uint16_t linestride;
const uint8_t filter;
const uint8_t wrapx;
const uint8_t wrapy;
const uint32_t RAMG_offset;
const uint16_t width;
const uint16_t height;
} bitmap_info_t;
FORCEDINLINE uint32_t BITMAP_SOURCE (const bitmap_info_t& info) {return BITMAP_SOURCE (ftdi_memory_map::RAM_G + info.RAMG_offset);};
FORCEDINLINE uint32_t BITMAP_LAYOUT (const bitmap_info_t& info) {return BITMAP_LAYOUT (info.format, info.linestride, info.height);};
FORCEDINLINE uint32_t BITMAP_SIZE (const bitmap_info_t& info) {return BITMAP_SIZE (info.filter, info.wrapx, info.wrapy, info.width, info.height);}
}

@ -0,0 +1,29 @@
/*************************
* command_processor.cpp *
*************************/
/****************************************************************************
* Written By Marcio Teixeira 2018 *
* *
* 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/>. *
****************************************************************************/
#include "ftdi_extended.h"
#ifdef FTDI_EXTENDED
CommandProcessor::btn_style_func_t *CommandProcessor::_btn_style_callback = CommandProcessor::default_button_style_func;
bool CommandProcessor::is_tracking = false;
#endif // FTDI_EXTENDED

@ -0,0 +1,347 @@
/***********************
* command_processor.h *
***********************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
typedef struct {
uint32_t bg;
uint32_t grad;
uint32_t fg;
uint32_t rgb;
} btn_colors;
/**************************** Enhanced Command Processor **************************/
/* The CommandProcessor class wraps the CommandFifo with several features to make
* defining user interfaces much easier.
*
* - Implements chaining on all methods
* - Automatically adds text to button, toggle, text and keys.
* - Constrains all widgets to fit inside a box for ease of layout.
* - Font size is specified using a chained modifier.
* - Option argument is given the default OPT_3D value.
*/
class CommandProcessor : public CLCD::CommandFifo {
public:
static constexpr uint8_t STYLE_DISABLED = 0x80;
private:
static bool default_button_style_func(CommandProcessor &, uint8_t tag, uint8_t & /*style*/, uint16_t &options, bool) {
if (tag != 0 && FTDI::EventLoop::get_pressed_tag() == tag) {
options = FTDI::OPT_FLAT;
}
return false;
}
typedef bool btn_style_func_t(CommandProcessor &cmd, uint8_t tag, uint8_t &style, uint16_t &options, bool post);
static btn_style_func_t *_btn_style_callback;
static bool is_tracking;
int8_t _font = 26, _tag = 0;
uint8_t _style = 0;
protected:
// Returns the cannonical thickness of a widget (i.e. the height of a toggle element)
uint16_t widget_thickness() {
CLCD::FontMetrics fm(_font);
return fm.height * 20.0/16;
}
FORCEDINLINE void linear_widget_box(int16_t &x, int16_t &y, int16_t &w, int16_t &h, bool tracker = false) {
const uint16_t th = widget_thickness()/2;
if (w > h) {
x += tracker ? th * 2.5 : th;
y += h/2 - th/2;
w -= tracker ? th * 5.0 : th * 2;
h = th;
} else {
x += w/2 - th/2;
y += tracker ? th * 2.5 : th;
w = th;
h -= tracker ? th * 5.0 : th * 2;
}
}
FORCEDINLINE uint16_t circular_widget_box(int16_t &x, int16_t &y, int16_t &w, int16_t &h) {
const uint16_t r = min(w,h)/2;
x += w/2;
y += h/2;
w = 1;
h = 1;
return r;
}
public:
// Helper method for setting all colors at once
inline CommandProcessor& colors(const btn_colors &colors) {
cmd(FTDI::COLOR_RGB(colors.rgb))
.gradcolor(colors.grad)
.fgcolor(colors.fg)
.bgcolor(colors.bg);
return *this;
}
inline CommandProcessor& bitmap_size(uint8_t filter, uint8_t wrapx, uint8_t wrapy, uint16_t width, uint16_t height) {
cmd(FTDI::BITMAP_SIZE(filter, wrapx, wrapy, width, height));
#if FTDI_API_LEVEL >= 810
if (FTDI::ftdi_chip >= 810)
cmd(FTDI::BITMAP_SIZE_H(width >> 9, height >> 9));
#endif
return *this;
}
inline CommandProcessor& bitmap_layout(uint8_t format, uint16_t linestride, uint16_t height) {
cmd(FTDI::BITMAP_LAYOUT(format, linestride, height));
#if FTDI_API_LEVEL >= 810
if (FTDI::ftdi_chip >= 810)
cmd(FTDI::BITMAP_LAYOUT_H(linestride >> 10, height >> 9));
#endif
return *this;
}
inline CommandProcessor& set_button_style_callback(const btn_style_func_t *func) {
_btn_style_callback = func ? func : default_button_style_func;
return *this;
}
inline CommandProcessor& tag (uint8_t tag) {_tag = tag; cmd(FTDI::TAG(tag)); return *this;}
inline CommandProcessor& font (int16_t font) {_font = font; return *this;}
inline CommandProcessor& enabled (bool enabled) {
if (enabled)
_style &= ~STYLE_DISABLED;
else
_style |= STYLE_DISABLED;
return *this;
}
inline CommandProcessor& style (uint8_t style) {
_style = (_style & STYLE_DISABLED) | style;
return *this;
}
// Wrap all the CommandFifo routines to allow method chaining
inline CommandProcessor& cmd (uint32_t cmd32) {CLCD::CommandFifo::cmd(cmd32); return *this;}
inline CommandProcessor& cmd (void* data, uint16_t len) {CLCD::CommandFifo::cmd(data, len); return *this;}
inline CommandProcessor& execute() {CLCD::CommandFifo::execute(); return *this;}
inline CommandProcessor& fgcolor (uint32_t rgb) {CLCD::CommandFifo::fgcolor(rgb); return *this;}
inline CommandProcessor& bgcolor (uint32_t rgb) {CLCD::CommandFifo::bgcolor(rgb); return *this;}
inline CommandProcessor& gradcolor(uint32_t rgb) {CLCD::CommandFifo::gradcolor(rgb); return *this;}
inline CommandProcessor& snapshot (uint32_t ptr) {CLCD::CommandFifo::snapshot(ptr); return *this;}
inline CommandProcessor& loadimage(uint32_t ptr, uint32_t options)
{CLCD::CommandFifo::loadimage(ptr, options); return *this;}
inline CommandProcessor& sketch (int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t ptr, uint16_t format)
{CLCD::CommandFifo::sketch(x, y, w, h, ptr, format); return *this;}
inline CommandProcessor& screensaver () {CLCD::CommandFifo::screensaver(); return *this;}
#if FTDI_API_LEVEL >= 810
inline CommandProcessor& setbase (uint8_t base) {CLCD::CommandFifo::setbase(base); return *this;}
#endif
inline CommandProcessor& loadidentity () {CLCD::CommandFifo::loadidentity(); return *this;}
inline CommandProcessor& scale (int32_t sx, int32_t sy) {CLCD::CommandFifo::scale(sx,sy); return *this;}
inline CommandProcessor& rotate (int32_t a) {CLCD::CommandFifo::rotate(a); return *this;}
inline CommandProcessor& translate(int32_t tx, int32_t ty) {CLCD::CommandFifo::translate(tx,ty); return *this;}
inline CommandProcessor& setmatrix () {CLCD::CommandFifo::setmatrix(); return *this;}
inline CommandProcessor& stop () {CLCD::CommandFifo::stop(); return *this;}
inline CommandProcessor& memzero (uint32_t ptr, uint32_t size)
{CLCD::CommandFifo::memzero(ptr, size); return *this;}
inline CommandProcessor& memset (uint32_t ptr, uint32_t val, uint32_t size)
{CLCD::CommandFifo::memset(ptr, val, size); return *this;}
inline CommandProcessor& memcpy (uint32_t src, uint32_t dst, uint32_t size)
{CLCD::CommandFifo::memcpy(src, dst, size); return *this;}
inline CommandProcessor& memcrc (uint32_t ptr, uint32_t num, uint32_t result)
{CLCD::CommandFifo::memcrc(ptr, num, result); return *this;}
inline CommandProcessor& memwrite (uint32_t ptr, uint32_t value)
{CLCD::CommandFifo::memwrite(ptr, value); return *this;}
inline CommandProcessor& inflate (uint32_t ptr)
{CLCD::CommandFifo::inflate(ptr); return *this;}
inline CommandProcessor& getptr (uint32_t result)
{CLCD::CommandFifo::getptr(result); return *this;}
inline CommandProcessor& getprops (uint32_t ptr, uint32_t width, uint32_t height)
{CLCD::CommandFifo::getprops(ptr, width, height); return *this;}
#if FTDI_API_LEVEL >= 810
inline CommandProcessor& setbitmap (uint32_t ptr, uint16_t fmt, uint16_t w, uint16_t h)
{CLCD::CommandFifo::setbitmap(ptr,fmt,w,h); return *this;}
inline CommandProcessor& snapshot2 (uint32_t fmt, uint32_t ptr, int16_t x, int16_t y, uint16_t w, uint16_t h)
{CLCD::CommandFifo::snapshot2(fmt,ptr,x,y,w,h); return *this;}
inline CommandProcessor& mediafifo (uint32_t p, uint32_t s) {CLCD::CommandFifo::mediafifo(p, s); return *this;}
inline CommandProcessor& playvideo(uint32_t options) {CLCD::CommandFifo::playvideo(options); return *this;}
#endif
inline CommandProcessor& gradient(int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1)
{CLCD::CommandFifo::gradient(x0,y0,rgb0,x1,y1,rgb1); return *this;}
inline CommandProcessor& rectangle(int16_t x, int16_t y, int16_t w, int16_t h) {
using namespace FTDI;
CLCD::CommandFifo::cmd(BEGIN(RECTS));
CLCD::CommandFifo::cmd(VERTEX2F(x*16,y*16));
CLCD::CommandFifo::cmd(VERTEX2F((x+w)*16,(y+h)*16));
return *this;
}
template<typename T>
FORCEDINLINE CommandProcessor& toggle(int16_t x, int16_t y, int16_t w, int16_t h, T text, bool state, uint16_t options = FTDI::OPT_3D) {
CLCD::FontMetrics fm(_font);
const int16_t widget_h = fm.height * 20.0/16;
//const int16_t outer_bar_r = widget_h / 2;
//const int16_t knob_r = outer_bar_r - 1.5;
// The y coordinate of the toggle is the baseline of the text,
// so we must introduce a fudge factor based on the line height to
// actually center the control.
const int16_t fudge_y = fm.height*5/16;
CLCD::CommandFifo::toggle(x + h/2, y + h/2 - widget_h/2 + fudge_y, w - h, _font, options, state);
CLCD::CommandFifo::str(text);
return *this;
}
// Contrained drawing routines. These constrain the widget inside a box for easier layout.
// The FORCEDINLINE ensures that the code is inlined so that all the math is done at compile time.
FORCEDINLINE CommandProcessor& track_linear(int16_t x, int16_t y, int16_t w, int16_t h, int16_t tag) {
linear_widget_box(x, y, w, h, true);
CLCD::CommandFifo::track(x, y, w, h, tag);
is_tracking = true;
return *this;
}
FORCEDINLINE CommandProcessor& track_circular(int16_t x, int16_t y, int16_t w, int16_t h, int16_t tag) {
circular_widget_box(x,y, w, h);
CLCD::CommandFifo::track(x, y, w, h, tag);
is_tracking = true;
return *this;
}
uint8_t track_tag (uint16_t &value) {
if (is_tracking) {
if (FTDI::EventLoop::is_touch_held()) {
return CLCD::get_tracker(value);
} else {
CLCD::CommandFifo::track(0, 0, 0, 0, 0);
CLCD::CommandFifo::execute();
is_tracking = false;
}
}
return 0;
}
FORCEDINLINE CommandProcessor& clock(int16_t x, int16_t y, int16_t w, int16_t h, int16_t hr, int16_t m, int16_t s, int16_t ms, uint16_t options = FTDI::OPT_3D) {
const uint16_t r = circular_widget_box(x, y, w, h);
CLCD::CommandFifo::clock(x, y, r, options, hr, m, s, ms);
return *this;
}
FORCEDINLINE CommandProcessor& gauge(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t major, uint16_t minor, uint16_t val, uint16_t range, uint16_t options = FTDI::OPT_3D) {
const uint16_t r = circular_widget_box(x, y, w, h);
CLCD::CommandFifo::gauge(x, y, r, options, major, minor, val, range);
return *this;
}
FORCEDINLINE CommandProcessor& dial(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t options = FTDI::OPT_3D) {
const uint16_t r = circular_widget_box(x, y, w, h);
CLCD::CommandFifo::dial(x, y, r, options, val);
return *this;
}
FORCEDINLINE CommandProcessor& slider(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t range, uint16_t options = FTDI::OPT_3D) {
linear_widget_box(x, y, w, h);
CLCD::CommandFifo::slider(x, y, w, h, options, val, range);
return *this;
}
FORCEDINLINE CommandProcessor& progress(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t range, uint16_t options = FTDI::OPT_3D) {
linear_widget_box(x, y, w, h);
CLCD::CommandFifo::progress(x, y, w, h, options, val, range);
return *this;
}
FORCEDINLINE CommandProcessor& scrollbar(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t size, uint16_t range, uint16_t options = 0) {
linear_widget_box(x, y, w, h);
CLCD::CommandFifo::scrollbar(x, y, w, h, options, val, size, range);
return *this;
}
CommandProcessor& number(int16_t x, int16_t y, int16_t w, int16_t h, int32_t n, uint16_t options = FTDI::OPT_CENTER) {
using namespace FTDI;
CLCD::CommandFifo::number(
x + ((options & OPT_CENTERX) ? w/2 : ((options & OPT_RIGHTX) ? w : 0)),
y + ((options & OPT_CENTERY) ? h/2 : h),
_font, options, n);
return *this;
}
template<typename T> FORCEDINLINE
CommandProcessor& text(int16_t x, int16_t y, int16_t w, int16_t h, T text, uint16_t options = FTDI::OPT_CENTER) {
using namespace FTDI;
CLCD::CommandFifo::text(
x + ((options & OPT_CENTERX) ? w/2 : ((options & OPT_RIGHTX) ? w : 0)),
y + ((options & OPT_CENTERY) ? h/2 : h),
_font, options);
CLCD::CommandFifo::str(text);
return *this;
}
FORCEDINLINE CommandProcessor& icon(int16_t x, int16_t y, int16_t w, int16_t h, const FTDI::bitmap_info_t& info, const float scale = 1) {
using namespace FTDI;
cmd(BEGIN(BITMAPS));
if (scale != 1) {
cmd(BITMAP_TRANSFORM_A(uint32_t(float(256)/scale)));
cmd(BITMAP_TRANSFORM_E(uint32_t(float(256)/scale)));
}
cmd(BITMAP_SIZE(info.filter, info.wrapx, info.wrapy, info.width*scale, info.height*scale));
cmd(VERTEX2F((x + w/2 - info.width*scale/2)*16, (y + h/2 - info.height*scale/2)*16));
if (scale != 1) {
cmd(BITMAP_TRANSFORM_A(256));
cmd(BITMAP_TRANSFORM_E(256));
}
return *this;
}
template<typename T>
CommandProcessor& button(int16_t x, int16_t y, int16_t w, int16_t h, T text, uint16_t options = FTDI::OPT_3D) {
using namespace FTDI;
bool styleModified = false;
if (_btn_style_callback) styleModified = _btn_style_callback(*this, _tag, _style, options, false);
CLCD::CommandFifo::button(x, y, w, h, _font, options);
CLCD::CommandFifo::str(text);
if (_btn_style_callback && styleModified) _btn_style_callback(*this, _tag, _style, options, true);
return *this;
}
template<typename T>
CommandProcessor& keys(int16_t x, int16_t y, int16_t w, int16_t h, T keys, uint16_t options = FTDI::OPT_3D) {
CLCD::CommandFifo::keys(x, y, w, h, _font, options);
CLCD::CommandFifo::str(keys);
return *this;
}
FORCEDINLINE CommandProcessor& spinner(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t style = 0, uint16_t scale = 0) {
circular_widget_box(x, y, w, h);
CLCD::CommandFifo::spinner(x, y, style, scale);
return *this;
}
};

@ -0,0 +1,176 @@
/****************
* dl_cache.cpp *
****************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#include "ftdi_extended.h"
#ifdef FTDI_EXTENDED
/* The Display List Cache mechanism stores the display list corresponding
* to a menu into RAM_G so that on subsequent calls drawing the menu does
* not require as much SPI traffic.
*
* 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
* ...
*/
#define DL_CACHE_START MAP::RAM_G_SIZE - 0xFFFF
#define DL_FREE_ADDR DL_CACHE_START + DL_CACHE_SLOTS * 8
using namespace FTDI;
// The init function ensures all cache locations are marked as empty
void DLCache::init() {
CLCD::mem_write_32(DL_FREE_ADDR, DL_FREE_ADDR + 4);
for(uint8_t slot = 0; slot < DL_CACHE_SLOTS; slot++) {
save_slot(slot, 0, 0);
}
}
bool DLCache::has_data() {
return dl_size != 0;
}
bool DLCache::wait_until_idle() {
const unsigned long startTime = millis();
do {
if ((millis() - startTime) > 250) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM("Timeout on DL_Cache::Wait_Until_Idle()");
CLCD::CommandFifo::reset();
return false;
}
#ifdef __MARLIN_FIRMWARE__
ExtUI::yield();
#endif
} while (CLCD::CommandFifo::is_processing());
return true;
}
/* 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 DLCache::store(uint32_t num_bytes /* = 0*/) {
CLCD::CommandFifo cmd;
// Execute any commands already in the FIFO
cmd.execute();
if (!wait_until_idle())
return false;
// Figure out how long the display list is
uint32_t new_dl_size = CLCD::mem_read_32(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 = CLCD::mem_read_32(DL_FREE_ADDR);
free_space = MAP::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_size > free_space) {
// Not enough memory to cache the display list.
#ifdef UI_FRAMEWORK_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOPAIR("Not enough space in GRAM to cache display list, free space: ", free_space);
SERIAL_ECHOLNPAIR(" Required: ", dl_size);
#endif
return false;
} else {
#ifdef UI_FRAMEWORK_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOPAIR("Saving DL to RAMG cache, bytes: ", dl_size);
SERIAL_ECHOLNPAIR(" Free space: ", free_space);
#endif
cmd.memcpy(dl_addr, MAP::RAM_DL, dl_size);
cmd.execute();
save_slot(dl_slot, dl_addr, dl_size);
if (dl_alloc > 0) {
// If we allocated space dynamically, then adjust dl_free_addr.
CLCD::mem_write_32(DL_FREE_ADDR, dl_addr + dl_alloc);
}
return true;
}
}
void DLCache::save_slot(uint8_t dl_slot, uint32_t dl_addr, uint32_t dl_size) {
CLCD::mem_write_32(DL_CACHE_START + dl_slot * 8 + 0, dl_addr);
CLCD::mem_write_32(DL_CACHE_START + dl_slot * 8 + 4, dl_size);
}
void DLCache::load_slot() {
dl_addr = CLCD::mem_read_32(DL_CACHE_START + dl_slot * 8 + 0);
dl_size = CLCD::mem_read_32(DL_CACHE_START + dl_slot * 8 + 4);
}
void DLCache::append() {
CLCD::CommandFifo cmd;
cmd.append(dl_addr, dl_size);
#ifdef UI_FRAMEWORK_DEBUG
cmd.execute();
wait_until_idle();
SERIAL_ECHO_START();
SERIAL_ECHOPAIR("Appending to DL from RAMG cache, bytes: ", dl_size);
SERIAL_ECHOLNPAIR(" REG_CMD_DL: ", CLCD::mem_read_32(REG::CMD_DL));
#endif
}
#endif // FTDI_EXTENDED

@ -0,0 +1,69 @@
/**************
* dl_cache.h *
**************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
/******************* DISPLAY LIST CACHE MANAGEMENT ************************/
/* The Display List Cache mechanism stores the display list corresponding
* to a menu into RAM_G so that on subsequent calls drawing the menu does
* not require as much SPI traffic. Dynamic content, such as indicators,
* should not be cached.
*
* The DLCache can be used like so:
*
* void some_function() {
* DLCache dlcache(UNIQUE_ID);
*
* if (dlcache.hasData()) {
* dlcache.append();
* } else {
* // Add stuff to the DL
* dlcache.store();
* }
*/
class DLCache {
private:
typedef FTDI::ftdi_registers REG;
typedef FTDI::ftdi_memory_map MAP;
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);
bool wait_until_idle();
public:
static void init();
DLCache(uint8_t slot) {
dl_slot = slot;
load_slot();
}
bool has_data();
bool store(uint32_t num_bytes = 0);
void append();
};
#define DL_CACHE_SLOTS 250

@ -0,0 +1,230 @@
/******************
* event_loop.cpp *
******************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#include "ftdi_extended.h"
#ifdef FTDI_EXTENDED
using namespace FTDI;
enum {
UNPRESSED = 0x00
};
tiny_timer_t touch_timer;
UIData::flags_t UIData::flags;
uint8_t pressed_tag = UNPRESSED;
uint8_t UIData::get_persistent_data_mask() {
// A bit mask for flags that should be stored to the EEPROM.
// Others are considered temporarily values that need not be
// saved.
constexpr flags_t persistent_flags = {
bits: {
touch_start_sound: true,
touch_end_sound: true,
touch_repeat_sound: true,
show_animations: true
}
};
return persistent_flags.value;
}
void UIData::reset_persistent_data() {
// Default values for persistent data
constexpr flags_t default_flags = {
bits: {
touch_start_sound: true,
touch_end_sound: true,
touch_repeat_sound: true,
show_animations: true,
touch_debouncing: false,
ignore_unpress: false
}
};
flags.value = default_flags.value;
}
uint8_t UIData::get_persistent_data() {
return flags.value & get_persistent_data_mask();
}
void UIData::set_persistent_data(uint8_t value) {
flags.value = value & get_persistent_data_mask();
}
void UIData::enable_touch_sounds(bool enabled) {
UIData::flags.bits.touch_start_sound = enabled;
UIData::flags.bits.touch_end_sound = enabled;
UIData::flags.bits.touch_repeat_sound = enabled;
}
bool UIData::touch_sounds_enabled() {
return UIData::flags.bits.touch_start_sound || UIData::flags.bits.touch_end_sound || UIData::flags.bits.touch_repeat_sound;
}
void UIData::enable_animations(bool enabled) {
UIData::flags.bits.show_animations = enabled;
}
bool UIData::animations_enabled() {
return UIData::flags.bits.show_animations;
}
namespace FTDI {
uint8_t EventLoop::get_pressed_tag() {
return pressed_tag;
}
bool EventLoop::is_touch_held() {
return pressed_tag != 0;
}
/**
* process_events(): Process events from the touch panel.
*
* This function consists of a state machine that accomplishes the following:
*
* - Reads the tag register from the touch panel
* - Dispatches onTouchStart and onTouchEnd events to the active screen.
* - Handles auto-repetition by sending onTouchHeld to the active screen periodically.
* - Plays touch feedback "click" sounds when appropriate.
* - Performs debouncing to supress spurious touch events.
*
*/
void EventLoop::process_events() {
// If the LCD is processing commands, don't check
// for tags since they may be changing and could
// cause spurious events.
if (!touch_timer.elapsed(TOUCH_UPDATE_INTERVAL) || CLCD::CommandFifo::is_processing()) {
return;
}
const uint8_t tag = CLCD::get_tag();
switch (pressed_tag) {
case UNPRESSED:
if (tag != 0) {
#ifdef UI_FRAMEWORK_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("Touch start: ", tag);
#endif
pressed_tag = tag;
current_screen.onRefresh();
// When the user taps on a button, activate the onTouchStart handler
const uint8_t lastScreen = current_screen.getScreen();
if (current_screen.onTouchStart(tag)) {
touch_timer.start();
if (UIData::flags.bits.touch_start_sound) sound.play(press_sound);
}
if (lastScreen != current_screen.getScreen()) {
// In the case in which a touch event triggered a new screen to be
// drawn, we don't issue a touchEnd since it would be sent to the
// wrong screen.
UIData::flags.bits.ignore_unpress = true;
} else {
UIData::flags.bits.ignore_unpress = false;
}
} else {
touch_timer.start();
}
break;
default: // PRESSED
if (!UIData::flags.bits.touch_debouncing) {
if (tag == pressed_tag) {
// The user is holding down a button.
if (touch_timer.elapsed(1000 / TOUCH_REPEATS_PER_SECOND) && current_screen.onTouchHeld(tag)) {
current_screen.onRefresh();
if (UIData::flags.bits.touch_repeat_sound) sound.play(repeat_sound);
touch_timer.start();
}
}
else if (tag == 0) {
touch_timer.start();
UIData::flags.bits.touch_debouncing = true;
}
}
else {
// Debouncing...
if (tag == pressed_tag) {
// If while debouncing, we detect a press, then cancel debouncing.
UIData::flags.bits.touch_debouncing = false;
}
else if (touch_timer.elapsed(DEBOUNCE_PERIOD)) {
UIData::flags.bits.touch_debouncing = false;
if (UIData::flags.bits.ignore_unpress) {
UIData::flags.bits.ignore_unpress = false;
pressed_tag = UNPRESSED;
break;
}
if (UIData::flags.bits.touch_end_sound) sound.play(unpress_sound);
#ifdef UI_FRAMEWORK_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("Touch end: ", tag);
#endif
const uint8_t saved_pressed_tag = pressed_tag;
pressed_tag = UNPRESSED;
current_screen.onTouchEnd(saved_pressed_tag);
current_screen.onRefresh();
}
}
break;
} // switch (pressed_tag)
} // processEvents()
void EventLoop::setup() {
CLCD::init();
DLCache::init();
UIData::reset_persistent_data();
current_screen.start();
}
void EventLoop::loop() {
sound.onIdle();
/**
* Guard against re-entry of UI methods, which can
* crash. Re-entry can happen because some functions
* (e.g. planner.synchronize) call idle().
*/
if (!UIData::flags.bits.prevent_reentry) {
UIData::flags.bits.prevent_reentry = true;
current_screen.onIdle();
process_events();
UIData::flags.bits.prevent_reentry = false;
}
}
} // namespace FTDI
#endif // FTDI_EXTENDED

@ -0,0 +1,74 @@
/****************
* event_loop.h *
****************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#pragma once
#define STATUS_UPDATE_INTERVAL 1000
#define TOUCH_UPDATE_INTERVAL 50
#define TOUCH_REPEATS_PER_SECOND 4
#define DEBOUNCE_PERIOD 150
class UIData {
private:
typedef union {
struct {
uint8_t touch_start_sound : 1;
uint8_t touch_end_sound : 1;
uint8_t touch_repeat_sound : 1;
uint8_t show_animations : 1;
uint8_t touch_debouncing : 1;
uint8_t ignore_unpress : 1;
uint8_t prevent_reentry : 1;
} bits;
uint8_t value;
} flags_t;
public:
static flags_t flags;
static uint8_t get_persistent_data_mask();
static uint8_t get_persistent_data();
static void set_persistent_data(uint8_t value);
static void reset_persistent_data();
static void enable_touch_sounds(bool enabled);
static bool touch_sounds_enabled();
static void enable_animations(bool enabled);
static bool animations_enabled();
};
namespace FTDI {
class EventLoop {
private:
static constexpr FTDI::effect_t press_sound = FTDI::CHACK;
static constexpr FTDI::effect_t repeat_sound = FTDI::CHACK;
static constexpr FTDI::effect_t unpress_sound = FTDI::POP;
static void process_events();
public:
static void setup();
static void loop();
static uint8_t get_pressed_tag();
static bool is_touch_held();
};
}

@ -0,0 +1,45 @@
/*******************
* ftdi_extended.h *
*******************/
/****************************************************************************
* Written By Mark Pelletier 2019 - Aleph Objects, Inc. *
* Written By Marcio Teixeira 201( - 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/>. *
****************************************************************************/
#pragma once
#include "../compat.h"
#include "../basic/ftdi_basic.h"
#if !defined(__MARLIN_FIRMWARE__)
#define FTDI_EXTENDED
#endif
#ifdef FTDI_EXTENDED
#include "rgb_t.h"
#include "bitmap_info.h"
#include "tiny_timer.h"
#include "grid_layout.h"
#include "dl_cache.h"
#include "screen_types.h"
#include "event_loop.h"
#include "command_processor.h"
#include "sound_player.h"
#include "sound_list.h"
#include "polygon.h"
#include "text_box.h"
#endif

@ -0,0 +1,98 @@
/*****************
* grid_layout.h *
*****************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
/* The grid layout macros allow buttons to be arranged on a grid so
* that their locations become independent of the display size. The
* layout model is similar to that of HTML TABLEs.
*
* These macros are meant to be evaluated into constants at compile
* time, so resolution independence can be as efficient as using
* hard-coded coordinates.
*/
// Margin defines the margin (in pixels) on each side of a button in
// the layout
#ifdef TOUCH_UI_800x480
#define MARGIN_L 5
#define MARGIN_R 5
#define MARGIN_T 5
#define MARGIN_B 5
#define MARGIN_DEFAULT 5
#else
#define MARGIN_L 3
#define MARGIN_R 3
#define MARGIN_T 3
#define MARGIN_B 3
#define MARGIN_DEFAULT 3
#endif
// EDGE_R adds some black space on the right edge of the display
// This shifts some of the screens left to visually center them.
#define EDGE_R 0
// GRID_X and GRID_Y computes the positions of the divisions on
// the layout grid.
#define GRID_X(x) ((x)*(FTDI::display_width-EDGE_R)/GRID_COLS)
#define GRID_Y(y) ((y)*FTDI::display_height/GRID_ROWS)
// BTN_X, BTN_Y, BTN_W and BTN_X returns the top-left and width
// and height of a button, taking into account the button margins.
#define BTN_X(x) (GRID_X((x)-1) + MARGIN_L)
#define BTN_Y(y) (GRID_Y((y)-1) + MARGIN_T)
#define BTN_W(w) (GRID_X(w) - MARGIN_L - MARGIN_R)
#define BTN_H(h) (GRID_Y(h) - MARGIN_T - MARGIN_B)
// Abbreviations for common phrases, to allow a button to be
// defined in one line of source.
#define BTN_POS(x,y) BTN_X(x), BTN_Y(y)
#define BTN_SIZE(w,h) BTN_W(w), BTN_H(h)
// Draw a reference grid for ease of spacing out widgets.
#define DRAW_LAYOUT_GRID \
{ \
cmd.cmd(LINE_WIDTH(4)); \
for(int i = 1; i <= GRID_COLS; i++) { \
cmd.cmd(BEGIN(LINES)); \
cmd.cmd(VERTEX2F(GRID_X(i) *16, 0 *16)); \
cmd.cmd(VERTEX2F(GRID_X(i) *16, FTDI::display_height *16)); \
} \
for(int i = 1; i < GRID_ROWS; i++) { \
cmd.cmd(BEGIN(LINES)); \
cmd.cmd(VERTEX2F(0 *16, GRID_Y(i) *16)); \
cmd.cmd(VERTEX2F(FTDI::display_width *16, GRID_Y(i) *16)); \
} \
cmd.cmd(LINE_WIDTH(16)); \
}
namespace FTDI {
#ifdef TOUCH_UI_PORTRAIT
constexpr uint16_t display_width = Vsize;
constexpr uint16_t display_height = Hsize;
#else
constexpr uint16_t display_width = Hsize;
constexpr uint16_t display_height = Vsize;
#endif
}

@ -0,0 +1,96 @@
/*************
* polygon.h *
*************/
/****************************************************************************
* Written By Marcio Teixeira 2019 - 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/>. *
****************************************************************************/
#pragma once
/**
* The Polygon class helps drawing filled or stroked polygons on the FTDI EVE:
*
* CommandProcessor cmd;
* cmd.cmd(COLOR_RGB(0x00FF00));
*
* Polygon p(cmd);
* p.begin_fill();
* p.begin_loop();
* p(10,10);
* p(20,10);
* p(20,20);
* p(10,20);
* p.end_loop();
* p.begin_loop();
* ... // Additional closed paths
* p.end_loop();
* ...
* p.end_fill();
*
* Based on the example from "Applicaton Note AN_334, FT801 Polygon Application":
*
* https://brtchip.com/wp-content/uploads/Support/Documentation/Application_Notes/ICs/EVE/AN_334-FT801_Polygon_Application.pdf
*/
namespace FTDI {
class Polygon {
private:
FTDI::begin_t path_initiator = FTDI::LINE_STRIP;
public:
CommandProcessor &cmd;
Polygon(CommandProcessor &c) : cmd(c) {}
void begin_fill() {
using namespace FTDI;
cmd.cmd(SAVE_CONTEXT());
cmd.cmd(TAG_MASK(0));
cmd.cmd(CLEAR(0,1,0));
cmd.cmd(COLOR_MASK(0,0,0,0));
cmd.cmd(STENCIL_OP(STENCIL_OP_KEEP, STENCIL_OP_INVERT));
cmd.cmd(STENCIL_FUNC(STENCIL_FUNC_ALWAYS, 255, 255));
// Drawing the edge strip along scan lines
// seems to yield the best performance
#ifdef TOUCH_UI_PORTRAIT
path_initiator = EDGE_STRIP_B;
#else
path_initiator = EDGE_STRIP_R;
#endif
}
// Specify a clipping rectangle to paint fewer pixels and reduce rendering time, otherwise all pixels will be painted.
void end_fill(const int16_t x1 = 0, const int16_t y1 = 0, const int16_t x2 = display_width * 16, const int16_t y2 = display_height * 16) {
using namespace FTDI;
cmd.cmd(RESTORE_CONTEXT());
cmd.cmd(SAVE_CONTEXT());
cmd.cmd(STENCIL_FUNC(STENCIL_FUNC_NOTEQUAL, 0, 255));
cmd.cmd(BEGIN(RECTS));
cmd.cmd(VERTEX2F(x1, y1));
cmd.cmd(VERTEX2F(x2, y2));
cmd.cmd(RESTORE_CONTEXT());
}
void begin_stroke() {path_initiator = FTDI::LINE_STRIP;}
void begin_loop() {cmd.cmd(FTDI::BEGIN(path_initiator));}
void end_stroke() {}
void end_loop() {}
void operator()(const uint16_t x, const uint16_t y) {cmd.cmd(FTDI::VERTEX2F(x, y));}
};
}

@ -0,0 +1,44 @@
/***********
* rgb_t.h *
***********/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
struct rgb_t {
union {
struct {
uint8_t b,g,r,a;
};
uint32_t packed;
};
rgb_t() : packed(0) {}
rgb_t(uint32_t rgb) : packed(rgb) {}
rgb_t(uint8_t r, uint8_t g, uint8_t b) : b(b), g(g), r(r), a(0) {}
operator uint32_t() const {return packed;};
static void lerp(float t, const rgb_t a, const rgb_t b, rgb_t &c) {
c.r = a.r + t * (b.r - a.r);
c.g = a.g + t * (b.g - a.g);
c.b = a.b + t * (b.b - a.b);
}
uint8_t luminance() const {return 0.299*r + 0.587*g + 0.114*b;}
};

@ -0,0 +1,106 @@
/******************
* screen_types.h *
******************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#include "ftdi_extended.h"
#ifdef FTDI_EXTENDED
/********************** VIRTUAL DISPATCH DATA TYPE ******************************/
uint8_t ScreenRef::lookupScreen(onRedraw_func_t onRedraw_ptr) {
for(uint8_t type = 0; type < functionTableSize; type++) {
if (GET_METHOD(type, onRedraw) == onRedraw_ptr) {
return type;
}
}
#ifdef UI_FRAMEWORK_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOPAIR("Screen not found: ", (uintptr_t) onRedraw_ptr);
#endif
return 0xFF;
}
void ScreenRef::setScreen(onRedraw_func_t onRedraw_ptr) {
uint8_t type = lookupScreen(onRedraw_ptr);
if (type != 0xFF) {
setType(type);
#ifdef UI_FRAMEWORK_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOLNPAIR("New screen: ", type);
#endif
}
}
void ScreenRef::initializeAll() {
for(uint8_t type = 0; type < functionTableSize; type++) {
GET_METHOD(type, onStartup)();
}
}
/********************** SCREEN STACK ******************************/
void ScreenStack::start() {
initializeAll();
onEntry();
}
void ScreenStack::push(onRedraw_func_t onRedraw_ptr) {
stack[3] = stack[2];
stack[2] = stack[1];
stack[1] = stack[0];
stack[0] = lookupScreen(onRedraw_ptr);
}
void ScreenStack::push() {
stack[3] = stack[2];
stack[2] = stack[1];
stack[1] = stack[0];
stack[0] = getType();
}
void ScreenStack::pop() {
setType(stack[0]);
forget();
}
void ScreenStack::forget() {
stack[0] = stack[1];
stack[1] = stack[2];
stack[2] = stack[3];
stack[3] = 0;
}
void ScreenStack::goTo(onRedraw_func_t s) {
push();
onExit();
setScreen(s);
onEntry();
}
void ScreenStack::goBack() {
onExit();
pop();
onEntry();
}
ScreenStack current_screen;
#endif // FTDI_EXTENDED

@ -0,0 +1,215 @@
/********************
* screen_types.cpp *
********************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
typedef enum {
BACKGROUND = 1,
FOREGROUND = 2,
BOTH = 3
} draw_mode_t;
/********************** VIRTUAL DISPATCH DATA TYPE ******************************/
// True virtual classes are extremely expensive on the Arduino
// as the compiler stores the virtual function tables in RAM.
// We invent a data type called ScreenRef that gives us
// polymorphism by mapping an ID to virtual methods on various
// classes. This works by keeping a table in PROGMEM of pointers
// to static methods.
#define DECL_SCREEN(className) { \
className::onStartup, \
className::onEntry, \
className::onExit, \
className::onIdle, \
className::onRefresh, \
className::onRedraw, \
className::onTouchStart, \
className::onTouchHeld, \
className::onTouchEnd \
}
#define GET_METHOD(type, method) reinterpret_cast<method##_func_t*>(pgm_read_ptr_far(&functionTable[type].method##_ptr))
#define SCREEN_TABLE PROGMEM const ScreenRef::table_t ScreenRef::functionTable[] =
#define SCREEN_TABLE_POST const uint8_t ScreenRef::functionTableSize = sizeof(ScreenRef::functionTable)/sizeof(ScreenRef::functionTable[0]);
class ScreenRef {
protected:
typedef void onStartup_func_t(void);
typedef void onEntry_func_t(void);
typedef void onExit_func_t(void);
typedef void onIdle_func_t(void);
typedef void onRefresh_func_t(void);
typedef void onRedraw_func_t(draw_mode_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 {
onStartup_func_t *onStartup_ptr;
onEntry_func_t *onEntry_ptr;
onExit_func_t *onExit_ptr;
onIdle_func_t *onIdle_ptr;
onRefresh_func_t *onRefresh_ptr;
onRedraw_func_t *onRedraw_ptr;
onTouchStart_func_t *onTouchStart_ptr;
onTouchHeld_func_t *onTouchHeld_ptr;
onTouchEnd_func_t *onTouchEnd_ptr;
} table_t;
uint8_t type = 0;
static PROGMEM const table_t functionTable[];
static const uint8_t functionTableSize;
public:
uint8_t getType() {return type;}
void setType(uint8_t t) {
type = t;
}
uint8_t lookupScreen(onRedraw_func_t onRedraw_ptr);
void setScreen(onRedraw_func_t onRedraw_ptr);
void onStartup() {GET_METHOD(type, onStartup)();}
void onEntry() {GET_METHOD(type, onEntry)();}
void onExit() {GET_METHOD(type, onExit)();}
void onIdle() {GET_METHOD(type, onIdle)();}
void onRefresh() {GET_METHOD(type, onRefresh)();}
void onRedraw(draw_mode_t dm) {GET_METHOD(type, onRedraw)(dm);}
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();
};
/********************** SCREEN STACK ******************************/
// To conserve dynamic memory, the screen stack is hard-coded to
// have four values, allowing a menu of up to four levels.
class ScreenStack : public ScreenRef {
private:
uint8_t stack[4];
public:
void start();
void push(onRedraw_func_t);
void push();
void pop();
void forget();
void goTo(onRedraw_func_t);
void goBack();
uint8_t peek() {return stack[0];}
uint8_t getScreen() {return getType();}
};
extern ScreenStack current_screen;
/********************** BASE SCREEN CLASS ******************************/
/* UIScreen is the base class for all user interface screens.
*/
class UIScreen {
public:
static void onStartup() {}
static void onEntry() {current_screen.onRefresh();}
static void onExit() {}
static void onIdle() {}
static bool onTouchStart(uint8_t) {return true;}
static bool onTouchHeld(uint8_t) {return false;}
static bool onTouchEnd(uint8_t) {return true;}
};
#define PUSH_SCREEN(screen) current_screen.push(screen::onRedraw);
#define GOTO_SCREEN(screen) current_screen.goTo(screen::onRedraw);
#define GOTO_PREVIOUS() current_screen.goBack();
#define AT_SCREEN(screen) (current_screen.getType() == current_screen.lookupScreen(screen::onRedraw))
#define IS_PARENT_SCREEN(screen) (current_screen.peek() == current_screen.lookupScreen(screen::onRedraw))
/************************** CACHED VS UNCHACHED SCREENS ***************************/
class UncachedScreen {
public:
static void onRefresh() {
using namespace FTDI;
CLCD::CommandFifo cmd;
cmd.cmd(CMD_DLSTART);
current_screen.onRedraw(BOTH);
cmd.cmd(DL::DL_DISPLAY);
cmd.cmd(CMD_SWAP);
cmd.execute();
}
};
template<uint8_t DL_SLOT,uint32_t DL_SIZE = 0>
class CachedScreen {
protected:
static bool storeBackground(){
DLCache dlcache(DL_SLOT);
if (!dlcache.store(DL_SIZE)) {
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM("CachedScreen::storeBackground() failed: not enough DL cache space");
return false;
}
return true;
}
static void repaintBackground(){
using namespace FTDI;
DLCache dlcache(DL_SLOT);
CLCD::CommandFifo cmd;
cmd.cmd(CMD_DLSTART);
current_screen.onRedraw(BACKGROUND);
dlcache.store(DL_SIZE);
}
public:
static void onRefresh(){
using namespace FTDI;
DLCache dlcache(DL_SLOT);
CLCD::CommandFifo cmd;
cmd.cmd(CMD_DLSTART);
if (dlcache.has_data()) {
dlcache.append();
} else {
current_screen.onRedraw(BACKGROUND);
dlcache.store(DL_SIZE);
}
current_screen.onRedraw(FOREGROUND);
cmd.cmd(DL::DL_DISPLAY);
cmd.cmd(CMD_SWAP);
cmd.execute();
}
};

@ -0,0 +1,38 @@
/****************
* sound_list.h *
****************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#pragma once
class SoundList {
private:
static PROGMEM const struct list_t {
const char *const PROGMEM name;
const FTDI::SoundPlayer::sound_t* data;
} list[];
public:
static const uint8_t n;
static inline const char* name(uint8_t val) {
return (const char* ) pgm_read_ptr_near(&list[val].name);
}
static inline FTDI::SoundPlayer::sound_t* data(uint8_t val) {
return (FTDI::SoundPlayer::sound_t*) pgm_read_ptr_near(&list[val].data);
}
};

@ -0,0 +1,111 @@
/********************
* sound_player.cpp *
********************/
/****************************************************************************
* 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/>. *
****************************************************************************/
#include "ftdi_extended.h"
#ifdef FTDI_EXTENDED
namespace FTDI {
SoundPlayer sound; // Global sound player object
void SoundPlayer::set_volume(uint8_t vol) {
CLCD::mem_write_8(REG::VOL_SOUND, vol);
}
uint8_t SoundPlayer::get_volume() {
return CLCD::mem_read_8(REG::VOL_SOUND);
}
void SoundPlayer::play(effect_t effect, note_t note) {
#ifdef UI_FRAMEWORK_DEBUG
SERIAL_ECHO_START();
SERIAL_ECHOPAIR("Playing note ", note);
SERIAL_ECHOLNPAIR(", instrument ", effect);
#endif
// Play the note
CLCD::mem_write_16(REG::SOUND, (note == REST) ? 0 : (((note ? note : NOTE_C4) << 8) | effect));
CLCD::mem_write_8(REG::PLAY, 1);
}
note_t SoundPlayer::frequency_to_midi_note(const uint16_t frequency_hz) {
const float f0 = 440;
return note_t(NOTE_A4 + (log(frequency_hz)-log(f0))*12/log(2) + 0.5);
}
// Plays a tone of a given frequency and duration. Since the FTDI FT810 only
// supports MIDI notes, we round down to the nearest note.
void SoundPlayer::play_tone(const uint16_t frequency_hz, const uint16_t duration_ms) {
play(ORGAN, frequency_to_midi_note(frequency_hz));
// Schedule silence to squelch the note after the duration expires.
sequence = silence;
wait = duration_ms;
timer.start();
}
void SoundPlayer::play(const sound_t* seq, play_mode_t mode) {
sequence = seq;
wait = 250; // Adding this delay causes the note to not be clipped, not sure why.
timer.start();
if (mode == PLAY_ASYNCHRONOUS) return;
// If playing synchronously, then play all the notes here
while (has_more_notes()) {
onIdle();
#ifdef EXTENSIBLE_UI
ExtUI::yield();
#endif
}
}
bool SoundPlayer::is_sound_playing() {
return CLCD::mem_read_8( REG::PLAY ) & 0x1;
}
void SoundPlayer::onIdle() {
if (!sequence) return;
const bool ready_for_next_note = (wait == 0) ? !is_sound_playing() : timer.elapsed(wait);
if (ready_for_next_note) {
const effect_t fx = effect_t(pgm_read_byte(&sequence->effect));
const note_t nt = note_t(pgm_read_byte(&sequence->note));
const uint32_t ms = uint32_t(pgm_read_byte(&sequence->sixteenths)) * 1000 / 16;
if (ms == 0 && fx == SILENCE && nt == END_SONG) {
sequence = 0;
play(SILENCE, REST);
} else {
wait = ms;
timer.start();
play(fx, nt);
sequence++;
}
}
}
} // namespace FTDI
#endif // FTDI_EXTENDED

@ -0,0 +1,70 @@
/******************
* sound_player.h *
******************/
/****************************************************************************
* Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
* 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/>. *
****************************************************************************/
#pragma once
namespace FTDI {
typedef enum {
PLAY_ASYNCHRONOUS,
PLAY_SYNCHRONOUS
} play_mode_t;
class SoundPlayer {
typedef FTDI::ftdi_registers REG;
typedef FTDI::ftdi_memory_map MAP;
public:
struct sound_t {
effect_t effect; // The sound effect number
note_t note; // The MIDI note value
uint16_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;
tiny_timer_t timer;
tiny_time_t wait;
note_t frequency_to_midi_note(const uint16_t frequency);
public:
static void set_volume(uint8_t volume);
static uint8_t get_volume();
static void play(effect_t effect, note_t note = NOTE_C4);
static bool is_sound_playing();
void play(const sound_t* seq, play_mode_t mode = PLAY_SYNCHRONOUS);
void play_tone(const uint16_t frequency_hz, const uint16_t duration_ms);
bool has_more_notes() {return sequence != 0;};
void onIdle();
};
extern SoundPlayer sound;
const PROGMEM SoundPlayer::sound_t silence[] = {
{SILENCE, END_SONG, 0}
};
}

@ -0,0 +1,129 @@
/****************
* text_box.cpp *
****************/
/****************************************************************************
* Written By Marcio Teixeira 2019 - 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/>. *
****************************************************************************/
#include "ftdi_extended.h"
#ifdef FTDI_EXTENDED
namespace FTDI {
/**
* Given a str, end will be set to the position at which a line needs to
* be broken so that the display width is less than w. The line will also
* be broken after a '\n'. Returns the display width of the line.
*/
static uint16_t find_line_break(const CLCD::FontMetrics &fm, uint16_t w, const char *str, const char *&end) {
const char *p = str;
end = str + strlen(str);
uint16_t width = fm.get_text_width(str);
for(;;) {
// Find next tentative line break.
char delim = *(p);
while (delim && delim != ' ' && delim != '\n') {
delim = *(++p);
}
// Check to see whether to break the line.
const uint16_t margin = fm.get_text_width(" ");
const uint16_t lw = p > str ? fm.get_text_width(str, p - str) + margin : 0;
if (lw < w) {
width = lw;
switch (delim) {
case '\0':
end = p;
break;
case '\n':
end = ++p;
break;
case ' ':
end = ++p;
continue;
}
}
return width;
}
}
/**
* This function returns a measurements of the word-wrapped text box.
*/
static void measure_text_box(const CLCD::FontMetrics &fm, const char *str, uint16_t &width, uint16_t &height) {
const char *line_start = (const char*)str;
const char *line_end;
const uint16_t wrap_width = width;
width = height = 0;
for(;;) {
uint16_t line_width = find_line_break(fm, wrap_width, line_start, line_end);
if (line_end == line_start) break;
width = max(width, line_width);
height += fm.height;
line_start = line_end;
}
}
/**
* This function draws text inside a bounding box, doing word wrapping and using the largest font that will fit.
*/
void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options, uint8_t font) {
CLCD::FontMetrics fm(font);
uint16_t box_width, box_height;
for(;;) {
box_width = w;
measure_text_box(fm, str, box_width, box_height);
if (box_width <= (uint16_t)w && box_height <= (uint16_t)h) break;
fm.load(--font);
if (font == 26) break;
}
const uint16_t dx = (options & OPT_RIGHTX) ? w : (options & OPT_CENTERX) ? w/2 : 0;
const uint16_t dy = (options & OPT_CENTERY) ? (h - box_height)/2 : 0;
const char *line_start = str;
const char *line_end;
for(;;) {
find_line_break(fm, w, line_start, line_end);
if (line_end == line_start) break;
const size_t line_len = line_end - line_start;
if (line_len) {
char line[line_len + 1];
strncpy(line, line_start, line_len);
line[line_len] = 0;
if (line[line_len - 1] == '\n' || line[line_len - 1] == ' ')
line[line_len - 1] = 0;
cmd.CLCD::CommandFifo::text(x + dx, y + dy, font, options & ~OPT_CENTERY);
cmd.CLCD::CommandFifo::str(line);
}
y += fm.height;
line_start = line_end;
}
}
void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, progmem_str pstr, uint16_t options, uint8_t font) {
char str[strlen_P((const char*)pstr) + 1];
strcpy_P(str, (const char*)pstr);
draw_text_box(cmd, x, y, w, h, (const char*) str, options, font);
}
} // namespace FTDI
#endif // FTDI_EXTENDED

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save