aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/lcd/extui
diff options
context:
space:
mode:
Diffstat (limited to 'Marlin/src/lcd/extui')
-rw-r--r--Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp130
-rw-r--r--Marlin/src/lcd/extui/anycubic_i3mega_lcd.cpp117
-rw-r--r--Marlin/src/lcd/extui/dgus_lcd.cpp158
-rw-r--r--Marlin/src/lcd/extui/example.cpp125
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp164
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h56
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp62
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.h224
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp885
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h77
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h151
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp1028
-rw-r--r--Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h97
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp261
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h118
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/DGUSDisplayDef.h54
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.cpp1140
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.h232
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/DGUSVPVariable.h49
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.cpp486
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.h296
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.cpp485
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.h292
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.cpp310
-rw-r--r--Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.h282
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp553
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.h106
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp63
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h48
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h53
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/config.h26
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt674
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/README.md28
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h184
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp1194
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h262
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h414
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h118
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h40
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h150
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h187
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h127
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp175
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h136
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h278
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h49
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp29
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h437
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp180
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h70
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp228
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h74
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h52
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h98
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h96
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h84
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp105
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h241
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h38
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp110
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h70
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp129
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h30
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp91
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h31
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp39
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h56
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt40
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp139
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h32
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h2529
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp58
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h30
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.pngbin0 -> 34122 bytes
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg535
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbmbin0 -> 23570 bytes
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pngbin0 -> 16643 bytes
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.pngbin0 -> 24548 bytes
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg443
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp46
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h55
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp107
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h30
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp238
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h112
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp455
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h31
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h1315
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/bitmap2cpp.py108
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/circular_progress.h105
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/poly_ui.h408
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/svg2cpp.py280
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h27
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.cpp27
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.h23
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language_en.h176
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/marlin_events.cpp184
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/pin_mappings.h144
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/about_screen.cpp116
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/advanced_settings_menu.cpp156
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/alert_dialog_box.cpp70
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/backlash_compensation_screen.cpp76
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_numeric_adjustment_screen.cpp388
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_screen.cpp90
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp341
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_advanced_settings.cpp137
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_e.cpp57
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_xyz.cpp56
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_main_menu.cpp88
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_landscape.h59
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_portrait.h52
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printing_dialog_box.cpp151
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_status_screen.cpp379
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_tune_menu.cpp79
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/boot_screen.cpp130
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/case_light_screen.cpp62
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/change_filament_screen.cpp330
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_advanced_settings_menu.cpp102
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_load_chocolate.cpp101
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_main_menu.cpp89
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_e_screen.cpp62
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_xyz_screen.cpp53
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_menu.cpp113
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_screen.cpp172
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_status_screen.cpp307
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_ui.h54
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_unload_cartridge.cpp101
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_abort_print_dialog_box.cpp53
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_auto_calibration_dialog_box.cpp48
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_erase_flash_dialog_box.cpp54
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_start_print_dialog_box.cpp65
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_user_request_alert_box.cpp66
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/custom_user_menus.cpp215
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/default_acceleration_screen.cpp63
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/developer_menu.cpp150
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/dialog_box_base_class.cpp87
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/display_tuning_screen.cpp61
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/endstop_state_screen.cpp152
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/feedrate_percent_screen.cpp52
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_menu.cpp85
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp65
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp264
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_settings_screen.cpp291
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_sounds_screen.cpp160
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/jerk_screen.cpp65
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/junction_deviation_screen.cpp54
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/kill_screen.cpp62
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/language_menu.cpp66
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/leveling_menu.cpp121
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/linear_advance_screen.cpp77
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/lock_screen.cpp205
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/main_menu.cpp131
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_acceleration_screen.cpp86
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_velocity_screen.cpp90
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/media_player_screen.cpp168
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/move_axis_screen.cpp133
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nozzle_offsets_screen.cpp73
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nudge_nozzle_screen.cpp123
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/restore_failsafe_dialog_box.cpp51
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/save_settings_dialog_box.cpp64
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screen_data.h97
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.cpp139
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h911
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/spinner_dialog_box.cpp68
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/statistics_screen.cpp78
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/status_screen.cpp465
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_bump_sensitivity_screen.cpp59
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_current_screen.cpp127
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/steps_screen.cpp86
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp149
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.cpp83
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.h29
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/temperature_screen.cpp119
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_calibration_screen.cpp94
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_registers_screen.cpp86
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/tune_menu.cpp156
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/widget_demo_screen.cpp158
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/z_offset_screen.cpp54
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bitmaps.h183
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bootscreen_logo_portrait.h42
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/colors.h183
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/fonts.h80
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_landscape.h39
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_portrait.h39
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.cpp410
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.h43
-rw-r--r--Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/theme.h28
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp303
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h108
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.cpp83
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.h43
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_about.cpp65
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_about.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.cpp155
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.cpp96
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.cpp90
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.cpp179
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.h35
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.cpp184
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.h37
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.cpp225
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.h39
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.cpp205
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.h37
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp574
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.h91
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.cpp82
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.cpp72
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.cpp46
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.h37
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.cpp266
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.h38
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_fan.cpp117
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_fan.h34
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.cpp216
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.h35
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.cpp126
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp93
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_home.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.cpp104
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.cpp99
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp289
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_language.cpp208
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_language.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp104
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.h35
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.cpp84
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.cpp82
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp135
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.cpp146
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.cpp119
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp119
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_more.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.cpp98
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp211
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.h34
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.cpp772
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_operation.cpp230
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_operation.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.cpp51
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.h32
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.cpp85
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.cpp297
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.h36
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.cpp552
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.h64
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_printing.cpp290
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_printing.h53
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.cpp220
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.h40
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_set.cpp134
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_set.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.cpp115
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.cpp156
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.h34
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.cpp154
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp113
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_tool.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.cpp117
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.h34
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.cpp101
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.h35
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp1510
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h551
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.cpp166
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.h38
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.cpp177
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.h76
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.cpp141
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.h36
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.cpp68
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.h51
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/gb2312_puhui16.cpp105
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/irq_overrid.cpp63
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp655
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.h33
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp622
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h168
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/printer_operation.cpp250
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/printer_operation.h36
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h751
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h268
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h265
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h384
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h518
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h274
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h515
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp584
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.h69
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp2920
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h865
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.cpp526
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h145
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp2231
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/wifi_module.h201
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp726
-rw-r--r--Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.h74
-rw-r--r--Marlin/src/lcd/extui/malyan_lcd.cpp543
-rw-r--r--Marlin/src/lcd/extui/ui_api.cpp1074
-rw-r--r--Marlin/src/lcd/extui/ui_api.h402
319 files changed, 61817 insertions, 0 deletions
diff --git a/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp b/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp
new file mode 100644
index 0000000..06baa4c
--- /dev/null
+++ b/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp
@@ -0,0 +1,130 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * lcd/extui/anycubic_chiron_lcd.cpp
+ *
+ * Anycubic Chiron TFT support for Marlin
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+
+#include "ui_api.h"
+#include "lib/anycubic_chiron/chiron_tft.h"
+
+using namespace Anycubic;
+
+namespace ExtUI {
+
+ void onStartup() { Chiron.Startup(); }
+
+ void onIdle() { Chiron.IdleLoop(); }
+
+ void onPrinterKilled(PGM_P const error, PGM_P const component) {
+ Chiron.PrinterKilled(error,component);
+ }
+
+ void onMediaInserted() { Chiron.MediaEvent(AC_media_inserted); }
+ void onMediaError() { Chiron.MediaEvent(AC_media_error); }
+ void onMediaRemoved() { Chiron.MediaEvent(AC_media_removed); }
+
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {
+ #if ENABLED(SPEAKER)
+ ::tone(BEEPER_PIN, frequency, duration);
+ #endif
+ }
+
+ void onPrintTimerStarted() { Chiron.TimerEvent(AC_timer_started); }
+ void onPrintTimerPaused() { Chiron.TimerEvent(AC_timer_paused); }
+ void onPrintTimerStopped() { Chiron.TimerEvent(AC_timer_stopped); }
+ void onFilamentRunout(const extruder_t) { Chiron.FilamentRunout(); }
+ void onUserConfirmRequired(const char * const msg) { Chiron.ConfirmationRequest(msg); }
+ void onStatusChanged(const char * const msg) { Chiron.StatusChange(msg); }
+
+ void onHomingStart() {}
+ void onHomingComplete() {}
+ void onPrintFinished() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onConfigurationStoreWritten(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onConfigurationStoreRead(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+ void onMeshLevelingStart() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {
+ // Called when any mesh points are updated
+ //SERIAL_ECHOLNPAIR("onMeshUpdate() x:", xpos, " y:", ypos, " z:", zval);
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {
+ // Called to indicate a special condition
+ //SERIAL_ECHOLNPAIR("onMeshUpdate() x:", xpos, " y:", ypos, " state:", state);
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ // Called on resume from power-loss
+ void onPowerLossResume() { Chiron.PowerLossRecovery(); }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/Marlin/src/lcd/extui/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/anycubic_i3mega_lcd.cpp
new file mode 100644
index 0000000..e2bd960
--- /dev/null
+++ b/Marlin/src/lcd/extui/anycubic_i3mega_lcd.cpp
@@ -0,0 +1,117 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * anycubic_i3mega_lcd.cpp
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_I3MEGA)
+
+#include "lib/anycubic_i3mega/anycubic_i3mega_lcd.h"
+#include "ui_api.h"
+
+#include <Arduino.h> // for the ::tone() call
+
+namespace ExtUI {
+
+ void onStartup() { AnycubicTFT.OnSetup(); }
+ void onIdle() { AnycubicTFT.OnCommandScan(); }
+ void onPrinterKilled(PGM_P const error, PGM_P const component) { AnycubicTFT.OnKillTFT(); }
+ void onMediaInserted() { AnycubicTFT.OnSDCardStateChange(true); }
+ void onMediaError() { AnycubicTFT.OnSDCardError(); }
+ void onMediaRemoved() { AnycubicTFT.OnSDCardStateChange(false); }
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {
+ #if ENABLED(SPEAKER)
+ ::tone(BEEPER_PIN, frequency, duration);
+ #endif
+ }
+ void onPrintTimerStarted() { AnycubicTFT.OnPrintTimerStarted(); }
+ void onPrintTimerPaused() { AnycubicTFT.OnPrintTimerPaused(); }
+ void onPrintTimerStopped() { AnycubicTFT.OnPrintTimerStopped(); }
+ void onFilamentRunout(const extruder_t extruder) { AnycubicTFT.OnFilamentRunout(); }
+ void onUserConfirmRequired(const char * const msg) { AnycubicTFT.OnUserConfirmRequired(msg); }
+ void onStatusChanged(const char * const msg) {}
+
+ void onHomingStart() {}
+ void onHomingComplete() {}
+ void onPrintFinished() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onConfigurationStoreWritten(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onConfigurationStoreRead(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+
+ void onMeshLevelingStart() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {
+ // Called when any mesh points are updated
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // ANYCUBIC_LCD_I3MEGA
diff --git a/Marlin/src/lcd/extui/dgus_lcd.cpp b/Marlin/src/lcd/extui/dgus_lcd.cpp
new file mode 100644
index 0000000..9fcb6c8
--- /dev/null
+++ b/Marlin/src/lcd/extui/dgus_lcd.cpp
@@ -0,0 +1,158 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * dgus_lcd.cpp
+ *
+ * DGUS implementation for Marlin by coldtobi, Feb-May 2019
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_DGUS_LCD
+
+#include "ui_api.h"
+#include "lib/dgus/DGUSDisplay.h"
+#include "lib/dgus/DGUSDisplayDef.h"
+#include "lib/dgus/DGUSScreenHandler.h"
+
+namespace ExtUI {
+
+ void onStartup() {
+ dgusdisplay.InitDisplay();
+ ScreenHandler.UpdateScreenVPData();
+ }
+
+ void onIdle() { ScreenHandler.loop(); }
+
+ void onPrinterKilled(PGM_P const error, PGM_P const component) {
+ ScreenHandler.sendinfoscreen(GET_TEXT(MSG_HALTED), error, NUL_STR, GET_TEXT(MSG_PLEASE_RESET), true, true, true, true);
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_KILL);
+ while (!ScreenHandler.loop()); // Wait while anything is left to be sent
+ }
+
+ void onMediaInserted() { TERN_(SDSUPPORT, ScreenHandler.SDCardInserted()); }
+ void onMediaError() { TERN_(SDSUPPORT, ScreenHandler.SDCardError()); }
+ void onMediaRemoved() { TERN_(SDSUPPORT, ScreenHandler.SDCardRemoved()); }
+
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {}
+ void onPrintTimerStarted() {}
+ void onPrintTimerPaused() {}
+ void onPrintTimerStopped() {}
+ void onFilamentRunout(const extruder_t extruder) {}
+
+ void onUserConfirmRequired(const char * const msg) {
+ if (msg) {
+ ScreenHandler.sendinfoscreen(PSTR("Please confirm."), nullptr, msg, nullptr, true, true, false, true);
+ ScreenHandler.SetupConfirmAction(ExtUI::setUserConfirmed);
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_POPUP);
+ }
+ else if (ScreenHandler.getCurrentScreen() == DGUSLCD_SCREEN_POPUP ) {
+ ScreenHandler.SetupConfirmAction(nullptr);
+ ScreenHandler.PopToOldScreen();
+ }
+ }
+
+ void onStatusChanged(const char * const msg) { ScreenHandler.setstatusmessage(msg); }
+
+ void onHomingStart() {}
+ void onHomingComplete() {}
+ void onPrintFinished() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onConfigurationStoreWritten(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onConfigurationStoreRead(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+ void onMeshLevelingStart() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {
+ // Called when any mesh points are updated
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {
+ // Called to indicate a special condition
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_POWER_LOSS);
+ }
+ #endif
+
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ switch (rst) {
+ case PID_BAD_EXTRUDER_NUM:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_BAD_EXTRUDER_NUM));
+ break;
+ case PID_TEMP_TOO_HIGH:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_TEMP_TOO_HIGH));
+ break;
+ case PID_TUNING_TIMEOUT:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_TIMEOUT));
+ break;
+ case PID_DONE:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_AUTOTUNE_DONE));
+ break;
+ }
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // HAS_DGUS_LCD
diff --git a/Marlin/src/lcd/extui/example.cpp b/Marlin/src/lcd/extui/example.cpp
new file mode 100644
index 0000000..dd4b331
--- /dev/null
+++ b/Marlin/src/lcd/extui/example.cpp
@@ -0,0 +1,125 @@
+/*********************
+ * example.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if BOTH(EXTUI_EXAMPLE, EXTENSIBLE_UI)
+
+#include "ui_api.h"
+
+// To implement a new UI, complete the functions below and
+// read or update Marlin's state using the methods in the
+// ExtUI methods in "../ui_api.h"
+//
+// Although it may be possible to access other state
+// variables from Marlin, using the API here possibly
+// helps ensure future compatibility.
+
+namespace ExtUI {
+ void onStartup() {
+ /* Initialize the display module here. The following
+ * routines are available for access to the GPIO pins:
+ *
+ * SET_OUTPUT(pin)
+ * SET_INPUT_PULLUP(pin)
+ * SET_INPUT(pin)
+ * WRITE(pin,value)
+ * READ(pin)
+ */
+ }
+ void onIdle() {}
+ void onPrinterKilled(PGM_P const error, PGM_P const component) {}
+ void onMediaInserted() {}
+ void onMediaError() {}
+ void onMediaRemoved() {}
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {}
+ void onPrintTimerStarted() {}
+ void onPrintTimerPaused() {}
+ void onPrintTimerStopped() {}
+ void onFilamentRunout(const extruder_t extruder) {}
+ void onUserConfirmRequired(const char * const msg) {}
+ void onStatusChanged(const char * const msg) {}
+
+ void onHomingStart() {}
+ void onHomingComplete() {}
+ void onPrintFinished() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= ExtUI::eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onConfigurationStoreWritten(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onConfigurationStoreRead(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+ void onMeshLevelingStart() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {
+ // Called when any mesh points are updated
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {
+ // Called to indicate a special condition
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // EXTUI_EXAMPLE && EXTENSIBLE_UI
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp
new file mode 100644
index 0000000..19f8ec8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp
@@ -0,0 +1,164 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * lcd/extui/lib/FileNavigator.cpp
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+/***************************************************************************
+ * The AC panel wants files in block of 4 and can only display a flat list *
+ * This library allows full folder traversal. *
+ ***************************************************************************/
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+
+#include "FileNavigator.h"
+#include "chiron_tft.h"
+
+using namespace ExtUI;
+
+namespace Anycubic {
+
+ FileNavigator filenavigator;
+
+ FileList FileNavigator::filelist; // Instance of the Marlin file API
+ char FileNavigator::currentfoldername[MAX_PATH_LEN]; // Current folder path
+ uint16_t FileNavigator::lastindex;
+ uint8_t FileNavigator::folderdepth;
+ uint16_t FileNavigator::currentindex; // override the panel request
+
+ FileNavigator::FileNavigator() { reset(); }
+
+ void FileNavigator::reset() {
+ currentfoldername[0] = '\0';
+ folderdepth = 0;
+ currentindex = 0;
+ lastindex = 0;
+ // Start at root folder
+ while (!filelist.isAtRootDir()) filelist.upDir();
+ refresh();
+ }
+
+ void FileNavigator::refresh() { filelist.refresh(); }
+
+ void FileNavigator::getFiles(uint16_t index) {
+ uint8_t files = 4;
+ if (index == 0) currentindex = 0;
+
+ // Each time we change folder we reset the file index to 0 and keep track
+ // of the current position as the TFT panel isnt aware of folders trees.
+ if (index > 0) {
+ --currentindex; // go back a file to take account off the .. we added to the root.
+ if (index > lastindex)
+ currentindex += files;
+ else
+ currentindex = currentindex < 4 ? 0 : currentindex - files;
+ }
+ lastindex = index;
+
+ #if ACDEBUG(AC_FILE)
+ SERIAL_ECHOLNPAIR("index=", index, " currentindex=", currentindex);
+ #endif
+
+ if (currentindex == 0 && folderdepth > 0) { // Add a link to go up a folder
+ TFTSer.println("<<");
+ TFTSer.println("..");
+ files--;
+ }
+
+ for (uint16_t seek = currentindex; seek < currentindex + files; seek++) {
+ if (filelist.seek(seek)) {
+ sendFile();
+ #if ACDEBUG(AC_FILE)
+ SERIAL_ECHOLNPAIR("-", seek, " '", filelist.longFilename(), "' '", currentfoldername, "", filelist.shortFilename(), "'\n");
+ #endif
+ }
+ }
+ }
+
+ void FileNavigator::sendFile() {
+ // send the file and folder info to the panel
+ // this info will be returned when the file is selected
+ // Permitted special characters in file name -_*#~
+ // Panel can display 22 characters per line
+ if (filelist.isDir()) {
+ //TFTSer.print(currentfoldername);
+ TFTSer.println(filelist.shortFilename());
+ TFTSer.print(filelist.shortFilename());
+ TFTSer.println("/");
+ }
+ else {
+ // Logical Name
+ TFTSer.print("/");
+ if (folderdepth > 0) TFTSer.print(currentfoldername);
+
+ TFTSer.println(filelist.shortFilename());
+
+ // Display Name
+ TFTSer.println(filelist.longFilename());
+ }
+ }
+ void FileNavigator::changeDIR(char *folder) {
+ #if ACDEBUG(AC_FILE)
+ SERIAL_ECHOLNPAIR("currentfolder: ", currentfoldername, " New: ", folder);
+ #endif
+ if (folderdepth >= MAX_FOLDER_DEPTH) return; // limit the folder depth
+ strcat(currentfoldername, folder);
+ strcat(currentfoldername, "/");
+ filelist.changeDir(folder);
+ refresh();
+ folderdepth++;
+ currentindex = 0;
+ }
+
+ void FileNavigator::upDIR() {
+ filelist.upDir();
+ refresh();
+ folderdepth--;
+ currentindex = 0;
+ // Remove the last child folder from the stored path
+ if (folderdepth == 0) {
+ currentfoldername[0] = '\0';
+ reset();
+ }
+ else {
+ char *pos = nullptr;
+ for (uint8_t f = 0; f < folderdepth; f++)
+ pos = strchr(currentfoldername, '/');
+
+ *(pos + 1) = '\0';
+ }
+ #if ACDEBUG(AC_FILE)
+ SERIAL_ECHOLNPAIR("depth: ", folderdepth, " currentfoldername: ", currentfoldername);
+ #endif
+ }
+
+ char* FileNavigator::getCurrentFolderName() { return currentfoldername; }
+}
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h
new file mode 100644
index 0000000..8e03614
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h
@@ -0,0 +1,56 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/lib/FileNavigator.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#include "chiron_tft_defs.h"
+#include "../../ui_api.h"
+
+using namespace ExtUI;
+
+namespace Anycubic {
+ class FileNavigator {
+ public:
+ FileNavigator();
+ void reset();
+ void getFiles(uint16_t);
+ void upDIR();
+ void changeDIR(char *);
+ void sendFile();
+ void refresh();
+ char * getCurrentFolderName();
+ private:
+ static FileList filelist;
+ static char currentfoldername[MAX_PATH_LEN];
+ static uint16_t lastindex;
+ static uint8_t folderdepth;
+ static uint16_t currentindex;
+ };
+ extern FileNavigator filenavigator;
+}
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp
new file mode 100644
index 0000000..f09c4db
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp
@@ -0,0 +1,62 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * lcd/extui/lib/Tunes.cpp
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+/***********************************************************************
+ * A Utility to play tunes using the buzzer in the printer controller. *
+ * See Tunes.h for note and tune definitions. *
+ ***********************************************************************/
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+
+#include "Tunes.h"
+#include "../../ui_api.h"
+
+namespace Anycubic {
+
+ void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed=1) {
+ uint8_t pos = 1;
+ uint16_t wholenotelen = tune[0] / speed;
+ do {
+ uint16_t freq = tune[pos];
+ uint16_t notelen = wholenotelen / tune[pos + 1];
+
+ ::tone(beeperPin, freq, notelen);
+ ExtUI::delay_ms(notelen);
+ pos += 2;
+
+ if (pos >= MAX_TUNE_LENGTH) break;
+ } while (tune[pos] != n_END);
+ }
+
+}
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.h
new file mode 100644
index 0000000..1bafec4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.h
@@ -0,0 +1,224 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/lib/Tunes.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+/**************************************************************************
+ * Notes definition from https://pages.mtu.edu/~suits/NoteFreqCalcs.html *
+ * *
+ * The format of a tune is: *
+ * {<whole note time>,<note1>,<length1>, <note2>,<length2>, ... <END>} *
+ * *
+ * 1) The first value is the length of a whole note in milliseconds *
+ * 2) Then a sequence of pitch and duration pairs *
+ * 3) Finally the END marker so your tunes can be any length up to *
+ * MAX_TUNE_LEN *
+ *************************************************************************/
+
+#include <stdint.h>
+
+#define MAX_TUNE_LENGTH 128
+
+// Special notes!
+#define n_P 0 // silence or pause
+#define n_END 10000 // end of tune marker
+
+// Note duration divisors
+#define l_T1 1
+#define l_T2 2
+#define l_T3 3
+#define l_T4 4
+#define l_T8 8
+#define l_T16 16
+
+// Note Frequency
+#define n_C0 16
+#define n_CS0 17
+#define n_D0 18
+#define n_DS0 19
+#define n_E0 21
+#define n_F0 22
+#define n_FS0 23
+#define n_G0 25
+#define n_GS0 26
+#define n_A0 28
+#define n_AS0 29
+#define n_B0 31
+#define n_C1 33
+#define n_CS1 35
+#define n_D1 37
+#define n_DS1 39
+#define n_E1 41
+#define n_F1 44
+#define n_FS1 46
+#define n_G1 49
+#define n_GS1 52
+#define n_A1 55
+#define n_AS1 58
+#define n_B1 62
+#define n_C2 65
+#define n_CS2 69
+#define n_D2 73
+#define n_DS2 78
+#define n_E2 82
+#define n_F2 87
+#define n_FS2 93
+#define n_G2 98
+#define n_GS2 104
+#define n_A2 110
+#define n_AS2 117
+#define n_B2 123
+#define n_C3 131
+#define n_CS3 139
+#define n_D3 147
+#define n_DS3 156
+#define n_E3 165
+#define n_F3 175
+#define n_FS3 185
+#define n_G3 196
+#define n_GS3 208
+#define n_A3 220
+#define n_AS3 233
+#define n_B3 247
+#define n_C4 262
+#define n_CS4 277
+#define n_D4 294
+#define n_DS4 311
+#define n_E4 330
+#define n_F4 349
+#define n_FS4 370
+#define n_G4 392
+#define n_GS4 415
+#define n_A4 440
+#define n_AS4 466
+#define n_B4 494
+#define n_C5 523
+#define n_CS5 554
+#define n_D5 587
+#define n_DS5 622
+#define n_E5 659
+#define n_F5 698
+#define n_FS5 740
+#define n_G5 784
+#define n_GS5 831
+#define n_A5 880
+#define n_AS5 932
+#define n_B5 988
+#define n_C6 1047
+#define n_CS6 1109
+#define n_D6 1175
+#define n_DS6 1245
+#define n_E6 1319
+#define n_F6 1397
+#define n_FS6 1480
+#define n_G6 1568
+#define n_GS6 1661
+#define n_A6 1760
+#define n_AS6 1865
+#define n_B6 1976
+#define n_C7 2093
+#define n_CS7 2217
+#define n_D7 2349
+#define n_DS7 2489
+#define n_E7 2637
+#define n_F7 2794
+#define n_FS7 2960
+#define n_G7 3136
+#define n_GS7 3322
+#define n_A7 3520
+#define n_AS7 3729
+#define n_B7 3951
+#define n_C8 4186
+#define n_CS8 4435
+#define n_D8 4699
+#define n_DS8 4978
+#define n_E8 5274
+#define n_F8 5587
+#define n_FS8 5920
+#define n_G8 6272
+#define n_GS8 6645
+#define n_A8 7040
+#define n_AS8 7459
+#define n_B8 7902
+
+namespace Anycubic {
+
+ void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed);
+
+ // Only uncomment the tunes you are using to save memory
+ // This will help you write tunes!
+ // https://www.apronus.com/music/flashpiano.htm
+
+ const uint16_t SOS[] = {
+ 250,
+ n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1,
+ n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T1,
+ n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1,
+ n_END
+ };
+
+ const uint16_t BeepBeep[] = {
+ 500,
+ n_C7,l_T8, n_P,l_T16, n_C7,l_T8, n_P,l_T8,
+ n_END
+ };
+
+ const uint16_t BeepBeepBeeep[] = {
+ 1000,
+ n_G7,l_T4, n_P,l_T16, n_G7,l_T4, n_P,l_T8, n_G7,l_T2,
+ n_END
+ };
+
+ const uint16_t Anycubic_PowerOn[] = {
+ 1000,
+ n_F7,l_T8, n_P,l_T8, n_C7,l_T8, n_P,l_T8, n_D7,l_T8, n_P,l_T8,
+ n_E7,l_T8, n_P,l_T8, n_D7,l_T4, n_P,l_T4, n_G7,l_T4, n_P,l_T4,
+ n_A7,l_T2, n_P,l_T1,
+ n_END
+ };
+
+ const uint16_t GB_PowerOn[] = {
+ 500,
+ n_C6,l_T4, n_P,l_T16, n_C7,l_T2, n_P,l_T8,
+ n_END
+ };
+
+ const uint16_t Heater_Timedout[] = {
+ 1000,
+ n_C6,l_T1,
+ n_END
+ };
+
+ const uint16_t FilamentOut[] = {
+ 1000,
+ n_AS7,l_T4, n_P,l_T16, n_FS7,l_T2,
+ n_END
+ };
+
+}
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp
new file mode 100644
index 0000000..61057b5
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp
@@ -0,0 +1,885 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * lcd/extui/lib/chiron_tft.cpp
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+
+#include "chiron_tft.h"
+#include "Tunes.h"
+#include "FileNavigator.h"
+
+#include "../../../../gcode/queue.h"
+#include "../../../../sd/cardreader.h"
+#include "../../../../libs/numtostr.h"
+#include "../../../../MarlinCore.h"
+
+namespace Anycubic {
+
+ printer_state_t ChironTFT::printer_state;
+ paused_state_t ChironTFT::pause_state;
+ heater_state_t ChironTFT::hotend_state;
+ heater_state_t ChironTFT::hotbed_state;
+ xy_uint8_t ChironTFT::selectedmeshpoint;
+ char ChironTFT::selectedfile[MAX_PATH_LEN];
+ char ChironTFT::panel_command[MAX_CMND_LEN];
+ uint8_t ChironTFT::command_len;
+ float ChironTFT::live_Zoffset;
+ file_menu_t ChironTFT::file_menu;
+
+ ChironTFT Chiron;
+
+ ChironTFT::ChironTFT(){}
+
+ void ChironTFT::Startup() {
+ selectedfile[0] = '\0';
+ panel_command[0] = '\0';
+ command_len = 0;
+ printer_state = AC_printer_idle;
+ pause_state = AC_paused_idle;
+ hotend_state = AC_heater_off;
+ hotbed_state = AC_heater_off;
+ live_Zoffset = 0.0;
+ file_menu = AC_menu_file;
+
+ // Setup pins for powerloss detection
+ // Two IO pins are connected on the Trigorilla Board
+ // On a power interruption the OUTAGECON_PIN goes low.
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ OUT_WRITE(OUTAGECON_PIN, HIGH);
+ #endif
+
+ // Filament runout is handled by Marlin settings in Configuration.h
+ // opt_set FIL_RUNOUT_STATE HIGH // Pin state indicating that filament is NOT present.
+ // opt_enable FIL_RUNOUT_PULLUP
+
+ TFTSer.begin(115200);
+
+ // Signal Board has reset
+ SendtoTFTLN(AC_msg_main_board_has_reset);
+
+ safe_delay(200);
+
+ // Enable leveling and Disable end stops during print
+ // as Z home places nozzle above the bed so we need to allow it past the end stops
+ injectCommands_P(AC_cmnd_enable_leveling);
+
+ // Startup tunes are defined in Tunes.h
+ //PlayTune(BEEPER_PIN, Anycubic_PowerOn, 1);
+ PlayTune(BEEPER_PIN, GB_PowerOn, 1);
+ #if ACDEBUGLEVEL
+ SERIAL_ECHOLNPAIR("AC Debug Level ", ACDEBUGLEVEL);
+ #endif
+ SendtoTFTLN(AC_msg_ready);
+ }
+
+ void ChironTFT::IdleLoop() {
+ if (ReadTFTCommand()) {
+ ProcessPanelRequest();
+ command_len = 0;
+ }
+ CheckHeaters();
+ }
+
+ void ChironTFT::PrinterKilled(PGM_P error,PGM_P component) {
+ SendtoTFTLN(AC_msg_kill_lcd);
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPAIR("PrinterKilled()\nerror: ", error , "\ncomponent: ", component);
+ #endif
+ }
+
+ void ChironTFT::MediaEvent(media_event_t event) {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPAIR("ProcessMediaStatus() ", event);
+ #endif
+ switch (event) {
+ case AC_media_inserted:
+ SendtoTFTLN(AC_msg_sd_card_inserted);
+ break;
+
+ case AC_media_removed:
+ SendtoTFTLN(AC_msg_sd_card_removed);
+ break;
+
+ case AC_media_error:
+ SendtoTFTLN(AC_msg_no_sd_card);
+ break;
+ }
+ }
+
+ void ChironTFT::TimerEvent(timer_event_t event) {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPAIR("TimerEvent() ", event);
+ SERIAL_ECHOLNPAIR("Printer State: ", printer_state);
+ #endif
+
+ switch (event) {
+ case AC_timer_started: {
+ live_Zoffset = 0.0; // reset print offset
+ setSoftEndstopState(false); // disable endstops to print
+ printer_state = AC_printer_printing;
+ SendtoTFTLN(AC_msg_print_from_sd_card);
+ } break;
+
+ case AC_timer_paused: {
+ printer_state = AC_printer_paused;
+ pause_state = AC_paused_idle;
+ SendtoTFTLN(AC_msg_paused);
+ } break;
+
+ case AC_timer_stopped: {
+ if (printer_state != AC_printer_idle) {
+ printer_state = AC_printer_stopping;
+ SendtoTFTLN(AC_msg_print_complete);
+ }
+ setSoftEndstopState(true); // enable endstops
+ } break;
+ }
+ }
+
+ void ChironTFT::FilamentRunout() {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPAIR("FilamentRunout() printer_state ", printer_state);
+ #endif
+ // 1 Signal filament out
+ SendtoTFTLN(isPrintingFromMedia() ? AC_msg_filament_out_alert : AC_msg_filament_out_block);
+ //printer_state = AC_printer_filament_out;
+ PlayTune(BEEPER_PIN, FilamentOut, 1);
+ }
+
+ void ChironTFT::ConfirmationRequest(const char * const msg) {
+ // M108 continue
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPAIR("ConfirmationRequest() ", msg, " printer_state:", printer_state);
+ #endif
+ switch (printer_state) {
+ case AC_printer_pausing: {
+ if (strcmp_P(msg, MARLIN_msg_print_paused) == 0 || strcmp_P(msg, MARLIN_msg_nozzle_parked) == 0) {
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ printer_state = AC_printer_paused;
+ }
+ } break;
+
+ case AC_printer_resuming_from_power_outage:
+ case AC_printer_printing:
+ case AC_printer_paused: {
+ // Heater timout, send acknowledgement
+ if (strcmp_P(msg, MARLIN_msg_heater_timeout) == 0) {
+ pause_state = AC_paused_heater_timed_out;
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ PlayTune(BEEPER_PIN,Heater_Timedout,1);
+ }
+ // Reheat finished, send acknowledgement
+ else if (strcmp_P(msg, MARLIN_msg_reheat_done) == 0) {
+ pause_state = AC_paused_idle;
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ }
+ // Filament Purging, send acknowledgement enter run mode
+ else if (strcmp_P(msg, MARLIN_msg_filament_purging) == 0) {
+ pause_state = AC_paused_purging_filament;
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ void ChironTFT::StatusChange(const char * const msg) {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPAIR("StatusChange() ", msg);
+ SERIAL_ECHOLNPAIR("printer_state:", printer_state);
+ #endif
+ bool msg_matched = false;
+ // The only way to get printer status is to parse messages
+ // Use the state to minimise the work we do here.
+ switch (printer_state) {
+ case AC_printer_probing: {
+ // If probing completes ok save the mesh and park
+ // Ignore the custom machine name
+ if (strcmp_P(msg + strlen(CUSTOM_MACHINE_NAME), MARLIN_msg_ready) == 0) {
+ injectCommands_P(PSTR("M500\nG27"));
+ SendtoTFTLN(AC_msg_probing_complete);
+ printer_state = AC_printer_idle;
+ msg_matched = true;
+ }
+ // If probing fails dont save the mesh raise the probe above the bad point
+ if (strcmp_P(msg, MARLIN_msg_probing_failed) == 0) {
+ PlayTune(BEEPER_PIN, BeepBeepBeeep, 1);
+ injectCommands_P(PSTR("G1 Z50 F500"));
+ SendtoTFTLN(AC_msg_probing_complete);
+ printer_state = AC_printer_idle;
+ msg_matched = true;
+ }
+ } break;
+
+ case AC_printer_printing: {
+ if (strcmp_P(msg, MARLIN_msg_reheating) == 0) {
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ msg_matched = true;
+ }
+ } break;
+
+ case AC_printer_pausing: {
+ if (strcmp_P(msg, MARLIN_msg_print_paused) == 0) {
+ SendtoTFTLN(AC_msg_paused);
+ printer_state = AC_printer_paused;
+ pause_state = AC_paused_idle;
+ msg_matched = true;
+ }
+ } break;
+
+ case AC_printer_stopping: {
+ if (strcmp_P(msg, MARLIN_msg_print_aborted) == 0) {
+ SendtoTFTLN(AC_msg_stop);
+ printer_state = AC_printer_idle;
+ msg_matched = true;
+ }
+ } break;
+ default:
+ break;
+ }
+
+ // If not matched earlier see if this was a heater message
+ if (!msg_matched) {
+ if (strcmp_P(msg, MARLIN_msg_extruder_heating) == 0) {
+ SendtoTFTLN(AC_msg_nozzle_heating);
+ hotend_state = AC_heater_temp_set;
+ }
+ else if (strcmp_P(msg, MARLIN_msg_bed_heating) == 0) {
+ SendtoTFTLN(AC_msg_bed_heating);
+ hotbed_state = AC_heater_temp_set;
+ }
+ }
+ }
+
+ void ChironTFT::PowerLossRecovery() {
+ printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover.
+ PlayTune(BEEPER_PIN, SOS, 1);
+ SERIAL_ECHOLNPGM("Resuming from power outage...");
+ SERIAL_ECHOLNPGM("Select SD file then press resume");
+ }
+
+ void ChironTFT::SendtoTFT(PGM_P str) { // A helper to print PROGMEN string to the panel
+ #if ACDEBUG(AC_SOME)
+ serialprintPGM(str);
+ #endif
+ while (const char c = pgm_read_byte(str++)) TFTSer.print(c);
+ }
+
+ void ChironTFT::SendtoTFTLN(PGM_P str = nullptr) {
+ if (str) {
+ #if ACDEBUG(AC_SOME)
+ SERIAL_ECHOPGM("> ");
+ #endif
+ SendtoTFT(str);
+ #if ACDEBUG(AC_SOME)
+ SERIAL_EOL();
+ #endif
+ }
+ TFTSer.println("");
+ }
+
+ bool ChironTFT::ReadTFTCommand() {
+ bool command_ready = false;
+ while(TFTSer.available() > 0 && command_len < MAX_CMND_LEN) {
+ panel_command[command_len] = TFTSer.read();
+ if (panel_command[command_len] == '\n') {
+ command_ready = true;
+ break;
+ }
+ command_len++;
+ }
+
+ if (command_ready) {
+ panel_command[command_len] = 0x00;
+ #if ACDEBUG(AC_ALL)
+ SERIAL_ECHOLNPAIR("< ", panel_command);
+ #endif
+ #if ACDEBUG(AC_SOME)
+ // Ignore status request commands
+ uint8_t req = atoi(&panel_command[1]);
+ if (req > 7 && req != 20) {
+ SERIAL_ECHOLNPAIR("> ", panel_command);
+ SERIAL_ECHOLNPAIR("printer_state:", printer_state);
+ }
+ #endif
+ }
+ return command_ready;
+ }
+
+ int8_t ChironTFT::Findcmndpos(const char * buff, char q) {
+ int8_t pos = 0;
+ do { if (buff[pos] == q) return pos; } while(++pos < MAX_CMND_LEN);
+ return -1;
+ }
+
+ void ChironTFT::CheckHeaters() {
+ uint8_t faultDuration = 0;
+ float temp = 0;
+
+ // if the hotend temp is abnormal, confirm state before signalling panel
+ temp = getActualTemp_celsius(E0);
+ while (!WITHIN(temp, HEATER_0_MINTEMP, HEATER_0_MAXTEMP)) {
+ faultDuration++;
+ if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) {
+ SendtoTFTLN(AC_msg_nozzle_temp_abnormal);
+ SERIAL_ECHOLNPAIR("Extruder temp abnormal! : ", temp);
+ break;
+ }
+ delay_ms(500);
+ temp = getActualTemp_celsius(E0);
+ }
+
+ // If the hotbed temp is abnormal, confirm state before signaling panel
+ faultDuration = 0;
+ temp = getActualTemp_celsius(BED);
+ while (!WITHIN(temp, BED_MINTEMP, BED_MAXTEMP)) {
+ faultDuration++;
+ if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) {
+ SendtoTFTLN(AC_msg_nozzle_temp_abnormal);
+ SERIAL_ECHOLNPAIR("Bed temp abnormal! : ", temp);
+ break;
+ }
+ delay_ms(500);
+ temp = getActualTemp_celsius(E0);
+ }
+
+ // Update panel with hotend heater status
+ if (hotend_state != AC_heater_temp_reached) {
+ if (WITHIN(getActualTemp_celsius(E0) - getTargetTemp_celsius(E0), -1, 1)) {
+ SendtoTFTLN(AC_msg_nozzle_heating_done);
+ hotend_state = AC_heater_temp_reached;
+ }
+ }
+
+ // Update panel with bed heater status
+ if (hotbed_state != AC_heater_temp_reached) {
+ if (WITHIN(getActualTemp_celsius(BED) - getTargetTemp_celsius(BED), -0.5, 0.5)) {
+ SendtoTFTLN(AC_msg_bed_heating_done);
+ hotbed_state = AC_heater_temp_reached;
+ }
+ }
+ }
+
+ void ChironTFT::SendFileList(int8_t startindex) {
+ // Respond to panel request for 4 files starting at index
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("## SendFileList ## ", startindex);
+ #endif
+ SendtoTFTLN(PSTR("FN "));
+ filenavigator.getFiles(startindex);
+ SendtoTFTLN(PSTR("END"));
+ }
+
+ void ChironTFT::SelectFile() {
+ strncpy(selectedfile, panel_command + 4, command_len - 4);
+ selectedfile[command_len - 5] = '\0';
+ #if ACDEBUG(AC_FILE)
+ SERIAL_ECHOLNPAIR_F(" Selected File: ",selectedfile);
+ #endif
+ switch (selectedfile[0]) {
+ case '/': // Valid file selected
+ SendtoTFTLN(AC_msg_sd_file_open_success);
+ break;
+
+ case '<': // .. (go up folder level)
+ filenavigator.upDIR();
+ SendtoTFTLN(AC_msg_sd_file_open_failed);
+ SendFileList( 0 );
+ break;
+ default: // enter sub folder
+ filenavigator.changeDIR(selectedfile);
+ SendtoTFTLN(AC_msg_sd_file_open_failed);
+ SendFileList( 0 );
+ break;
+ }
+ }
+
+ void ChironTFT::InjectCommandandWait(PGM_P cmd) {
+ //injectCommands_P(cmnd); queue.enqueue_now_P(cmd);
+ //SERIAL_ECHOLN(PSTR("Inject>"));
+ }
+
+ void ChironTFT::ProcessPanelRequest() {
+ // Break these up into logical blocks // as its easier to navigate than one huge switch case!
+ int8_t req = atoi(&panel_command[1]);
+
+ // Information requests A0 - A8 and A33
+ if (req <= 8 || req == 33) PanelInfo(req);
+
+ // Simple Actions A9 - A28
+ else if ( req <= 28) PanelAction(req);
+
+ // Process Initiation
+ else if (req <= 34) PanelProcess(req);
+
+ else SendtoTFTLN();
+ }
+
+ void ChironTFT::PanelInfo(uint8_t req) {
+ // information requests A0-A8 and A33
+ switch (req) {
+ case 0: // A0 Get HOTEND Temp
+ SendtoTFT(PSTR("A0V "));
+ TFTSer.println(getActualTemp_celsius(E0));
+ break;
+
+ case 1: // A1 Get HOTEND Target Temp
+ SendtoTFT(PSTR("A1V "));
+ TFTSer.println(getTargetTemp_celsius(E0));
+ break;
+
+ case 2: // A2 Get BED Temp
+ SendtoTFT(PSTR("A2V "));
+ TFTSer.println(getActualTemp_celsius(BED));
+ break;
+
+ case 3: // A3 Get BED Target Temp
+ SendtoTFT(PSTR("A3V "));
+ TFTSer.println(getTargetTemp_celsius(BED));
+ break;
+
+ case 4: // A4 Get FAN Speed
+ SendtoTFT(PSTR("A4V "));
+ TFTSer.println(getActualFan_percent(FAN0));
+ break;
+
+ case 5: // A5 Get Current Coordinates
+ SendtoTFT(PSTR("A5V X: "));
+ TFTSer.print(getAxisPosition_mm(X));
+ SendtoTFT(PSTR(" Y: "));
+ TFTSer.print(getAxisPosition_mm(Y));
+ SendtoTFT(PSTR(" Z: "));
+ TFTSer.println(getAxisPosition_mm(Z));
+ break;
+
+ case 6: // A6 Get printing progress
+ if (isPrintingFromMedia()) {
+ SendtoTFT(PSTR("A6V "));
+ TFTSer.println(ui8tostr2(getProgress_percent()));
+ }
+ else
+ SendtoTFTLN(PSTR("A6V ---"));
+ break;
+
+ case 7: { // A7 Get Printing Time
+ uint32_t time = getProgress_seconds_elapsed() / 60;
+ SendtoTFT(PSTR("A7V "));
+ TFTSer.print(ui8tostr2(time / 60));
+ SendtoTFT(PSTR(" H "));
+ TFTSer.print(ui8tostr2(time % 60));
+ SendtoTFT(PSTR(" M"));
+ #if ACDEBUG(AC_ALL)
+ SERIAL_ECHOLNPAIR("Print time ", ui8tostr2(time / 60), ":", ui8tostr2(time % 60));
+ #endif
+ } break;
+
+ case 8: // A8 Get SD Card list A8 S0
+ if (!isMediaInserted()) safe_delay(500);
+ if (!isMediaInserted()) // Make sure the card is removed
+ SendtoTFTLN(AC_msg_no_sd_card);
+ else if (panel_command[3] == 'S')
+ SendFileList( atoi( &panel_command[4] ) );
+ break;
+
+ case 33: // A33 Get firmware info
+ SendtoTFT(PSTR("J33 "));
+ SendtoTFTLN(PSTR(SHORT_BUILD_VERSION));
+ break;
+ }
+ }
+
+ void ChironTFT::PanelAction(uint8_t req) {
+ switch (req) {
+ case 9: // A9 Pause SD print
+ if (isPrintingFromMedia()) {
+ SendtoTFTLN(AC_msg_pause);
+ pausePrint();
+ printer_state = AC_printer_pausing;
+ }
+ else
+ SendtoTFTLN(AC_msg_stop);
+ break;
+
+ case 10: // A10 Resume SD Print
+ if (pause_state == AC_paused_idle || printer_state == AC_printer_resuming_from_power_outage)
+ resumePrint();
+ else
+ setUserConfirmed();
+ break;
+
+ case 11: // A11 Stop SD print
+ if (isPrintingFromMedia()) {
+ printer_state = AC_printer_stopping;
+ stopPrint();
+ }
+ else {
+ if (printer_state == AC_printer_resuming_from_power_outage)
+ injectCommands_P(PSTR("M1000 C")); // Cancel recovery
+ SendtoTFTLN(AC_msg_stop);
+ printer_state = AC_printer_idle;
+ }
+ break;
+
+ case 12: // A12 Kill printer
+ kill(); // from marlincore.h
+ break;
+
+ case 13: // A13 Select file
+ SelectFile();
+ break;
+
+ case 14: { // A14 Start Printing
+ // Allows printer to restart the job if we dont want to recover
+ if (printer_state == AC_printer_resuming_from_power_outage) {
+ injectCommands_P(PSTR("M1000 C")); // Cancel recovery
+ printer_state = AC_printer_idle;
+ }
+ #if ACDebugLevel >= 1
+ SERIAL_ECHOLNPAIR_F("Print: ", selectedfile);
+ #endif
+ // the card library needs a path starting // but the File api doesn't...
+ char file[MAX_PATH_LEN];
+ file[0] = '/';
+ strcpy(file + 1, selectedfile);
+ printFile(file);
+ SendtoTFTLN(AC_msg_print_from_sd_card);
+ } break;
+
+ case 15: // A15 Resuming from outage
+ if (printer_state == AC_printer_resuming_from_power_outage) {
+ // Need to home here to restore the Z position
+ injectCommands(AC_cmnd_power_loss_recovery);
+ injectCommands("M1000"); // home and start recovery
+ }
+ break;
+
+ case 16: { // A16 Set HotEnd temp A17 S170
+ const float set_Htemp = atof(&panel_command[5]);
+ hotend_state = set_Htemp ? AC_heater_temp_set : AC_heater_off;
+ switch ((char)panel_command[4]) {
+ // Set Temp
+ case 'S': case 'C': setTargetTemp_celsius(set_Htemp, E0);
+ }
+ } break;
+
+ case 17: { // A17 Set bed temp
+ const float set_Btemp = atof(&panel_command[5]);
+ hotbed_state = set_Btemp ? AC_heater_temp_set : AC_heater_off;
+ if (panel_command[4] == 'S')
+ setTargetTemp_celsius(set_Btemp, BED);
+ } break;
+
+ case 18: // A18 Set Fan Speed
+ if (panel_command[4] == 'S')
+ setTargetFan_percent(atof(&panel_command[5]), FAN0);
+ break;
+
+ case 19: // A19 Motors off
+ if (!isPrinting()) {
+ disable_all_steppers(); // from marlincore.h
+ SendtoTFTLN(AC_msg_ready);
+ }
+ break;
+
+ case 20: // A20 Read/write print speed
+ if (panel_command[4] == 'S')
+ setFeedrate_percent(atoi(&panel_command[5]));
+ else {
+ SendtoTFT(PSTR("A20V "));
+ TFTSer.println(getFeedrate_percent());
+ }
+ break;
+
+ case 21: // A21 Home Axis A21 X
+ if (!isPrinting()) {
+ switch ((char)panel_command[4]) {
+ case 'X': injectCommands_P(PSTR("G28X")); break;
+ case 'Y': injectCommands_P(PSTR("G28Y")); break;
+ case 'Z': injectCommands_P(PSTR("G28Z")); break;
+ case 'C': injectCommands_P(G28_STR); break;
+ }
+ }
+ break;
+
+ case 22: // A22 Move Axis A22 Y +10F3000
+ // Ignore request if printing
+ if (!isPrinting()) {
+ // setAxisPosition_mm() uses pre defined manual feedrates so ignore the feedrate from the panel
+ setSoftEndstopState(true); // enable endstops
+ float newposition = atof(&panel_command[6]);
+
+ #if ACDEBUG(AC_ACTION)
+ SERIAL_ECHOLNPAIR("Nudge ", panel_command[4], " axis ", newposition);
+ #endif
+
+ switch (panel_command[4]) {
+ case 'X': setAxisPosition_mm(getAxisPosition_mm(X) + newposition, X); break;
+ case 'Y': setAxisPosition_mm(getAxisPosition_mm(Y) + newposition, Y); break;
+ case 'Z': setAxisPosition_mm(getAxisPosition_mm(Z) + newposition, Z); break;
+ case 'E': // The only time we get this command is from the filament load/unload menu
+ // the standard movement is too slow so we will use the load unlod GCode to speed it up a bit
+ if (canMove(E0) && !commandsInQueue())
+ injectCommands_P(newposition > 0 ? AC_cmnd_manual_load_filament : AC_cmnd_manual_unload_filament);
+ break;
+ }
+ }
+ break;
+
+ case 23: // A23 Preheat PLA
+ // Ignore request if printing
+ if (!isPrinting()) {
+ // Temps defined in configuration.h
+ setTargetTemp_celsius(PREHEAT_1_TEMP_BED, BED);
+ setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, E0);
+ SendtoTFTLN();
+ hotbed_state = AC_heater_temp_set;
+ hotend_state = AC_heater_temp_set;
+ }
+ break;
+
+ case 24: // A24 Preheat ABS
+ // Ignore request if printing
+ if (!isPrinting()) {
+ setTargetTemp_celsius(PREHEAT_2_TEMP_BED, BED);
+ setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, E0);
+ SendtoTFTLN();
+ hotbed_state = AC_heater_temp_set;
+ hotend_state = AC_heater_temp_set;
+ }
+ break;
+
+ case 25: // A25 Cool Down
+ // Ignore request if printing
+ if (!isPrinting()) {
+ setTargetTemp_celsius(0, E0);
+ setTargetTemp_celsius(0, BED);
+ SendtoTFTLN(AC_msg_ready);
+ hotbed_state = AC_heater_off;
+ hotend_state = AC_heater_off;
+ }
+ break;
+
+ case 26: // A26 Refresh SD
+ // M22 M21 maybe needed here to reset sd card
+ filenavigator.reset();
+ break;
+
+ case 27: // A27 Servo Angles adjust
+ break;
+
+ case 28: // A28 Filament set A28 O/C
+ // Ignore request if printing
+ if (isPrinting()) break;
+ SendtoTFTLN();
+ break;
+ }
+ }
+
+ void ChironTFT::PanelProcess(uint8_t req) {
+ switch (req) {
+ case 29: { // A29 Read Mesh Point A29 X1 Y1
+ xy_uint8_t pos;
+ float pos_z;
+ pos.x = atoi(&panel_command[5]);
+ pos.y = atoi(&panel_command[8]);
+ pos_z = getMeshPoint(pos);
+
+ SendtoTFT(PSTR("A29V "));
+ TFTSer.println(pos_z * 100);
+ if (!isPrinting()) {
+ setSoftEndstopState(true); // disable endstops
+ // If the same meshpoint is selected twice in a row, move the head to that ready for adjustment
+ if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) {
+ if (!isPositionKnown())
+ injectCommands_P(G28_STR); // home
+
+ if (isPositionKnown()) {
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Moving to mesh point at x: ", pos.x, " y: ", pos.y, " z: ", pos_z);
+ #endif
+ // Go up before moving
+ setAxisPosition_mm(3.0,Z);
+
+ setAxisPosition_mm(17 + (93 * pos.x), X);
+ setAxisPosition_mm(20 + (93 * pos.y), Y);
+ setAxisPosition_mm(0.0, Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Current Z: ", getAxisPosition_mm(Z));
+ #endif
+ }
+ }
+ selectedmeshpoint.x = pos.x;
+ selectedmeshpoint.y = pos.y;
+ }
+ } break;
+
+ case 30: { // A30 Auto leveling
+ if (panel_command[3] == 'S') { // Start probing
+ // Ignore request if printing
+ if (isPrinting())
+ SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling
+ else {
+ injectCommands_P(PSTR("G28O\nG29"));
+ printer_state = AC_printer_probing;
+ SendtoTFTLN(AC_msg_start_probing);
+ }
+ }
+ else SendtoTFTLN(AC_msg_start_probing);
+ } break;
+
+ case 31: { // A31 Adjust all Probe Points
+ switch (panel_command[3]) {
+ case 'C': // Restore and apply original offsets
+ if (!isPrinting()) {
+ injectCommands_P(PSTR("M501\nM420 S1"));
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ }
+ break;
+ case 'D': // Save Z Offset tables and restore leveling state
+ if (!isPrinting()) {
+ setAxisPosition_mm(1.0,Z);
+ injectCommands_P(PSTR("M500"));
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ }
+ break;
+ case 'G': // Get current offset
+ SendtoTFT(PSTR("A31V "));
+ // When printing use the live z Offset position
+ // we will use babystepping to move the print head
+ if (isPrinting())
+ TFTSer.println(live_Zoffset);
+ else {
+ TFTSer.println(getZOffset_mm());
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ }
+ break;
+ case 'S': { // Set offset (adjusts all points by value)
+ float Zshift = atof(&panel_command[4]);
+ setSoftEndstopState(false); // disable endstops
+ // Allow temporary Z position nudging during print
+ // From the leveling panel use the all points UI to adjust the print pos.
+ if (isPrinting()) {
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Change Zoffset from:", live_Zoffset, " to ", live_Zoffset + Zshift);
+ #endif
+ if (isAxisPositionKnown(Z)) {
+ #if ACDEBUG(AC_INFO)
+ const float currZpos = getAxisPosition_mm(Z);
+ SERIAL_ECHOLNPAIR("Nudge Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05));
+ #endif
+ // Use babystepping to adjust the head position
+ int16_t steps = mmToWholeSteps(constrain(Zshift,-0.05,0.05), Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Steps to move Z: ", steps);
+ #endif
+ babystepAxis_steps(steps, Z);
+ live_Zoffset += Zshift;
+ }
+ SendtoTFT(PSTR("A31V "));
+ TFTSer.println(live_Zoffset);
+ }
+ else {
+ GRID_LOOP(x, y) {
+ const xy_uint8_t pos { x, y };
+ const float currval = getMeshPoint(pos);
+ setMeshPoint(pos, constrain(currval + Zshift, AC_LOWEST_MESHPOINT_VAL, 2));
+ }
+ const float currZOffset = getZOffset_mm();
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Change probe offset from ", currZOffset, " to ", currZOffset + Zshift);
+ #endif
+
+ setZOffset_mm(currZOffset + Zshift);
+ SendtoTFT(PSTR("A31V "));
+ TFTSer.println(getZOffset_mm());
+
+ if (isAxisPositionKnown(Z)) {
+ // Move Z axis
+ const float currZpos = getAxisPosition_mm(Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05));
+ #endif
+ setAxisPosition_mm(currZpos+constrain(Zshift,-0.05,0.05),Z);
+ }
+ }
+ } break;
+ } // end switch
+ } break;
+
+ case 32: { // A32 clean leveling beep flag
+ // Ignore request if printing
+ //if (isPrinting()) break;
+ //injectCommands_P(PSTR("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000"));
+ //TFTSer.println("");
+ } break;
+
+ // A33 firmware info request seet PanelInfo()
+
+ case 34: { // A34 Adjust single mesh point A34 C/S X1 Y1 V123
+ if (panel_command[3] == 'C') { // Restore original offsets
+ injectCommands_P(PSTR("M501\nM420 S1"));
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ //printer_state = AC_printer_idle;
+ }
+ else {
+ xy_uint8_t pos;
+ pos.x = atoi(&panel_command[5]);
+ pos.y = atoi(&panel_command[8]);
+
+ float currmesh = getMeshPoint(pos);
+ float newval = atof(&panel_command[11])/100;
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Change mesh point x:", pos.x, " y:", pos.y);
+ SERIAL_ECHOLNPAIR("from ", currmesh, " to ", newval);
+ #endif
+ // Update Meshpoint
+ setMeshPoint(pos,newval);
+ if (printer_state == AC_printer_idle || printer_state == AC_printer_probing /*!isPrinting()*/) {
+ // if we are at the current mesh point indicated on the panel Move Z pos +/- 0.05mm
+ // (The panel changes the mesh value by +/- 0.05mm on each button press)
+ if (selectedmeshpoint.x == pos.x && selectedmeshpoint.y == pos.y) {
+ setSoftEndstopState(false);
+ float currZpos = getAxisPosition_mm(Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPAIR("Move Z pos from ", currZpos, " to ", currZpos + constrain(newval - currmesh, -0.05, 0.05));
+ #endif
+ setAxisPosition_mm(currZpos + constrain(newval - currmesh, -0.05, 0.05), Z);
+ }
+ }
+ }
+ } break;
+ }
+ }
+} // namespace
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h
new file mode 100644
index 0000000..267f2fe
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h
@@ -0,0 +1,77 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/lib/chiron_tft.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#include "chiron_tft_defs.h"
+#include "../../../../inc/MarlinConfigPre.h"
+#include "../../ui_api.h"
+namespace Anycubic {
+
+ class ChironTFT {
+ static printer_state_t printer_state;
+ static paused_state_t pause_state;
+ static heater_state_t hotend_state;
+ static heater_state_t hotbed_state;
+ static xy_uint8_t selectedmeshpoint;
+ static char panel_command[MAX_CMND_LEN];
+ static uint8_t command_len;
+ static char selectedfile[MAX_PATH_LEN];
+ static float live_Zoffset;
+ static file_menu_t file_menu;
+ public:
+ ChironTFT();
+ void Startup();
+ void IdleLoop();
+ void PrinterKilled(PGM_P,PGM_P);
+ void MediaEvent(media_event_t);
+ void TimerEvent(timer_event_t);
+ void FilamentRunout();
+ void ConfirmationRequest(const char * const );
+ void StatusChange(const char * const );
+ void PowerLossRecovery();
+
+ private:
+ void SendtoTFT(PGM_P);
+ void SendtoTFTLN(PGM_P);
+ bool ReadTFTCommand();
+ int8_t Findcmndpos(const char *, char);
+ void CheckHeaters();
+ void SendFileList(int8_t);
+ void SelectFile();
+ void InjectCommandandWait(PGM_P);
+ void ProcessPanelRequest();
+ void PanelInfo(uint8_t);
+ void PanelAction(uint8_t);
+ void PanelProcess(uint8_t);
+ };
+
+ extern ChironTFT Chiron;
+
+}
diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h
new file mode 100644
index 0000000..7012e98
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h
@@ -0,0 +1,151 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * lcd/extui/lib/chiron_defs.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#pragma once
+#include "../../../../inc/MarlinConfigPre.h"
+//#define ACDEBUGLEVEL 255
+
+#if ACDEBUGLEVEL
+ // Bit-masks for selective debug:
+ enum ACDebugMask : uint8_t {
+ AC_INFO = 1,
+ AC_ACTION = 2,
+ AC_FILE = 4,
+ AC_PANEL = 8,
+ AC_MARLIN = 16,
+ AC_SOME = 32,
+ AC_ALL = 64
+ };
+ #define ACDEBUG(mask) ( ((mask) & ACDEBUGLEVEL) == mask ) // Debug flag macro
+#else
+ #define ACDEBUG(mask) false
+#endif
+
+#define TFTSer LCD_SERIAL // Serial interface for TFT panel now uses marlinserial
+#define MAX_FOLDER_DEPTH 4 // Limit folder depth TFT has a limit for the file path
+#define MAX_CMND_LEN 16 * MAX_FOLDER_DEPTH // Maximum Length for a Panel command
+#define MAX_PATH_LEN 16 * MAX_FOLDER_DEPTH // Maximum number of characters in a SD file path
+
+#define AC_HEATER_FAULT_VALIDATION_TIME 5 // number of 1/2 second loops before signalling a heater fault
+#define AC_LOWEST_MESHPOINT_VAL Z_PROBE_LOW_POINT // The lowest value you can set for a single mesh point offset
+
+ // TFT panel commands
+#define AC_msg_sd_card_inserted PSTR("J00")
+#define AC_msg_sd_card_removed PSTR("J01")
+#define AC_msg_no_sd_card PSTR("J02")
+#define AC_msg_usb_connected PSTR("J03")
+#define AC_msg_print_from_sd_card PSTR("J04")
+#define AC_msg_pause PSTR("J05")
+#define AC_msg_nozzle_heating PSTR("J06")
+#define AC_msg_nozzle_heating_done PSTR("J07")
+#define AC_msg_bed_heating PSTR("J08")
+#define AC_msg_bed_heating_done PSTR("J09")
+#define AC_msg_nozzle_temp_abnormal PSTR("J10")
+#define AC_msg_kill_lcd PSTR("J11")
+#define AC_msg_ready PSTR("J12")
+#define AC_msg_low_nozzle_temp PSTR("J13")
+#define AC_msg_print_complete PSTR("J14")
+#define AC_msg_filament_out_alert PSTR("J15")
+#define AC_msg_stop PSTR("J16")
+#define AC_msg_main_board_has_reset PSTR("J17")
+#define AC_msg_paused PSTR("J18")
+#define AC_msg_j19_unknown PSTR("J19")
+#define AC_msg_sd_file_open_success PSTR("J20")
+#define AC_msg_sd_file_open_failed PSTR("J21")
+#define AC_msg_level_monitor_finished PSTR("J22")
+#define AC_msg_filament_out_block PSTR("J23")
+#define AC_msg_probing_not_allowed PSTR("J24")
+#define AC_msg_probing_complete PSTR("J25")
+#define AC_msg_start_probing PSTR("J26")
+#define AC_msg_version PSTR("J27")
+
+#define MARLIN_msg_start_probing PSTR("Probing Point 1/25")
+#define MARLIN_msg_probing_failed PSTR("Probing Failed")
+#define MARLIN_msg_ready PSTR(" Ready.")
+#define MARLIN_msg_print_paused PSTR("Print Paused")
+#define MARLIN_msg_print_aborted PSTR("Print Aborted")
+#define MARLIN_msg_extruder_heating PSTR("E Heating...")
+#define MARLIN_msg_bed_heating PSTR("Bed Heating...")
+
+#define MARLIN_msg_nozzle_parked PSTR("Nozzle Parked")
+#define MARLIN_msg_heater_timeout PSTR("Heater Timeout")
+#define MARLIN_msg_reheating PSTR("Reheating...")
+#define MARLIN_msg_reheat_done PSTR("Reheat finished.")
+#define MARLIN_msg_filament_purging PSTR("Filament Purging...")
+#define MARLIN_msg_special_pause PSTR("PB")
+#define AC_cmnd_auto_unload_filament PSTR("M701") // Use Marlin unload routine
+#define AC_cmnd_auto_load_filament PSTR("M702 M0 PB") // Use Marlin load routing then pause for user to clean nozzle
+
+#define AC_cmnd_manual_load_filament PSTR("M83\nG1 E50 F700\nM82") // replace the manual panel commands with something a little faster
+#define AC_cmnd_manual_unload_filament PSTR("M83\nG1 E-50 F1200\nM82")
+#define AC_cmnd_enable_leveling PSTR("M420SV")
+#define AC_cmnd_power_loss_recovery PSTR("G28XYR5\nG28Z") // Lift, home X and Y then home Z when in 'safe' position
+
+namespace Anycubic {
+ enum heater_state_t : uint8_t {
+ AC_heater_off,
+ AC_heater_temp_set,
+ AC_heater_temp_reached
+ };
+
+ enum paused_state_t : uint8_t {
+ AC_paused_heater_timed_out,
+ AC_paused_purging_filament,
+ AC_paused_idle
+ };
+
+ enum printer_state_t : uint8_t {
+ AC_printer_idle,
+ AC_printer_probing,
+ AC_printer_printing,
+ AC_printer_pausing,
+ AC_printer_paused,
+ AC_printer_stopping,
+ AC_printer_resuming_from_power_outage
+ };
+
+ enum timer_event_t : uint8_t {
+ AC_timer_started,
+ AC_timer_paused,
+ AC_timer_stopped
+ };
+
+ enum media_event_t : uint8_t {
+ AC_media_inserted,
+ AC_media_removed,
+ AC_media_error
+ };
+ enum file_menu_t : uint8_t {
+ AC_menu_file,
+ AC_menu_command,
+ AC_menu_change_to_file,
+ AC_menu_change_to_command
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp
new file mode 100644
index 0000000..1508dc0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp
@@ -0,0 +1,1028 @@
+/**
+ * anycubic_i3mega_lcd.cpp --- Support for Anycubic i3 Mega TFT
+ * Created by Christian Hopp on 09.12.17.
+ * Improved by David Ramiro
+ * Converted to ext_iu by John BouAntoun 21 June 2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_I3MEGA)
+
+#include "anycubic_i3mega_lcd.h"
+#include "../../ui_api.h"
+
+#include "../../../../libs/numtostr.h"
+#include "../../../../module/motion.h" // for quickstop_stepper, A20 read printing speed, feedrate_percentage
+#include "../../../../MarlinCore.h" // for disable_steppers
+#include "../../../../inc/MarlinConfig.h"
+
+// command sending macro's with debugging capability
+#define SEND_PGM(x) send_P(PSTR(x))
+#define SENDLINE_PGM(x) sendLine_P(PSTR(x))
+#define SEND_PGM_VAL(x,y) (send_P(PSTR(x)), sendLine(i16tostr3rj(y)))
+#define SEND(x) send(x)
+#define SENDLINE(x) sendLine(x)
+#if ENABLED(ANYCUBIC_LCD_DEBUG)
+ #define SENDLINE_DBG_PGM(x,y) (sendLine_P(PSTR(x)), SERIAL_ECHOLNPGM(y))
+ #define SENDLINE_DBG_PGM_VAL(x,y,z) (sendLine_P(PSTR(x)), SERIAL_ECHOPGM(y), SERIAL_ECHOLN(z))
+#else
+ #define SENDLINE_DBG_PGM(x,y) sendLine_P(PSTR(x))
+ #define SENDLINE_DBG_PGM_VAL(x,y,z) sendLine_P(PSTR(x))
+#endif
+
+AnycubicTFTClass AnycubicTFT;
+
+static void sendNewLine(void) {
+ LCD_SERIAL.write('\r');
+ LCD_SERIAL.write('\n');
+}
+
+static void send(const char *str) {
+ LCD_SERIAL.print(str);
+}
+
+static void sendLine(const char *str) {
+ send(str);
+ sendNewLine();
+}
+
+static void send_P(PGM_P str) {
+ while (const char c = pgm_read_byte(str++))
+ LCD_SERIAL.write(c);
+}
+
+static void sendLine_P(PGM_P str) {
+ send_P(str);
+ sendNewLine();
+}
+
+AnycubicTFTClass::AnycubicTFTClass() {}
+
+void AnycubicTFTClass::OnSetup() {
+ #ifndef LCD_BAUDRATE
+ #define LCD_BAUDRATE 115200
+ #endif
+ LCD_SERIAL.begin(LCD_BAUDRATE);
+
+ SENDLINE_DBG_PGM("J17", "TFT Serial Debug: Main board reset... J17"); // J17 Main board reset
+ ExtUI::delay_ms(10);
+
+ // initialise the state of the key pins running on the tft
+ #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)
+ SET_INPUT_PULLUP(SD_DETECT_PIN);
+ #endif
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ SET_INPUT_PULLUP(FIL_RUNOUT1_PIN);
+ #endif
+
+ mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+
+ // DoSDCardStateCheck();
+ SENDLINE_DBG_PGM("J12", "TFT Serial Debug: Ready... J12"); // J12 Ready
+ ExtUI::delay_ms(10);
+
+ DoFilamentRunoutCheck();
+ SelectedFile[0] = 0;
+
+ #if ENABLED(STARTUP_CHIME)
+ ExtUI::injectCommands_P(PSTR("M300 P250 S554\nM300 P250 S554\nM300 P250 S740\nM300 P250 S554\nM300 P250 S740\nM300 P250 S554\nM300 P500 S831"));
+ #endif
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: Finished startup");
+ #endif
+}
+
+void AnycubicTFTClass::OnCommandScan() {
+ static millis_t nextStopCheck = 0; // used to slow the stopped print check down to reasonable times
+ const millis_t ms = millis();
+ if (ELAPSED(ms, nextStopCheck)) {
+ nextStopCheck = ms + 1000UL;
+ if (mediaPrintingState == AMPRINTSTATE_STOP_REQUESTED && IsNozzleHomed()) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: Finished stopping print, releasing motors ...");
+ #endif
+ mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ ExtUI::injectCommands_P(PSTR("M84\nM27")); // disable stepper motors and force report of SD status
+ ExtUI::delay_ms(200);
+ // tell printer to release resources of print to indicate it is done
+ SENDLINE_DBG_PGM("J14", "TFT Serial Debug: SD Print Stopped... J14");
+ }
+ }
+
+ if (TFTbuflen < (TFTBUFSIZE - 1))
+ GetCommandFromTFT();
+
+ if (TFTbuflen) {
+ TFTbuflen = (TFTbuflen - 1);
+ TFTbufindr = (TFTbufindr + 1) % TFTBUFSIZE;
+ }
+}
+
+void AnycubicTFTClass::OnKillTFT() {
+ SENDLINE_DBG_PGM("J11", "TFT Serial Debug: Kill command... J11");
+}
+
+void AnycubicTFTClass::OnSDCardStateChange(bool isInserted) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOPGM("TFT Serial Debug: OnSDCardStateChange event triggered...");
+ SERIAL_ECHO(ui8tostr2(isInserted));
+ SERIAL_EOL();
+ #endif
+ DoSDCardStateCheck();
+}
+
+void AnycubicTFTClass::OnSDCardError() {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: OnSDCardError event triggered...");
+ #endif
+ SENDLINE_DBG_PGM("J21", "TFT Serial Debug: On SD Card Error ... J21");
+}
+
+void AnycubicTFTClass::OnFilamentRunout() {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: FilamentRunout triggered...");
+ #endif
+ DoFilamentRunoutCheck();
+}
+
+void AnycubicTFTClass::OnUserConfirmRequired(const char * const msg) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOPGM("TFT Serial Debug: OnUserConfirmRequired triggered... ");
+ SERIAL_ECHOLN(msg);
+ #endif
+
+ #if ENABLED(SDSUPPORT)
+ /**
+ * Need to handle the process of following states
+ * "Nozzle Parked"
+ * "Load Filament"
+ * "Filament Purging..."
+ * "HeaterTimeout"
+ * "Reheat finished."
+ *
+ * NOTE: The only way to handle these states is strcmp_P with the msg unfortunately (very expensive)
+ */
+ if (strcmp_P(msg, PSTR("Nozzle Parked")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_PARKED;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm SD print paused done... J18");
+ }
+ else if (strcmp_P(msg, PSTR("Load Filament")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_FILAMENT_OUT;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm Filament is out... J18");
+ SENDLINE_DBG_PGM("J23", "TFT Serial Debug: UserConfirm Blocking filament prompt... J23");
+ }
+ else if (strcmp_P(msg, PSTR("Filament Purging...")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_PARKING;
+ // TODO: JBA I don't think J05 just disables the continue button, i think it injects a rogue M25. So taking this out
+ // disable continue button
+ // SENDLINE_DBG_PGM("J05", "TFT Serial Debug: UserConfirm SD Filament Purging... J05"); // J05 printing pause
+
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm Filament is purging... J18");
+ }
+ else if (strcmp_P(msg, PSTR("HeaterTimeout")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_HEATER_TIMEOUT;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm SD Heater timeout... J18");
+ }
+ else if (strcmp_P(msg, PSTR("Reheat finished.")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_REHEAT_FINISHED;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm SD Reheat done... J18");
+ }
+ #endif
+}
+
+float AnycubicTFTClass::CodeValue() {
+ return (strtod(&TFTcmdbuffer[TFTbufindr][TFTstrchr_pointer - TFTcmdbuffer[TFTbufindr] + 1], nullptr));
+}
+
+bool AnycubicTFTClass::CodeSeen(char code) {
+ TFTstrchr_pointer = strchr(TFTcmdbuffer[TFTbufindr], code);
+ return !!TFTstrchr_pointer; // Return True if a character was found
+}
+
+bool AnycubicTFTClass::IsNozzleHomed() {
+ const float xPosition = ExtUI::getAxisPosition_mm((ExtUI::axis_t) ExtUI::X);
+ const float yPosition = ExtUI::getAxisPosition_mm((ExtUI::axis_t) ExtUI::Y);
+ return WITHIN(xPosition, X_MIN_POS - 0.1, X_MIN_POS + 0.1) &&
+ WITHIN(yPosition, Y_MIN_POS - 0.1, Y_MIN_POS + 0.1);
+}
+
+void AnycubicTFTClass::HandleSpecialMenu() {
+ /**
+ * NOTE: that the file selection command actual lowercases the entire selected file/foldername, so charracter comparisons need to be lowercase.
+ */
+ if (SelectedDirectory[0] == '<') {
+ switch (SelectedDirectory[1]) {
+ case 'e': // "<exit>"
+ SpecialMenu = false;
+ return;
+ break;
+
+ #if ENABLED(PROBE_MANUALLY)
+ case '0':
+ switch (SelectedDirectory[2]) {
+ case '1': // "<01ZUp0.1>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Up 0.1");
+ ExtUI::injectCommands_P(PSTR("G91\nG1 Z+0.1\nG90"));
+ break;
+
+ case '2': // "<02ZUp0.02>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Up 0.02");
+ ExtUI::injectCommands_P(PSTR("G91\nG1 Z+0.02\nG90"));
+ break;
+
+ case '3': // "<03ZDn0.02>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Down 0.02");
+ ExtUI::injectCommands_P(PSTR("G91\nG1 Z-0.02\nG90"));
+ break;
+
+ case '4': // "<04ZDn0.1>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Down 0.1");
+ ExtUI::injectCommands_P(PSTR("G91\nG1 Z-0.1\nG90"));
+ break;
+
+ case '5': // "<05PrehtBed>"
+ SERIAL_ECHOLNPGM("Special Menu: Preheat Bed");
+ ExtUI::injectCommands_P(PSTR("M140 S65"));
+ break;
+
+ case '6': // "<06SMeshLvl>"
+ SERIAL_ECHOLNPGM("Special Menu: Start Mesh Leveling");
+ ExtUI::injectCommands_P(PSTR("G29S1"));
+ break;
+
+ case '7': // "<07MeshNPnt>"
+ SERIAL_ECHOLNPGM("Special Menu: Next Mesh Point");
+ ExtUI::injectCommands_P(PSTR("G29S2"));
+ break;
+
+ case '8': // "<08HtEndPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotend PID");
+ // need to dwell for half a second to give the fan a chance to start before the pid tuning starts
+ ExtUI::injectCommands_P(PSTR("M106 S204\nG4 P500\nM303 E0 S215 C15 U1"));
+ break;
+
+ case '9': // "<09HtBedPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotbed Pid");
+ ExtUI::injectCommands_P(PSTR("M303 E-1 S65 C6 U1"));
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case '1':
+ switch (SelectedDirectory[2]) {
+ case '0': // "<10FWDeflts>"
+ SERIAL_ECHOLNPGM("Special Menu: Load FW Defaults");
+ ExtUI::injectCommands_P(PSTR("M502\nM300 P105 S1661\nM300 P210 S1108"));
+ break;
+
+ case '1': // "<11SvEEPROM>"
+ SERIAL_ECHOLNPGM("Special Menu: Save EEPROM");
+ ExtUI::injectCommands_P(PSTR("M500\nM300 P105 S1108\nM300 P210 S1661"));
+ break;
+
+ default:
+ break;
+ }
+ break;
+ #else // if ENABLED(PROBE_MANUALLY)
+ case '0':
+ switch (SelectedDirectory[2]) {
+ case '1': // "<01PrehtBed>"
+ SERIAL_ECHOLNPGM("Special Menu: Preheat Bed");
+ ExtUI::injectCommands_P(PSTR("M140 S65"));
+ break;
+
+ case '2': // "<02ABL>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Bed Leveling");
+ ExtUI::injectCommands_P(PSTR("G29N"));
+ break;
+
+ case '3': // "<03HtendPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotend PID");
+ // need to dwell for half a second to give the fan a chance to start before the pid tuning starts
+ ExtUI::injectCommands_P(PSTR("M106 S204\nG4 P500\nM303 E0 S215 C15 U1"));
+ break;
+
+ case '4': // "<04HtbedPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotbed Pid");
+ ExtUI::injectCommands_P(PSTR("M303 E-1 S65 C6 U1"));
+ break;
+
+ case '5': // "<05FWDeflts>"
+ SERIAL_ECHOLNPGM("Special Menu: Load FW Defaults");
+ ExtUI::injectCommands_P(PSTR("M502\nM300 P105 S1661\nM300 P210 S1108"));
+ break;
+
+ case '6': // "<06SvEEPROM>"
+ SERIAL_ECHOLNPGM("Special Menu: Save EEPROM");
+ ExtUI::injectCommands_P(PSTR("M500\nM300 P105 S1108\nM300 P210 S1661"));
+ break;
+
+ case '7': // <07SendM108>
+ SERIAL_ECHOLNPGM("Special Menu: Send User Confirmation");
+ ExtUI::injectCommands_P(PSTR("M108"));
+ break;
+
+ default:
+ break;
+ }
+ break;
+ #endif // PROBE_MANUALLY
+
+ default:
+ break;
+ }
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ }
+ else {
+ SERIAL_ECHOPGM("TFT Serial Debug: Attempted to HandleSpecialMenu on non-special menu... ");
+ SERIAL_ECHOLN(SelectedDirectory);
+ #endif
+ }
+}
+
+void AnycubicTFTClass::RenderCurrentFileList() {
+ #if ENABLED(SDSUPPORT)
+ uint16_t selectedNumber = 0;
+ SelectedDirectory[0] = 0;
+ SelectedFile[0] = 0;
+ ExtUI::FileList currentFileList;
+
+ SENDLINE_PGM("FN "); // Filelist start
+
+ if (!ExtUI::isMediaInserted() && !SpecialMenu) {
+ SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to render Current File List... J02");
+
+ SENDLINE_PGM("<Special_Menu>");
+ SENDLINE_PGM("<Special_Menu>");
+ }
+ else {
+ if (CodeSeen('S'))
+ selectedNumber = CodeValue();
+
+ if (SpecialMenu)
+ RenderSpecialMenu(selectedNumber);
+ else if (selectedNumber <= currentFileList.count())
+ RenderCurrentFolder(selectedNumber);
+ }
+ SENDLINE_PGM("END"); // Filelist stop
+ #endif // SDSUPPORT
+}
+
+void AnycubicTFTClass::RenderSpecialMenu(uint16_t selectedNumber) {
+ switch (selectedNumber) {
+ #if ENABLED(PROBE_MANUALLY)
+ case 0: // First Page
+ SENDLINE_PGM("<01ZUp0.1>");
+ SENDLINE_PGM("<Z Up 0.1>");
+ SENDLINE_PGM("<02ZUp0.02>");
+ SENDLINE_PGM("<Z Up 0.02>");
+ SENDLINE_PGM("<03ZDn0.02>");
+ SENDLINE_PGM("<Z Down 0.02>");
+ SENDLINE_PGM("<04ZDn0.1>");
+ SENDLINE_PGM("<Z Down 0.1>");
+ break;
+
+ case 4: // Second Page
+ SENDLINE_PGM("<05PrehtBed>");
+ SENDLINE_PGM("<Preheat bed>");
+ SENDLINE_PGM("<06SMeshLvl>");
+ SENDLINE_PGM("<Start Mesh Leveling>");
+ SENDLINE_PGM("<07MeshNPnt>");
+ SENDLINE_PGM("<Next Mesh Point>");
+ SENDLINE_PGM("<08HtEndPID>");
+ SENDLINE_PGM("<Auto Tune Hotend PID>");
+ break;
+
+ case 8: // Third Page
+ SENDLINE_PGM("<09HtBedPID>");
+ SENDLINE_PGM("<Auto Tune Hotbed PID>");
+ SENDLINE_PGM("<10FWDeflts>");
+ SENDLINE_PGM("<Load FW Defaults>");
+ SENDLINE_PGM("<11SvEEPROM>");
+ SENDLINE_PGM("<Save EEPROM>");
+ SENDLINE_PGM("<Exit>");
+ SENDLINE_PGM("<Exit>");
+ break;
+ #else
+ case 0: // First Page
+ SENDLINE_PGM("<01PrehtBed>");
+ SENDLINE_PGM("<Preheat bed>");
+ SENDLINE_PGM("<02ABL>");
+ SENDLINE_PGM("<Auto Bed Leveling>");
+ SENDLINE_PGM("<03HtEndPID>");
+ SENDLINE_PGM("<Auto Tune Hotend PID>");
+ SENDLINE_PGM("<04HtBedPID>");
+ SENDLINE_PGM("<Auto Tune Hotbed PID>");
+ break;
+
+ case 4: // Second Page
+ SENDLINE_PGM("<05FWDeflts>");
+ SENDLINE_PGM("<Load FW Defaults>");
+ SENDLINE_PGM("<06SvEEPROM>");
+ SENDLINE_PGM("<Save EEPROM>");
+ SENDLINE_PGM("<07SendM108>");
+ SENDLINE_PGM("<Send User Confirmation>");
+ SENDLINE_PGM("<Exit>");
+ SENDLINE_PGM("<Exit>");
+ break;
+
+ #endif // PROBE_MANUALLY
+
+ default:
+ break;
+ }
+}
+
+void AnycubicTFTClass::RenderCurrentFolder(uint16_t selectedNumber) {
+ ExtUI::FileList currentFileList;
+ uint16_t cnt = selectedNumber;
+ uint16_t max_files;
+ uint16_t dir_files = currentFileList.count();
+
+ if ((dir_files - selectedNumber) < 4)
+ max_files = dir_files;
+ else
+ max_files = selectedNumber + 3;
+
+ for (cnt = selectedNumber; cnt <= max_files; cnt++) {
+ if (cnt == 0) { // Special Entry
+ if (currentFileList.isAtRootDir()) {
+ SENDLINE_PGM("<specialmnu>");
+ SENDLINE_PGM("<Special Menu>");
+ }
+ else {
+ SENDLINE_PGM("/..");
+ SENDLINE_PGM("/..");
+ }
+ }
+ else {
+ currentFileList.seek(cnt - 1, false);
+
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLN(currentFileList.filename());
+ #endif
+ if (currentFileList.isDir()) {
+ SEND_PGM("/");
+ SENDLINE(currentFileList.shortFilename());
+ SEND_PGM("/");
+ SENDLINE(currentFileList.filename());
+
+ }
+ else {
+ SENDLINE(currentFileList.shortFilename());
+ SENDLINE(currentFileList.filename());
+ }
+ }
+ }
+}
+
+void AnycubicTFTClass::OnPrintTimerStarted() {
+ #if ENABLED(SDSUPPORT)
+ if (mediaPrintingState == AMPRINTSTATE_PRINTING)
+ SENDLINE_DBG_PGM("J04", "TFT Serial Debug: Starting SD Print... J04"); // J04 Starting Print
+
+ #endif
+}
+
+void AnycubicTFTClass::OnPrintTimerPaused() {
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isPrintingFromMedia()) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_PARKING;
+ }
+ #endif
+}
+
+void AnycubicTFTClass::OnPrintTimerStopped() {
+ #if ENABLED(SDSUPPORT)
+ if (mediaPrintingState == AMPRINTSTATE_PRINTING) {
+ mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ SENDLINE_DBG_PGM("J14", "TFT Serial Debug: SD Print Completed... J14");
+ }
+ // otherwise it was stopped by the printer so don't send print completed signal to TFT
+ #endif
+}
+
+void AnycubicTFTClass::GetCommandFromTFT() {
+ char *starpos = nullptr;
+ while (LCD_SERIAL.available() > 0 && TFTbuflen < TFTBUFSIZE) {
+ serial3_char = LCD_SERIAL.read();
+ if (serial3_char == '\n' ||
+ serial3_char == '\r' ||
+ serial3_char == ':' ||
+ serial3_count >= (TFT_MAX_CMD_SIZE - 1)
+ ) {
+
+ if (!serial3_count) return; // if empty line
+
+ TFTcmdbuffer[TFTbufindw][serial3_count] = 0; // terminate string
+
+ if ((strchr(TFTcmdbuffer[TFTbufindw], 'A') != nullptr)) {
+ int16_t a_command;
+ TFTstrchr_pointer = strchr(TFTcmdbuffer[TFTbufindw], 'A');
+ a_command = ((int)((strtod(&TFTcmdbuffer[TFTbufindw][TFTstrchr_pointer - TFTcmdbuffer[TFTbufindw] + 1], nullptr))));
+
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ if ((a_command > 7) && (a_command != 20)) { // No debugging of status polls, please!
+ SERIAL_ECHOPGM("TFT Serial Command: ");
+ SERIAL_ECHOLN(TFTcmdbuffer[TFTbufindw]);
+ }
+ #endif
+
+ switch (a_command) {
+ case 0: { // A0 GET HOTEND TEMP
+ float hotendActualTemp = ExtUI::getActualTemp_celsius((ExtUI::extruder_t) (ExtUI::extruder_t) ExtUI::E0);
+ SEND_PGM_VAL("A0V ", int(hotendActualTemp + 0.5));
+ }
+ break;
+
+ case 1: { // A1 GET HOTEND TARGET TEMP
+ float hotendTargetTemp = ExtUI::getTargetTemp_celsius((ExtUI::extruder_t) (ExtUI::extruder_t) ExtUI::E0);
+ SEND_PGM_VAL("A1V ", int(hotendTargetTemp + 0.5));
+ }
+ break;
+
+ case 2: { // A2 GET HOTBED TEMP
+ float heatedBedActualTemp = ExtUI::getActualTemp_celsius((ExtUI::heater_t) ExtUI::BED);
+ SEND_PGM_VAL("A2V ", int(heatedBedActualTemp + 0.5));
+ }
+ break;
+
+ case 3: { // A3 GET HOTBED TARGET TEMP
+ float heatedBedTargetTemp = ExtUI::getTargetTemp_celsius((ExtUI::heater_t) ExtUI::BED);
+ SEND_PGM_VAL("A3V ", int(heatedBedTargetTemp + 0.5));
+ } break;
+
+ case 4: { // A4 GET FAN SPEED
+ float fanPercent = ExtUI::getActualFan_percent(ExtUI::FAN0);
+ fanPercent = constrain(fanPercent, 0, 100);
+ SEND_PGM_VAL("A4V ", int(fanPercent));
+ } break;
+
+ case 5: { // A5 GET CURRENT COORDINATE
+ const float xPosition = ExtUI::getAxisPosition_mm(ExtUI::X),
+ yPosition = ExtUI::getAxisPosition_mm(ExtUI::Y),
+ zPosition = ExtUI::getAxisPosition_mm(ExtUI::Z);
+ SEND_PGM("A5V X: "); LCD_SERIAL.print(xPosition);
+ SEND_PGM( " Y: "); LCD_SERIAL.print(yPosition);
+ SEND_PGM( " Z: "); LCD_SERIAL.print(zPosition);
+ SENDLINE_PGM("");
+ } break;
+
+ case 6: // A6 GET SD CARD PRINTING STATUS
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isPrintingFromMedia()) {
+ SEND_PGM("A6V ");
+ if (ExtUI::isMediaInserted())
+ SENDLINE(ui8tostr3rj(ExtUI::getProgress_percent()));
+ else
+ SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to return printing status... J02");
+ }
+ else
+ SENDLINE_PGM("A6V ---");
+ #endif
+ break;
+
+ case 7: { // A7 GET PRINTING TIME
+ const uint32_t elapsedSeconds = ExtUI::getProgress_seconds_elapsed();
+ SEND_PGM("A7V ");
+ if (elapsedSeconds != 0) { // print time
+ const uint32_t elapsedMinutes = elapsedSeconds / 60;
+ SEND(ui8tostr2(elapsedMinutes / 60));
+ SEND_PGM(" H ");
+ SEND(ui8tostr2(elapsedMinutes % 60));
+ SENDLINE_PGM(" M");
+ }
+ else
+ SENDLINE_PGM(" 999:999");
+ }
+ break;
+
+ case 8: // A8 GET SD LIST
+ #if ENABLED(SDSUPPORT)
+ SelectedFile[0] = 0;
+ RenderCurrentFileList();
+ #endif
+ break;
+
+ case 9: // A9 pause sd print
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isPrintingFromMedia())
+ PausePrint();
+ #endif
+ break;
+
+ case 10: // A10 resume sd print
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isPrintingFromMediaPaused())
+ ResumePrint();
+ #endif
+ break;
+
+ case 11: // A11 STOP SD PRINT
+ TERN_(SDSUPPORT, StopPrint());
+ break;
+
+ case 12: // A12 kill
+ kill(PSTR(STR_ERR_KILLED));
+ break;
+
+ case 13: // A13 SELECTION FILE
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isMediaInserted()) {
+ starpos = (strchr(TFTstrchr_pointer + 4, '*'));
+ if (TFTstrchr_pointer[4] == '/') {
+ strcpy(SelectedDirectory, TFTstrchr_pointer + 5);
+ SelectedFile[0] = 0;
+ SENDLINE_DBG_PGM("J21", "TFT Serial Debug: Clear file selection... J21 "); // J21 Not File Selected
+ SENDLINE_PGM("");
+ }
+ else if (TFTstrchr_pointer[4] == '<') {
+ strcpy(SelectedDirectory, TFTstrchr_pointer + 4);
+ SpecialMenu = true;
+ SelectedFile[0] = 0;
+ SENDLINE_DBG_PGM("J21", "TFT Serial Debug: Clear file selection... J21 "); // J21 Not File Selected
+ SENDLINE_PGM("");
+ }
+ else {
+ SelectedDirectory[0] = 0;
+
+ if (starpos) *(starpos - 1) = '\0';
+
+ strcpy(SelectedFile, TFTstrchr_pointer + 4);
+ SENDLINE_DBG_PGM_VAL("J20", "TFT Serial Debug: File Selected... J20 ", SelectedFile); // J20 File Selected
+ }
+ }
+ #endif
+ break;
+
+ case 14: // A14 START PRINTING
+ #if ENABLED(SDSUPPORT)
+ if (!ExtUI::isPrinting() && strlen(SelectedFile) > 0)
+ StartPrint();
+ #endif
+ break;
+
+ case 15: // A15 RESUMING FROM OUTAGE
+ // TODO: JBA implement resume form outage
+ break;
+
+ case 16: { // A16 set hotend temp
+ unsigned int tempvalue;
+ if (CodeSeen('S')) {
+ tempvalue = constrain(CodeValue(), 0, 275);
+ ExtUI::setTargetTemp_celsius(tempvalue, (ExtUI::extruder_t) ExtUI::E0);
+ }
+ else if (CodeSeen('C') && !ExtUI::isPrinting()) {
+ if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 10)
+ ExtUI::injectCommands_P(PSTR("G1 Z10")); // RASE Z AXIS
+ tempvalue = constrain(CodeValue(), 0, 275);
+ ExtUI::setTargetTemp_celsius(tempvalue, (ExtUI::extruder_t) ExtUI::E0);
+ }
+ }
+ break;
+
+ case 17: { // A17 set heated bed temp
+ unsigned int tempbed;
+ if (CodeSeen('S')) {
+ tempbed = constrain(CodeValue(), 0, 100);
+ ExtUI::setTargetTemp_celsius(tempbed, (ExtUI::heater_t)ExtUI::BED);
+ }
+ }
+ break;
+
+ case 18: { // A18 set fan speed
+ float fanPercent;
+ if (CodeSeen('S')) {
+ fanPercent = CodeValue();
+ fanPercent = constrain(fanPercent, 0, 100);
+ ExtUI::setTargetFan_percent(fanPercent, ExtUI::FAN0);
+ }
+ else
+ fanPercent = 100;
+
+ ExtUI::setTargetFan_percent(fanPercent, ExtUI::FAN0);
+ SENDLINE_PGM("");
+ }
+ break;
+
+ case 19: // A19 stop stepper drivers - sent on stop extrude command and on turn motors off command
+ if (!ExtUI::isPrinting()) {
+ quickstop_stepper();
+ disable_all_steppers();
+ }
+
+ SENDLINE_PGM("");
+ break;
+
+ case 20: // A20 read printing speed
+ if (CodeSeen('S'))
+ feedrate_percentage = constrain(CodeValue(), 40, 999);
+ else
+ SEND_PGM_VAL("A20V ", feedrate_percentage);
+ break;
+
+ case 21: // A21 all home
+ if (!ExtUI::isPrinting() && !ExtUI::isPrintingFromMediaPaused()) {
+ if (CodeSeen('X') || CodeSeen('Y') || CodeSeen('Z')) {
+ if (CodeSeen('X'))
+ ExtUI::injectCommands_P(PSTR("G28X"));
+ if (CodeSeen('Y'))
+ ExtUI::injectCommands_P(PSTR("G28Y"));
+ if (CodeSeen('Z'))
+ ExtUI::injectCommands_P(PSTR("G28Z"));
+ }
+ else if (CodeSeen('C')) {
+ ExtUI::injectCommands_P(G28_STR);
+ }
+ }
+ break;
+
+ case 22: // A22 move X/Y/Z or extrude
+ if (!ExtUI::isPrinting()) {
+ float coorvalue;
+ unsigned int movespeed = 0;
+ char commandStr[30];
+ char fullCommandStr[38];
+
+ commandStr[0] = 0; // empty string
+ if (CodeSeen('F')) // Set feedrate
+ movespeed = CodeValue();
+
+ if (CodeSeen('X')) { // Move in X direction
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 X0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 X-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 X%iF%i"), int(coorvalue), movespeed);
+ }
+ else if (CodeSeen('Y')) { // Move in Y direction
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 Y0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 Y-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 Y%iF%i"), int(coorvalue), movespeed);
+ }
+ else if (CodeSeen('Z')) { // Move in Z direction
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 Z0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 Z-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 Z%iF%i"), int(coorvalue), movespeed);
+ }
+ else if (CodeSeen('E')) { // Extrude
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 E0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 E-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 E%iF500"), int(coorvalue));
+ }
+
+ if (strlen(commandStr) > 0) {
+ sprintf_P(fullCommandStr, PSTR("G91\n%s\nG90"), commandStr);
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOPGM("TFT Serial Debug: A22 Move final request with gcode... ");
+ SERIAL_ECHOLN(fullCommandStr);
+ #endif
+ ExtUI::injectCommands(fullCommandStr);
+ }
+ }
+ SENDLINE_PGM("");
+ break;
+
+ case 23: // A23 preheat pla
+ if (!ExtUI::isPrinting()) {
+ if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 10)
+ ExtUI::injectCommands_P(PSTR("G1 Z10")); // RASE Z AXIS
+
+ ExtUI::setTargetTemp_celsius(PREHEAT_1_TEMP_BED, (ExtUI::heater_t) ExtUI::BED);
+ ExtUI::setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, (ExtUI::extruder_t) ExtUI::E0);
+ SENDLINE_PGM("OK");
+ }
+ break;
+
+ case 24:// A24 preheat abs
+ if (!ExtUI::isPrinting()) {
+ if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 10)
+ ExtUI::injectCommands_P(PSTR("G1 Z10")); // RASE Z AXIS
+
+ ExtUI::setTargetTemp_celsius(PREHEAT_2_TEMP_BED, (ExtUI::heater_t) ExtUI::BED);
+ ExtUI::setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, (ExtUI::extruder_t) ExtUI::E0);
+ SENDLINE_PGM("OK");
+ }
+ break;
+
+ case 25: // A25 cool down
+ if (!ExtUI::isPrinting()) {
+ ExtUI::setTargetTemp_celsius(0, (ExtUI::heater_t) ExtUI::BED);
+ ExtUI::setTargetTemp_celsius(0, (ExtUI::extruder_t) ExtUI::E0);
+
+ SENDLINE_DBG_PGM("J12", "TFT Serial Debug: Cooling down... J12"); // J12 cool down
+ }
+ break;
+
+ case 26: // A26 refresh SD
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isMediaInserted()) {
+ if (strlen(SelectedDirectory) > 0) {
+ ExtUI::FileList currentFileList;
+ if ((SelectedDirectory[0] == '.') && (SelectedDirectory[1] == '.')) {
+ currentFileList.upDir();
+ }
+ else {
+ if (SelectedDirectory[0] == '<')
+ HandleSpecialMenu();
+ else
+ currentFileList.changeDir(SelectedDirectory);
+ }
+ }
+ }
+ else {
+ SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to refresh SD A26... J02");
+ }
+
+ SelectedDirectory[0] = 0;
+ #endif
+ break;
+
+ #if ENABLED(SERVO_ENDSTOPS)
+ case 27: break; // A27 servos angles adjust
+ #endif
+
+ case 28: // A28 filament test
+ if (CodeSeen('O'))
+ NOOP;
+ else if (CodeSeen('C'))
+ NOOP;
+ SENDLINE_PGM("");
+ break;
+
+ case 33: // A33 get version info
+ SEND_PGM("J33 ");
+ SENDLINE_PGM(DETAILED_BUILD_VERSION);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TFTbufindw = (TFTbufindw + 1) % TFTBUFSIZE;
+ TFTbuflen += 1;
+ serial3_count = 0; // clear buffer
+ }
+ else {
+ TFTcmdbuffer[TFTbufindw][serial3_count++] = serial3_char;
+ }
+ }
+}
+
+void AnycubicTFTClass::DoSDCardStateCheck() {
+ #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)
+ bool isInserted = ExtUI::isMediaInserted();
+ if (isInserted)
+ SENDLINE_DBG_PGM("J00", "TFT Serial Debug: SD card state changed... isInserted");
+ else
+ SENDLINE_DBG_PGM("J01", "TFT Serial Debug: SD card state changed... !isInserted");
+
+ #endif
+}
+
+void AnycubicTFTClass::DoFilamentRunoutCheck() {
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ // NOTE: ExtUI::getFilamentRunoutState() only returns the runout state if the job is printing
+ // we want to actually check the status of the pin here, regardless of printstate
+ if (READ(FIL_RUNOUT1_PIN)) {
+ if (mediaPrintingState == AMPRINTSTATE_PRINTING || mediaPrintingState == AMPRINTSTATE_PAUSED || mediaPrintingState == AMPRINTSTATE_PAUSE_REQUESTED) {
+ // play tone to indicate filament is out
+ ExtUI::injectCommands_P(PSTR("\nM300 P200 S1567\nM300 P200 S1174\nM300 P200 S1567\nM300 P200 S1174\nM300 P2000 S1567"));
+
+ // tell the user that the filament has run out and wait
+ SENDLINE_DBG_PGM("J23", "TFT Serial Debug: Blocking filament prompt... J23");
+ }
+ else {
+ SENDLINE_DBG_PGM("J15", "TFT Serial Debug: Non blocking filament runout... J15");
+ }
+ }
+ #endif // FILAMENT_RUNOUT_SENSOR
+}
+
+void AnycubicTFTClass::StartPrint() {
+ #if ENABLED(SDSUPPORT)
+ if (!ExtUI::isPrinting() && strlen(SelectedFile) > 0) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOPGM("TFT Serial Debug: About to print file ... ");
+ SERIAL_ECHO(ExtUI::isPrinting());
+ SERIAL_ECHOPGM(" ");
+ SERIAL_ECHOLN(SelectedFile);
+ #endif
+ mediaPrintingState = AMPRINTSTATE_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ ExtUI::printFile(SelectedFile);
+ }
+ #endif // SDUPPORT
+}
+
+void AnycubicTFTClass::PausePrint() {
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isPrintingFromMedia() && mediaPrintingState != AMPRINTSTATE_STOP_REQUESTED && mediaPauseState == AMPAUSESTATE_NOT_PAUSED) {
+ mediaPrintingState = AMPRINTSTATE_PAUSE_REQUESTED;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED; // need the userconfirm method to update pause state
+ SENDLINE_DBG_PGM("J05", "TFT Serial Debug: SD print pause started... J05"); // J05 printing pause
+
+ // for some reason pausing the print doesn't retract the extruder so force a manual one here
+ ExtUI::injectCommands_P(PSTR("G91\nG1 E-2 F1800\nG90"));
+ ExtUI::pausePrint();
+ }
+ #endif
+}
+
+void AnycubicTFTClass::ResumePrint() {
+ #if ENABLED(SDSUPPORT)
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ if (READ(FIL_RUNOUT1_PIN)) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: Resume Print with filament sensor still tripped... ");
+ #endif
+
+ // trigger the user message box
+ DoFilamentRunoutCheck();
+
+ // re-enable the continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: Resume Print with filament sensor still tripped... J18");
+ return;
+ }
+ #endif
+
+ if (mediaPauseState == AMPAUSESTATE_HEATER_TIMEOUT) {
+ mediaPauseState = AMPAUSESTATE_REHEATING;
+ // TODO: JBA I don't think J05 just disables the continue button, i think it injects a rogue M25. So taking this out
+ // // disable the continue button
+ // SENDLINE_DBG_PGM("J05", "TFT Serial Debug: Resume called with heater timeout... J05"); // J05 printing pause
+
+ // reheat the nozzle
+ ExtUI::setUserConfirmed();
+ }
+ else {
+ mediaPrintingState = AMPRINTSTATE_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+
+ SENDLINE_DBG_PGM("J04", "TFT Serial Debug: SD print resumed... J04"); // J04 printing form sd card now
+ ExtUI::resumePrint();
+ }
+ #endif
+}
+
+void AnycubicTFTClass::StopPrint() {
+ #if ENABLED(SDSUPPORT)
+ mediaPrintingState = AMPRINTSTATE_STOP_REQUESTED;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ SENDLINE_DBG_PGM("J16", "TFT Serial Debug: SD print stop called... J16");
+
+ // for some reason stopping the print doesn't retract the extruder so force a manual one here
+ ExtUI::injectCommands_P(PSTR("G91\nG1 E-2 F1800\nG90"));
+ ExtUI::stopPrint();
+ #endif
+}
+
+#endif // ANYCUBIC_LCD_I3MEGA
diff --git a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h
new file mode 100644
index 0000000..59050ac
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h
@@ -0,0 +1,97 @@
+/**
+ * anycubic_i3mega_lcd.h --- Support for Anycubic i3 Mega TFT
+ * Created by Christian Hopp on 09.12.17.
+ * Improved by David Ramiro
+ * Converted to ext_iu by John BouAntoun 21 June 2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#pragma once
+
+#include "../../../../inc/MarlinConfigPre.h"
+#include "../../../../sd/SdFatConfig.h" // for the FILENAME_LENGTH macro
+
+#define TFTBUFSIZE 4
+#define TFT_MAX_CMD_SIZE 96
+
+enum AnycubicMediaPrintState {
+ AMPRINTSTATE_NOT_PRINTING,
+ AMPRINTSTATE_PRINTING,
+ AMPRINTSTATE_PAUSE_REQUESTED,
+ AMPRINTSTATE_PAUSED,
+ AMPRINTSTATE_STOP_REQUESTED
+};
+
+enum AnycubicMediaPauseState {
+ AMPAUSESTATE_NOT_PAUSED,
+ AMPAUSESTATE_PARKING,
+ AMPAUSESTATE_PARKED,
+ AMPAUSESTATE_FILAMENT_OUT,
+ AMPAUSESTATE_FIAMENT_PRUGING,
+ AMPAUSESTATE_HEATER_TIMEOUT,
+ AMPAUSESTATE_REHEATING,
+ AMPAUSESTATE_REHEAT_FINISHED
+};
+
+class AnycubicTFTClass {
+public:
+ AnycubicTFTClass();
+ void OnSetup();
+ void OnCommandScan();
+ void OnKillTFT();
+ void OnSDCardStateChange(bool);
+ void OnSDCardError();
+ void OnFilamentRunout();
+ void OnUserConfirmRequired(const char *);
+ void OnPrintTimerStarted();
+ void OnPrintTimerPaused();
+ void OnPrintTimerStopped();
+
+private:
+ char TFTcmdbuffer[TFTBUFSIZE][TFT_MAX_CMD_SIZE];
+ int TFTbuflen=0;
+ int TFTbufindr = 0;
+ int TFTbufindw = 0;
+ char serial3_char;
+ int serial3_count = 0;
+ char *TFTstrchr_pointer;
+ uint8_t SpecialMenu = false;
+ AnycubicMediaPrintState mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+ AnycubicMediaPauseState mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+
+ float CodeValue();
+ bool CodeSeen(char);
+ bool IsNozzleHomed();
+ void RenderCurrentFileList();
+ void RenderSpecialMenu(uint16_t);
+ void RenderCurrentFolder(uint16_t);
+ void GetCommandFromTFT();
+ void CheckSDCardChange();
+ void CheckPauseState();
+ void CheckPrintCompletion();
+ void HandleSpecialMenu();
+ void DoSDCardStateCheck();
+ void DoFilamentRunoutCheck();
+ void StartPrint();
+ void PausePrint();
+ void ResumePrint();
+ void StopPrint();
+
+ char SelectedDirectory[30];
+ char SelectedFile[FILENAME_LENGTH];
+};
+
+extern AnycubicTFTClass AnycubicTFT;
+extern const char G28_STR[];
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp
new file mode 100644
index 0000000..c7cd767
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp
@@ -0,0 +1,261 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/* DGUS implementation written by coldtobi in 2019 for Marlin */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_DGUS_LCD
+
+#if HOTENDS > 2
+ #error "More than 2 hotends not implemented on the Display UI design."
+#endif
+
+#include "../../ui_api.h"
+
+#include "../../../../MarlinCore.h"
+#include "../../../../module/motion.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../module/planner.h"
+#include "../../../../libs/duration_t.h"
+#include "../../../../module/printcounter.h"
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#include "DGUSDisplay.h"
+#include "DGUSVPVariable.h"
+#include "DGUSDisplayDef.h"
+
+// Preamble... 2 Bytes, usually 0x5A 0xA5, but configurable
+constexpr uint8_t DGUS_HEADER1 = 0x5A;
+constexpr uint8_t DGUS_HEADER2 = 0xA5;
+
+constexpr uint8_t DGUS_CMD_WRITEVAR = 0x82;
+constexpr uint8_t DGUS_CMD_READVAR = 0x83;
+
+#if ENABLED(DEBUG_DGUSLCD)
+ bool dguslcd_local_debug; // = false;
+#endif
+
+void DGUSDisplay::InitDisplay() {
+ #ifndef LCD_BAUDRATE
+ #define LCD_BAUDRATE 115200
+ #endif
+ LCD_SERIAL.begin(LCD_BAUDRATE);
+ if (TERN1(POWER_LOSS_RECOVERY, !recovery.valid()))
+ RequestScreen(TERN(SHOW_BOOTSCREEN, DGUSLCD_SCREEN_BOOT, DGUSLCD_SCREEN_MAIN));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, const void* values, uint8_t valueslen, bool isstr) {
+ const char* myvalues = static_cast<const char*>(values);
+ bool strend = !myvalues;
+ WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
+ while (valueslen--) {
+ char x;
+ if (!strend) x = *myvalues++;
+ if ((isstr && !x) || strend) {
+ strend = true;
+ x = ' ';
+ }
+ LCD_SERIAL.write(x);
+ }
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, uint16_t value) {
+ value = (value & 0xffU) << 8U | (value >> 8U);
+ WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint16_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, int16_t value) {
+ value = (value & 0xffU) << 8U | (value >> 8U);
+ WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint16_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, uint8_t value) {
+ WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint8_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, int8_t value) {
+ WriteVariable(adr, static_cast<const void*>(&value), sizeof(int8_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, long value) {
+ union { long l; char lb[4]; } endian;
+ char tmp[4];
+ endian.l = value;
+ tmp[0] = endian.lb[3];
+ tmp[1] = endian.lb[2];
+ tmp[2] = endian.lb[1];
+ tmp[3] = endian.lb[0];
+ WriteVariable(adr, static_cast<const void*>(&tmp), sizeof(long));
+}
+
+void DGUSDisplay::WriteVariablePGM(uint16_t adr, const void* values, uint8_t valueslen, bool isstr) {
+ const char* myvalues = static_cast<const char*>(values);
+ bool strend = !myvalues;
+ WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
+ while (valueslen--) {
+ char x;
+ if (!strend) x = pgm_read_byte(myvalues++);
+ if ((isstr && !x) || strend) {
+ strend = true;
+ x = ' ';
+ }
+ LCD_SERIAL.write(x);
+ }
+}
+
+void DGUSDisplay::ProcessRx() {
+
+ #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
+ if (!LCD_SERIAL.available() && LCD_SERIAL.buffer_overruns()) {
+ // Overrun, but reset the flag only when the buffer is empty
+ // We want to extract as many as valid datagrams possible...
+ DEBUG_ECHOPGM("OVFL");
+ rx_datagram_state = DGUS_IDLE;
+ //LCD_SERIAL.reset_rx_overun();
+ LCD_SERIAL.flush();
+ }
+ #endif
+
+ uint8_t receivedbyte;
+ while (LCD_SERIAL.available()) {
+ switch (rx_datagram_state) {
+
+ case DGUS_IDLE: // Waiting for the first header byte
+ receivedbyte = LCD_SERIAL.read();
+ //DEBUG_ECHOPAIR("< ",x);
+ if (DGUS_HEADER1 == receivedbyte) rx_datagram_state = DGUS_HEADER1_SEEN;
+ break;
+
+ case DGUS_HEADER1_SEEN: // Waiting for the second header byte
+ receivedbyte = LCD_SERIAL.read();
+ //DEBUG_ECHOPAIR(" ",x);
+ rx_datagram_state = (DGUS_HEADER2 == receivedbyte) ? DGUS_HEADER2_SEEN : DGUS_IDLE;
+ break;
+
+ case DGUS_HEADER2_SEEN: // Waiting for the length byte
+ rx_datagram_len = LCD_SERIAL.read();
+ DEBUG_ECHOPAIR(" (", rx_datagram_len, ") ");
+
+ // Telegram min len is 3 (command and one word of payload)
+ rx_datagram_state = WITHIN(rx_datagram_len, 3, DGUS_RX_BUFFER_SIZE) ? DGUS_WAIT_TELEGRAM : DGUS_IDLE;
+ break;
+
+ case DGUS_WAIT_TELEGRAM: // wait for complete datagram to arrive.
+ if (LCD_SERIAL.available() < rx_datagram_len) return;
+
+ Initialized = true; // We've talked to it, so we defined it as initialized.
+ uint8_t command = LCD_SERIAL.read();
+
+ DEBUG_ECHOPAIR("# ", command);
+
+ uint8_t readlen = rx_datagram_len - 1; // command is part of len.
+ unsigned char tmp[rx_datagram_len - 1];
+ unsigned char *ptmp = tmp;
+ while (readlen--) {
+ receivedbyte = LCD_SERIAL.read();
+ DEBUG_ECHOPAIR(" ", receivedbyte);
+ *ptmp++ = receivedbyte;
+ }
+ DEBUG_ECHOPGM(" # ");
+ // mostly we'll get this: 5A A5 03 82 4F 4B -- ACK on 0x82, so discard it.
+ if (command == DGUS_CMD_WRITEVAR && 'O' == tmp[0] && 'K' == tmp[1]) {
+ DEBUG_ECHOLNPGM(">");
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ /* AutoUpload, (and answer to) Command 0x83 :
+ | tmp[0 1 2 3 4 ... ]
+ | Example 5A A5 06 83 20 01 01 78 01 ……
+ | / / | | \ / | \ \
+ | Header | | | | \_____\_ DATA (Words!)
+ | DatagramLen / VPAdr |
+ | Command DataLen (in Words) */
+ if (command == DGUS_CMD_READVAR) {
+ const uint16_t vp = tmp[0] << 8 | tmp[1];
+ //const uint8_t dlen = tmp[2] << 1; // Convert to Bytes. (Display works with words)
+ //DEBUG_ECHOPAIR(" vp=", vp, " dlen=", dlen);
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(vp, &ramcopy)) {
+ if (ramcopy.set_by_display_handler)
+ ramcopy.set_by_display_handler(ramcopy, &tmp[3]);
+ else
+ DEBUG_ECHOLNPGM(" VPVar found, no handler.");
+ }
+ else
+ DEBUG_ECHOLNPAIR(" VPVar not found:", vp);
+
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ // discard anything else
+ rx_datagram_state = DGUS_IDLE;
+ }
+ }
+}
+
+size_t DGUSDisplay::GetFreeTxBuffer() { return SERIAL_GET_TX_BUFFER_FREE(); }
+
+void DGUSDisplay::WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen) {
+ LCD_SERIAL.write(DGUS_HEADER1);
+ LCD_SERIAL.write(DGUS_HEADER2);
+ LCD_SERIAL.write(payloadlen + 3);
+ LCD_SERIAL.write(cmd);
+ LCD_SERIAL.write(adr >> 8);
+ LCD_SERIAL.write(adr & 0xFF);
+}
+
+void DGUSDisplay::WritePGM(const char str[], uint8_t len) {
+ while (len--) LCD_SERIAL.write(pgm_read_byte(str++));
+}
+
+void DGUSDisplay::loop() {
+ // protect against recursion… ProcessRx() may indirectly call idle() when injecting gcode commands.
+ if (!no_reentrance) {
+ no_reentrance = true;
+ ProcessRx();
+ no_reentrance = false;
+ }
+}
+
+rx_datagram_state_t DGUSDisplay::rx_datagram_state = DGUS_IDLE;
+uint8_t DGUSDisplay::rx_datagram_len = 0;
+bool DGUSDisplay::Initialized = false;
+bool DGUSDisplay::no_reentrance = false;
+
+// A SW memory barrier, to ensure GCC does not overoptimize loops
+#define sw_barrier() asm volatile("": : :"memory");
+
+bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy) {
+ // DEBUG_ECHOPAIR("populate_VPVar ", VP);
+ const DGUS_VP_Variable *pvp = DGUSLCD_FindVPVar(VP);
+ // DEBUG_ECHOLNPAIR(" pvp ", (uint16_t )pvp);
+ if (!pvp) return false;
+ memcpy_P(ramcopy, pvp, sizeof(DGUS_VP_Variable));
+ return true;
+}
+
+#endif // HAS_DGUS_LCD
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h
new file mode 100644
index 0000000..88c1195
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h
@@ -0,0 +1,118 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/* DGUS implementation written by coldtobi in 2019 for Marlin */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#include <stdlib.h> // size_t
+
+#if HAS_BED_PROBE
+ #include "../../../../module/probe.h"
+#endif
+#include "DGUSVPVariable.h"
+
+enum DGUSLCD_Screens : uint8_t;
+
+#define DEBUG_OUT ENABLED(DEBUG_DGUSLCD)
+#include "../../../../core/debug_out.h"
+
+typedef enum : uint8_t {
+ DGUS_IDLE, //< waiting for DGUS_HEADER1.
+ DGUS_HEADER1_SEEN, //< DGUS_HEADER1 received
+ DGUS_HEADER2_SEEN, //< DGUS_HEADER2 received
+ DGUS_WAIT_TELEGRAM, //< LEN received, Waiting for to receive all bytes.
+} rx_datagram_state_t;
+
+// Low-Level access to the display.
+class DGUSDisplay {
+public:
+
+ DGUSDisplay() = default;
+
+ static void InitDisplay();
+
+ // Variable access.
+ static void WriteVariable(uint16_t adr, const void* values, uint8_t valueslen, bool isstr=false);
+ static void WriteVariablePGM(uint16_t adr, const void* values, uint8_t valueslen, bool isstr=false);
+ static void WriteVariable(uint16_t adr, int16_t value);
+ static void WriteVariable(uint16_t adr, uint16_t value);
+ static void WriteVariable(uint16_t adr, uint8_t value);
+ static void WriteVariable(uint16_t adr, int8_t value);
+ static void WriteVariable(uint16_t adr, long value);
+
+ // Utility functions for bridging ui_api and dbus
+ template<typename T, float(*Getter)(const T), T selector, typename WireType=uint16_t>
+ static void SetVariable(DGUS_VP_Variable &var) {
+ WriteVariable(var.VP, (WireType)Getter(selector));
+ }
+
+ template<typename T, void(*Setter)(const float V, const T), T selector>
+ static void GetVariable(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
+ Setter(newvalue, selector);
+ }
+
+ // Until now I did not need to actively read from the display. That's why there is no ReadVariable
+ // (I extensively use the auto upload of the display)
+
+ // Force display into another screen.
+ // (And trigger update of containing VPs)
+ // (to implement a pop up message, which may not be nested)
+ static void RequestScreen(DGUSLCD_Screens screen);
+
+ // Periodic tasks, eg. Rx-Queue handling.
+ static void loop();
+
+public:
+ // Helper for users of this class to estimate if an interaction would be blocking.
+ static size_t GetFreeTxBuffer();
+
+ // Checks two things: Can we confirm the presence of the display and has we initiliazed it.
+ // (both boils down that the display answered to our chatting)
+ static inline bool isInitialized() { return Initialized; }
+
+private:
+ static void WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen);
+ static void WritePGM(const char str[], uint8_t len);
+ static void ProcessRx();
+
+ static inline uint16_t swap16(const uint16_t value) { return (value & 0xFFU) << 8U | (value >> 8U); }
+ static rx_datagram_state_t rx_datagram_state;
+ static uint8_t rx_datagram_len;
+ static bool Initialized, no_reentrance;
+};
+
+#define GET_VARIABLE(f, t, V...) (&DGUSDisplay::GetVariable<decltype(t), f, t, ##V>)
+#define SET_VARIABLE(f, t, V...) (&DGUSDisplay::SetVariable<decltype(t), f, t, ##V>)
+
+extern DGUSDisplay dgusdisplay;
+
+// compile-time x^y
+constexpr float cpow(const float x, const int y) { return y == 0 ? 1.0 : x * cpow(x, y - 1); }
+
+/// Find the flash address of a DGUS_VP_Variable for the VP.
+extern const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp);
+
+/// Helper to populate a DGUS_VP_Variable for a given VP. Return false if not found.
+extern bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy);
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplayDef.h
new file mode 100644
index 0000000..b34a048
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplayDef.h
@@ -0,0 +1,54 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/* DGUS implementation written by coldtobi in 2019 for Marlin */
+
+#include "DGUSVPVariable.h"
+
+#include <stdint.h>
+
+// This file defines the interaction between Marlin and the display firmware.
+
+// information on which screen which VP is displayed
+// As this is a sparse table, two arrays are needed:
+// one to list the VPs of one screen and one to map screens to the lists.
+// (Strictly this would not be necessary, but allows to only send data the display needs and reducing load on Marlin)
+struct VPMapping {
+ const uint8_t screen;
+ const uint16_t *VPList; // The list is null-terminated.
+};
+
+extern const struct VPMapping VPMap[];
+
+// List of VPs handled by Marlin / The Display.
+extern const struct DGUS_VP_Variable ListOfVP[];
+
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(DGUS_LCD_UI_ORIGIN)
+ #include "origin/DGUSDisplayDef.h"
+#elif ENABLED(DGUS_LCD_UI_FYSETC)
+ #include "fysetc/DGUSDisplayDef.h"
+#elif ENABLED(DGUS_LCD_UI_HIPRECY)
+ #include "hiprecy/DGUSDisplayDef.h"
+#endif
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.cpp
new file mode 100644
index 0000000..77feacf
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.cpp
@@ -0,0 +1,1140 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_DGUS_LCD
+
+#include "DGUSScreenHandler.h"
+#include "DGUSDisplay.h"
+#include "DGUSVPVariable.h"
+#include "DGUSDisplayDef.h"
+
+#include "../../ui_api.h"
+#include "../../../../MarlinCore.h"
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../module/planner.h"
+#include "../../../../sd/cardreader.h"
+#include "../../../../libs/duration_t.h"
+#include "../../../../module/printcounter.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+uint16_t DGUSScreenHandler::ConfirmVP;
+
+#if ENABLED(SDSUPPORT)
+ int16_t DGUSScreenHandler::top_file = 0;
+ int16_t DGUSScreenHandler::file_to_print = 0;
+ static ExtUI::FileList filelist;
+#endif
+
+void (*DGUSScreenHandler::confirm_action_cb)() = nullptr;
+
+//DGUSScreenHandler ScreenHandler;
+
+DGUSLCD_Screens DGUSScreenHandler::current_screen;
+DGUSLCD_Screens DGUSScreenHandler::past_screens[NUM_PAST_SCREENS];
+uint8_t DGUSScreenHandler::update_ptr;
+uint16_t DGUSScreenHandler::skipVP;
+bool DGUSScreenHandler::ScreenComplete;
+
+//DGUSDisplay dgusdisplay;
+
+// endianness swap
+uint16_t swap16(const uint16_t value) { return (value & 0xffU) << 8U | (value >> 8U); }
+
+void DGUSScreenHandler::sendinfoscreen(const char* line1, const char* line2, const char* line3, const char* line4, bool l1inflash, bool l2inflash, bool l3inflash, bool l4inflash) {
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(VP_MSGSTR1, &ramcopy)) {
+ ramcopy.memadr = (void*) line1;
+ l1inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+ if (populate_VPVar(VP_MSGSTR2, &ramcopy)) {
+ ramcopy.memadr = (void*) line2;
+ l2inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+ if (populate_VPVar(VP_MSGSTR3, &ramcopy)) {
+ ramcopy.memadr = (void*) line3;
+ l3inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+ if (populate_VPVar(VP_MSGSTR4, &ramcopy)) {
+ ramcopy.memadr = (void*) line4;
+ l4inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+}
+
+void DGUSScreenHandler::HandleUserConfirmationPopUp(uint16_t VP, const char* line1, const char* line2, const char* line3, const char* line4, bool l1, bool l2, bool l3, bool l4) {
+ if (current_screen == DGUSLCD_SCREEN_CONFIRM) {
+ // Already showing a pop up, so we need to cancel that first.
+ PopToOldScreen();
+ }
+
+ ConfirmVP = VP;
+ sendinfoscreen(line1, line2, line3, line4, l1, l2, l3, l4);
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_CONFIRM);
+}
+
+void DGUSScreenHandler::setstatusmessage(const char *msg) {
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(VP_M117, &ramcopy)) {
+ ramcopy.memadr = (void*) msg;
+ DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+}
+
+void DGUSScreenHandler::setstatusmessagePGM(PGM_P const msg) {
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(VP_M117, &ramcopy)) {
+ ramcopy.memadr = (void*) msg;
+ DGUSLCD_SendStringToDisplayPGM(ramcopy);
+ }
+}
+
+// Send an 8 bit or 16 bit value to the display.
+void DGUSScreenHandler::DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ //DEBUG_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
+ //DEBUG_ECHOLNPAIR(" data ", *(uint16_t *)var.memadr);
+ if (var.size > 1)
+ dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
+ else
+ dgusdisplay.WriteVariable(var.VP, *(int8_t*)var.memadr);
+ }
+}
+
+// Send an uint8_t between 0 and 255 to the display, but scale to a percentage (0..100)
+void DGUSScreenHandler::DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ //DEBUG_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
+ //DEBUG_ECHOLNPAIR(" data ", *(uint16_t *)var.memadr);
+ uint16_t tmp = *(uint8_t *) var.memadr +1 ; // +1 -> avoid rounding issues for the display.
+ tmp = map(tmp, 0, 255, 0, 100);
+ dgusdisplay.WriteVariable(var.VP, tmp);
+ }
+}
+
+// Send the current print progress to the display.
+void DGUSScreenHandler::DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var) {
+ //DEBUG_ECHOPAIR(" DGUSLCD_SendPrintProgressToDisplay ", var.VP);
+ uint16_t tmp = ExtUI::getProgress_percent();
+ //DEBUG_ECHOLNPAIR(" data ", tmp);
+ dgusdisplay.WriteVariable(var.VP, tmp);
+}
+
+// Send the current print time to the display.
+// It is using a hex display for that: It expects BSD coded data in the format xxyyzz
+void DGUSScreenHandler::DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var) {
+ duration_t elapsed = print_job_timer.duration();
+ char buf[32];
+ elapsed.toString(buf);
+ dgusdisplay.WriteVariable(VP_PrintTime, buf, var.size, true);
+}
+
+// Send an uint8_t between 0 and 100 to a variable scale to 0..255
+void DGUSScreenHandler::DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr) {
+ if (var.memadr) {
+ uint16_t value = swap16(*(uint16_t*)val_ptr);
+ *(uint8_t*)var.memadr = map(constrain(value, 0, 100), 0, 100, 0, 255);
+ }
+}
+
+// Sends a (RAM located) string to the DGUS Display
+// (Note: The DGUS Display does not clear after the \0, you have to
+// overwrite the remainings with spaces.// var.size has the display buffer size!
+void DGUSScreenHandler::DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var) {
+ char *tmp = (char*) var.memadr;
+ dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
+}
+
+// Sends a (flash located) string to the DGUS Display
+// (Note: The DGUS Display does not clear after the \0, you have to
+// overwrite the remainings with spaces.// var.size has the display buffer size!
+void DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var) {
+ char *tmp = (char*) var.memadr;
+ dgusdisplay.WriteVariablePGM(var.VP, tmp, var.size, true);
+}
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var) {
+ float value = *(float *)var.memadr;
+ float valuesend = 0;
+ switch (var.VP) {
+ default: return;
+ #if HOTENDS >= 1
+ case VP_E0_PID_P: valuesend = value; break;
+ case VP_E0_PID_I: valuesend = unscalePID_i(value); break;
+ case VP_E0_PID_D: valuesend = unscalePID_d(value); break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_E1_PID_P: valuesend = value; break;
+ case VP_E1_PID_I: valuesend = unscalePID_i(value); break;
+ case VP_E1_PID_D: valuesend = unscalePID_d(value); break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_BED_PID_P: valuesend = value; break;
+ case VP_BED_PID_I: valuesend = unscalePID_i(value); break;
+ case VP_BED_PID_D: valuesend = unscalePID_d(value); break;
+ #endif
+ }
+
+ valuesend *= cpow(10, 1);
+ union { int16_t i; char lb[2]; } endian;
+
+ char tmp[2];
+ endian.i = valuesend;
+ tmp[0] = endian.lb[1];
+ tmp[1] = endian.lb[0];
+ dgusdisplay.WriteVariable(var.VP, tmp, 2);
+ }
+#endif
+
+#if ENABLED(PRINTCOUNTER)
+
+ // Send the accumulate print time to the display.
+ // It is using a hex display for that: It expects BSD coded data in the format xxyyzz
+ void DGUSScreenHandler::DGUSLCD_SendPrintAccTimeToDisplay(DGUS_VP_Variable &var) {
+ printStatistics state = print_job_timer.getStats();
+ char buf[22];
+ duration_t elapsed = state.printTime;
+ elapsed.toString(buf);
+ dgusdisplay.WriteVariable(VP_PrintAccTime, buf, var.size, true);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SendPrintsTotalToDisplay(DGUS_VP_Variable &var) {
+ printStatistics state = print_job_timer.getStats();
+ char buf[10];
+ sprintf_P(buf, PSTR("%u"), state.totalPrints);
+ dgusdisplay.WriteVariable(VP_PrintsTotal, buf, var.size, true);
+ }
+
+#endif
+
+// Send fan status value to the display.
+#if HAS_FAN
+ void DGUSScreenHandler::DGUSLCD_SendFanStatusToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ DEBUG_ECHOPAIR(" DGUSLCD_SendFanStatusToDisplay ", var.VP);
+ DEBUG_ECHOLNPAIR(" data ", *(uint8_t *)var.memadr);
+ uint16_t data_to_send = 0;
+ if (*(uint8_t *) var.memadr) data_to_send = 1;
+ dgusdisplay.WriteVariable(var.VP, data_to_send);
+ }
+ }
+#endif
+
+// Send heater status value to the display.
+void DGUSScreenHandler::DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ DEBUG_ECHOPAIR(" DGUSLCD_SendHeaterStatusToDisplay ", var.VP);
+ DEBUG_ECHOLNPAIR(" data ", *(int16_t *)var.memadr);
+ uint16_t data_to_send = 0;
+ if (*(int16_t *) var.memadr) data_to_send = 1;
+ dgusdisplay.WriteVariable(var.VP, data_to_send);
+ }
+}
+
+#if ENABLED(DGUS_UI_WAITING)
+ void DGUSScreenHandler::DGUSLCD_SendWaitingStatusToDisplay(DGUS_VP_Variable &var) {
+ // In FYSETC UI design there are 10 statuses to loop
+ static uint16_t period = 0;
+ static uint16_t index = 0;
+ //DEBUG_ECHOPAIR(" DGUSLCD_SendWaitingStatusToDisplay ", var.VP);
+ //DEBUG_ECHOLNPAIR(" data ", swap16(index));
+ if (period++ > DGUS_UI_WAITING_STATUS_PERIOD) {
+ dgusdisplay.WriteVariable(var.VP, index);
+ //DEBUG_ECHOLNPAIR(" data ", swap16(index));
+ if (++index >= DGUS_UI_WAITING_STATUS) index = 0;
+ period = 0;
+ }
+ }
+#endif
+
+#if ENABLED(SDSUPPORT)
+
+ void DGUSScreenHandler::ScreenChangeHookIfSD(DGUS_VP_Variable &var, void *val_ptr) {
+ // default action executed when there is a SD card, but not printing
+ if (ExtUI::isMediaInserted() && !ExtUI::isPrintingFromMedia()) {
+ ScreenChangeHook(var, val_ptr);
+ dgusdisplay.RequestScreen(current_screen);
+ return;
+ }
+
+ // if we are printing, we jump to two screens after the requested one.
+ // This should host e.g a print pause / print abort / print resume dialog.
+ // This concept allows to recycle this hook for other file
+ if (ExtUI::isPrintingFromMedia() && !card.flag.abort_sd_printing) {
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
+ return;
+ }
+
+ // Don't let the user in the dark why there is no reaction.
+ if (!ExtUI::isMediaInserted()) {
+ setstatusmessagePGM(GET_TEXT(MSG_NO_MEDIA));
+ return;
+ }
+ if (card.flag.abort_sd_printing) {
+ setstatusmessagePGM(GET_TEXT(MSG_MEDIA_ABORTING));
+ return;
+ }
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ScrollFilelist(DGUS_VP_Variable& var, void *val_ptr) {
+ auto old_top = top_file;
+ const int16_t scroll = (int16_t)swap16(*(uint16_t*)val_ptr);
+ if (scroll) {
+ top_file += scroll;
+ DEBUG_ECHOPAIR("new topfile calculated:", top_file);
+ if (top_file < 0) {
+ top_file = 0;
+ DEBUG_ECHOLNPGM("Top of filelist reached");
+ }
+ else {
+ int16_t max_top = filelist.count() - DGUS_SD_FILESPERSCREEN;
+ NOLESS(max_top, 0);
+ NOMORE(top_file, max_top);
+ }
+ DEBUG_ECHOPAIR("new topfile adjusted:", top_file);
+ }
+ else if (!filelist.isAtRootDir()) {
+ filelist.upDir();
+ top_file = 0;
+ ForceCompleteUpdate();
+ }
+
+ if (old_top != top_file) ForceCompleteUpdate();
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t touched_nr = (int16_t)swap16(*(uint16_t*)val_ptr) + top_file;
+ if (touched_nr > filelist.count()) return;
+ if (!filelist.seek(touched_nr)) return;
+ if (filelist.isDir()) {
+ filelist.changeDir(filelist.filename());
+ top_file = 0;
+ ForceCompleteUpdate();
+ return;
+ }
+
+ #if ENABLED(DGUS_PRINT_FILENAME)
+ // Send print filename
+ dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN, true);
+ #endif
+
+ // Setup Confirmation screen
+ file_to_print = touched_nr;
+ HandleUserConfirmationPopUp(VP_SD_FileSelectConfirm, nullptr, PSTR("Print file"), filelist.filename(), PSTR("from SD Card?"), true, true, false, true);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!filelist.seek(file_to_print)) return;
+ ExtUI::printFile(filelist.shortFilename());
+ ScreenHandler.GotoScreen(
+ #if ENABLED(DGUS_LCD_UI_ORIGIN)
+ DGUSLCD_SCREEN_STATUS
+ #else
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ #endif
+ );
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
+ switch (swap16(*(uint16_t*)val_ptr)) {
+ case 0: // Resume
+ if (ExtUI::isPrintingFromMediaPaused()) ExtUI::resumePrint();
+ break;
+ case 1: // Pause
+ if (!ExtUI::isPrintingFromMediaPaused()) ExtUI::pausePrint();
+ break;
+ case 2: // Abort
+ ScreenHandler.HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true);
+ break;
+ }
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ReallyAbort(DGUS_VP_Variable &var, void *val_ptr) {
+ ExtUI::stopPrint();
+ GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_PrintTune(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTTUNE);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_SendFilename(DGUS_VP_Variable& var) {
+ uint16_t target_line = (var.VP - VP_SD_FileName0) / VP_SD_FileName_LEN;
+ if (target_line > DGUS_SD_FILESPERSCREEN) return;
+ char tmpfilename[VP_SD_FileName_LEN + 1] = "";
+ var.memadr = (void*)tmpfilename;
+ if (filelist.seek(top_file + target_line))
+ snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s%c"), filelist.filename(), filelist.isDir() ? '/' : 0);
+ DGUSLCD_SendStringToDisplay(var);
+ }
+
+ void DGUSScreenHandler::SDCardInserted() {
+ top_file = 0;
+ filelist.refresh();
+ auto cs = ScreenHandler.getCurrentScreen();
+ if (cs == DGUSLCD_SCREEN_MAIN || cs == DGUSLCD_SCREEN_STATUS)
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_SDFILELIST);
+ }
+
+ void DGUSScreenHandler::SDCardRemoved() {
+ if (current_screen == DGUSLCD_SCREEN_SDFILELIST
+ || (current_screen == DGUSLCD_SCREEN_CONFIRM && (ConfirmVP == VP_SD_AbortPrintConfirmed || ConfirmVP == VP_SD_FileSelectConfirm))
+ || current_screen == DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ ) ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+
+ void DGUSScreenHandler::SDCardError() {
+ DGUSScreenHandler::SDCardRemoved();
+ ScreenHandler.sendinfoscreen(PSTR("NOTICE"), nullptr, PSTR("SD card error"), nullptr, true, true, true, true);
+ ScreenHandler.SetupConfirmAction(nullptr);
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_POPUP);
+ }
+
+#endif // SDSUPPORT
+
+void DGUSScreenHandler::ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr) {
+ DGUS_VP_Variable ramcopy;
+ if (!populate_VPVar(ConfirmVP, &ramcopy)) return;
+ if (ramcopy.set_by_display_handler) ramcopy.set_by_display_handler(ramcopy, val_ptr);
+}
+
+const uint16_t* DGUSLCD_FindScreenVPMapList(uint8_t screen) {
+ const uint16_t *ret;
+ const struct VPMapping *map = VPMap;
+ while (ret = (uint16_t*) pgm_read_ptr(&(map->VPList))) {
+ if (pgm_read_byte(&(map->screen)) == screen) return ret;
+ map++;
+ }
+ return nullptr;
+}
+
+const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp) {
+ const DGUS_VP_Variable *ret = ListOfVP;
+ do {
+ const uint16_t vpcheck = pgm_read_word(&(ret->VP));
+ if (vpcheck == 0) break;
+ if (vpcheck == vp) return ret;
+ ++ret;
+ } while (1);
+
+ DEBUG_ECHOLNPAIR("FindVPVar NOT FOUND ", vp);
+ return nullptr;
+}
+
+void DGUSScreenHandler::ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!ExtUI::isPrinting()) {
+ ScreenChangeHook(var, val_ptr);
+ dgusdisplay.RequestScreen(current_screen);
+ }
+}
+
+void DGUSScreenHandler::ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr) {
+ uint8_t *tmp = (uint8_t*)val_ptr;
+
+ // The keycode in target is coded as <from-frame><to-frame>, so 0x0100A means
+ // from screen 1 (main) to 10 (temperature). DGUSLCD_SCREEN_POPUP is special,
+ // meaning "return to previous screen"
+ DGUSLCD_Screens target = (DGUSLCD_Screens)tmp[1];
+
+ if (target == DGUSLCD_SCREEN_POPUP) {
+ // special handling for popup is to return to previous menu
+ if (current_screen == DGUSLCD_SCREEN_POPUP && confirm_action_cb) confirm_action_cb();
+ PopToOldScreen();
+ return;
+ }
+
+ UpdateNewScreen(target);
+
+ #ifdef DEBUG_DGUSLCD
+ if (!DGUSLCD_FindScreenVPMapList(target)) DEBUG_ECHOLNPAIR("WARNING: No screen Mapping found for ", target);
+ #endif
+}
+
+void DGUSScreenHandler::HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr) {
+ thermalManager.disable_all_heaters();
+ ScreenHandler.ForceCompleteUpdate(); // hint to send all data.
+}
+
+void DGUSScreenHandler::HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
+ uint16_t acceptedvalue;
+
+ switch (var.VP) {
+ default: return;
+ #if HOTENDS >= 1
+ case VP_T_E0_Set:
+ thermalManager.setTargetHotend(newvalue, 0);
+ acceptedvalue = thermalManager.temp_hotend[0].target;
+ break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_T_E1_Set:
+ thermalManager.setTargetHotend(newvalue, 1);
+ acceptedvalue = thermalManager.temp_hotend[1].target;
+ break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_T_Bed_Set:
+ thermalManager.setTargetBed(newvalue);
+ acceptedvalue = thermalManager.temp_bed.target;
+ break;
+ #endif
+ }
+
+ // reply to display the new value to update the view if the new value was rejected by the Thermal Manager.
+ if (newvalue != acceptedvalue && var.send_to_display_handler) var.send_to_display_handler(var);
+ ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ #if EXTRUDERS
+ uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
+ uint8_t target_extruder;
+ switch (var.VP) {
+ default: return;
+ #if HOTENDS >= 1
+ case VP_Flowrate_E0: target_extruder = 0; break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_Flowrate_E1: target_extruder = 1; break;
+ #endif
+ }
+
+ planner.set_flow(target_extruder, newvalue);
+ ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ #else
+ UNUSED(var); UNUSED(val_ptr);
+ #endif
+}
+
+void DGUSScreenHandler::HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualExtrude");
+
+ int16_t movevalue = swap16(*(uint16_t*)val_ptr);
+ float target = movevalue * 0.01f;
+ ExtUI::extruder_t target_extruder;
+
+ switch (var.VP) {
+ #if HOTENDS >= 1
+ case VP_MOVE_E0: target_extruder = ExtUI::extruder_t::E0; break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break;
+ #endif
+ default: return;
+ }
+
+ target += ExtUI::getAxisPosition_mm(target_extruder);
+ ExtUI::setAxisPosition_mm(target, target_extruder);
+ skipVP = var.VP;
+}
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ void DGUSScreenHandler::HandleManualMoveOption(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualMoveOption");
+ *(uint16_t*)var.memadr = swap16(*(uint16_t*)val_ptr);
+ }
+#endif
+
+void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualMove");
+
+ int16_t movevalue = swap16(*(uint16_t*)val_ptr);
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ if (movevalue) {
+ const uint16_t choice = *(uint16_t*)var.memadr;
+ movevalue = movevalue < 0 ? -choice : choice;
+ }
+ #endif
+ char axiscode;
+ unsigned int speed = 1500; //FIXME: get default feedrate for manual moves, dont hardcode.
+
+ switch (var.VP) {
+ default: return;
+
+ case VP_MOVE_X:
+ axiscode = 'X';
+ if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Y:
+ axiscode = 'Y';
+ if (!ExtUI::canMove(ExtUI::axis_t::Y)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Z:
+ axiscode = 'Z';
+ speed = 300; // default to 5mm/s
+ if (!ExtUI::canMove(ExtUI::axis_t::Z)) goto cannotmove;
+ break;
+
+ case VP_HOME_ALL: // only used for homing
+ axiscode = '\0';
+ movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing.
+ break;
+ }
+
+ if (!movevalue) {
+ // homing
+ DEBUG_ECHOPAIR(" homing ", axiscode);
+ char buf[6] = "G28 X";
+ buf[4] = axiscode;
+ //DEBUG_ECHOPAIR(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓");
+ ScreenHandler.ForceCompleteUpdate();
+ return;
+ }
+ else {
+ //movement
+ DEBUG_ECHOPAIR(" move ", axiscode);
+ bool old_relative_mode = relative_mode;
+ if (!relative_mode) {
+ //DEBUG_ECHOPGM(" G91");
+ queue.enqueue_now_P(PSTR("G91"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ char buf[32]; // G1 X9999.99 F12345
+ unsigned int backup_speed = MMS_TO_MMM(feedrate_mm_s);
+ char sign[]="\0";
+ int16_t value = movevalue / 100;
+ if (movevalue < 0) { value = -value; sign[0] = '-'; }
+ int16_t fraction = ABS(movevalue) % 100;
+ snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed);
+ //DEBUG_ECHOPAIR(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (backup_speed != speed) {
+ snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOPAIR(" ", buf);
+ }
+ //while (!enqueue_and_echo_command(buf)) idle();
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (!old_relative_mode) {
+ //DEBUG_ECHOPGM("G90");
+ queue.enqueue_now_P(PSTR("G90"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ }
+
+ ScreenHandler.ForceCompleteUpdate();
+ DEBUG_ECHOLNPGM("manmv done.");
+ return;
+
+ cannotmove:
+ DEBUG_ECHOLNPAIR(" cannot move ", axiscode);
+ return;
+}
+
+void DGUSScreenHandler::HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleMotorLockUnlock");
+
+ char buf[4];
+ const int16_t lock = swap16(*(uint16_t*)val_ptr);
+ strcpy_P(buf, lock ? PSTR("M18") : PSTR("M17"));
+
+ //DEBUG_ECHOPAIR(" ", buf);
+ queue.enqueue_one_now(buf);
+}
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+
+ void DGUSScreenHandler::HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t value = swap16(*(uint16_t*)val_ptr);
+ if (value) {
+ queue.inject_P(PSTR("M1000"));
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
+ }
+ else {
+ recovery.cancel();
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_STATUS);
+ }
+ }
+
+#endif
+
+void DGUSScreenHandler::HandleSettings(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleSettings");
+ uint16_t value = swap16(*(uint16_t*)val_ptr);
+ switch (value) {
+ default: break;
+ case 1:
+ TERN_(PRINTCOUNTER, print_job_timer.initStats());
+ queue.inject_P(PSTR("M502\nM500"));
+ break;
+ case 2: queue.inject_P(PSTR("M501")); break;
+ case 3: queue.inject_P(PSTR("M500")); break;
+ }
+}
+
+void DGUSScreenHandler::HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleStepPerMMChanged");
+
+ uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPAIR("value_raw:", value_raw);
+ float value = (float)value_raw/10;
+ ExtUI::axis_t axis;
+ switch (var.VP) {
+ case VP_X_STEP_PER_MM: axis = ExtUI::axis_t::X; break;
+ case VP_Y_STEP_PER_MM: axis = ExtUI::axis_t::Y; break;
+ case VP_Z_STEP_PER_MM: axis = ExtUI::axis_t::Z; break;
+ default: return;
+ }
+ DEBUG_ECHOLNPAIR_F("value:", value);
+ ExtUI::setAxisSteps_per_mm(value, axis);
+ DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(axis));
+ ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ return;
+}
+
+void DGUSScreenHandler::HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleStepPerMMExtruderChanged");
+
+ uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPAIR("value_raw:", value_raw);
+ float value = (float)value_raw/10;
+ ExtUI::extruder_t extruder;
+ switch (var.VP) {
+ default: return;
+ #if HOTENDS >= 1
+ case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break;
+ #endif
+ }
+ DEBUG_ECHOLNPAIR_F("value:", value);
+ ExtUI::setAxisSteps_per_mm(value,extruder);
+ DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(extruder));
+ ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ return;
+}
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t rawvalue = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPAIR("V1:", rawvalue);
+ float value = (float)rawvalue / 10;
+ DEBUG_ECHOLNPAIR("V2:", value);
+ float newvalue = 0;
+
+ switch (var.VP) {
+ default: return;
+ #if HOTENDS >= 1
+ case VP_E0_PID_P: newvalue = value; break;
+ case VP_E0_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E0_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_E1_PID_P: newvalue = value; break;
+ case VP_E1_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E1_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_BED_PID_P: newvalue = value; break;
+ case VP_BED_PID_I: newvalue = scalePID_i(value); break;
+ case VP_BED_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ }
+
+ DEBUG_ECHOLNPAIR_F("V3:", newvalue);
+ *(float *)var.memadr = newvalue;
+ ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ }
+
+ void DGUSScreenHandler::HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandlePIDAutotune");
+
+ char buf[32] = {0};
+
+ switch (var.VP) {
+ default: break;
+ #if ENABLED(PIDTEMP)
+ #if HOTENDS >= 1
+ case VP_PID_AUTOTUNE_E0: // Autotune Extruder 0
+ sprintf(buf, "M303 E%d C5 S210 U1", ExtUI::extruder_t::E0);
+ break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_PID_AUTOTUNE_E1:
+ sprintf(buf, "M303 E%d C5 S210 U1", ExtUI::extruder_t::E1);
+ break;
+ #endif
+ #endif
+ #if ENABLED(PIDTEMPBED)
+ case VP_PID_AUTOTUNE_BED:
+ sprintf(buf, "M303 E-1 C5 S70 U1");
+ break;
+ #endif
+ }
+
+ if (buf[0]) queue.enqueue_one_now(buf);
+
+ #if ENABLED(DGUS_UI_WAITING)
+ sendinfoscreen(PSTR("PID is autotuning"), PSTR("please wait"), NUL_STR, NUL_STR, true, true, true, true);
+ GotoScreen(DGUSLCD_SCREEN_WAITING);
+ #endif
+ }
+#endif
+
+#if HAS_BED_PROBE
+ void DGUSScreenHandler::HandleProbeOffsetZChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleProbeOffsetZChanged");
+
+ const float offset = float(int16_t(swap16(*(uint16_t*)val_ptr))) / 100.0f;
+ ExtUI::setZOffset_mm(offset);
+ ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ return;
+ }
+#endif
+
+#if ENABLED(BABYSTEPPING)
+ void DGUSScreenHandler::HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleLiveAdjustZ");
+
+ int16_t flag = swap16(*(uint16_t*)val_ptr);
+ int16_t steps = flag ? -20 : 20;
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::axis_t::Z, true);
+ ScreenHandler.ForceCompleteUpdate();
+ return;
+ }
+#endif
+
+#if HAS_FAN
+ void DGUSScreenHandler::HandleFanControl(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleFanControl");
+ *(uint8_t*)var.memadr = *(uint8_t*)var.memadr > 0 ? 0 : 255;
+ }
+#endif
+
+void DGUSScreenHandler::HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleHeaterControl");
+
+ uint8_t preheat_temp = 0;
+ switch (var.VP) {
+ #if HOTENDS >= 1
+ case VP_E0_CONTROL:
+ #endif
+ #if HOTENDS >= 2
+ case VP_E1_CONTROL:
+ #endif
+ #if HOTENDS >= 3
+ case VP_E2_CONTROL:
+ #endif
+ preheat_temp = PREHEAT_1_TEMP_HOTEND;
+ break;
+
+ case VP_BED_CONTROL:
+ preheat_temp = PREHEAT_1_TEMP_BED;
+ break;
+ }
+
+ *(int16_t*)var.memadr = *(int16_t*)var.memadr > 0 ? 0 : preheat_temp;
+}
+
+#if ENABLED(DGUS_PREHEAT_UI)
+
+ void DGUSScreenHandler::HandlePreheat(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandlePreheat");
+
+ uint8_t e_temp = 0;
+ TERN_(HAS_HEATED_BED, uint8_t bed_temp = 0);
+ const uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
+ switch (preheat_option) {
+ default:
+ case 0: // Preheat PLA
+ #if defined(PREHEAT_1_TEMP_HOTEND) && defined(PREHEAT_1_TEMP_BED)
+ e_temp = PREHEAT_1_TEMP_HOTEND;
+ TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_1_TEMP_BED);
+ #endif
+ break;
+ case 1: // Preheat ABS
+ #if defined(PREHEAT_2_TEMP_HOTEND) && defined(PREHEAT_2_TEMP_BED)
+ e_temp = PREHEAT_2_TEMP_HOTEND;
+ TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_2_TEMP_BED);
+ #endif
+ break;
+ case 2: // Preheat PET
+ #if defined(PREHEAT_3_TEMP_HOTEND) && defined(PREHEAT_3_TEMP_BED)
+ e_temp = PREHEAT_3_TEMP_HOTEND;
+ TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_3_TEMP_BED);
+ #endif
+ break;
+ case 3: // Preheat FLEX
+ #if defined(PREHEAT_4_TEMP_HOTEND) && defined(PREHEAT_4_TEMP_BED)
+ e_temp = PREHEAT_4_TEMP_HOTEND;
+ TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_4_TEMP_BED);
+ #endif
+ break;
+ case 7: break; // Custom preheat
+ case 9: break; // Cool down
+ }
+
+ switch (var.VP) {
+ default: return;
+ #if HOTENDS >= 1
+ case VP_E0_BED_PREHEAT:
+ thermalManager.setTargetHotend(e_temp, 0);
+ TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp));
+ break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_E1_BED_PREHEAT:
+ thermalManager.setTargetHotend(e_temp, 1);
+ TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp));
+ break;
+ #endif
+ }
+
+ // Go to the preheat screen to show the heating progress
+ GotoScreen(DGUSLCD_SCREEN_PREHEAT);
+ }
+
+#endif
+
+#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+
+ typedef struct {
+ ExtUI::extruder_t extruder; // which extruder to operate
+ uint8_t action; // load or unload
+ bool heated; // heating done ?
+ float purge_length; // the length to extrude before unload, prevent filament jam
+ } filament_data_t;
+
+ static filament_data_t filament_data;
+
+ void DGUSScreenHandler::HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleFilamentOption");
+
+ uint8_t e_temp = 0;
+ filament_data.heated = false;
+ uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
+ if (preheat_option <= 8) // Load filament type
+ filament_data.action = 1;
+ else if (preheat_option >= 10) { // Unload filament type
+ preheat_option -= 10;
+ filament_data.action = 2;
+ filament_data.purge_length = DGUS_FILAMENT_PURGE_LENGTH;
+ }
+ else // Cancel filament operation
+ filament_data.action = 0;
+
+ switch (preheat_option) {
+ case 0: // Load PLA
+ #ifdef PREHEAT_1_TEMP_HOTEND
+ e_temp = PREHEAT_1_TEMP_HOTEND;
+ #endif
+ break;
+ case 1: // Load ABS
+ TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND);
+ break;
+ case 2: // Load PET
+ #ifdef PREHEAT_3_TEMP_HOTEND
+ e_temp = PREHEAT_3_TEMP_HOTEND;
+ #endif
+ break;
+ case 3: // Load FLEX
+ #ifdef PREHEAT_4_TEMP_HOTEND
+ e_temp = PREHEAT_4_TEMP_HOTEND;
+ #endif
+ break;
+ case 9: // Cool down
+ default:
+ e_temp = 0;
+ break;
+ }
+
+ if (filament_data.action == 0) { // Go back to utility screen
+ #if HOTENDS >= 1
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0);
+ #endif
+ #if HOTENDS >= 2
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1);
+ #endif
+ GotoScreen(DGUSLCD_SCREEN_UTILITY);
+ }
+ else { // Go to the preheat screen to show the heating progress
+ switch (var.VP) {
+ default: return;
+ #if HOTENDS >= 1
+ case VP_E0_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E0;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ #if HOTENDS >= 2
+ case VP_E1_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E1;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ }
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_HEATING);
+ }
+ }
+
+ void DGUSScreenHandler::HandleFilamentLoadUnload(DGUS_VP_Variable &var) {
+ DEBUG_ECHOLNPGM("HandleFilamentLoadUnload");
+ if (filament_data.action <= 0) return;
+
+ // If we close to the target temperature, we can start load or unload the filament
+ if (thermalManager.hotEnoughToExtrude(filament_data.extruder) && \
+ thermalManager.targetHotEnoughToExtrude(filament_data.extruder)) {
+ float movevalue = DGUS_FILAMENT_LOAD_LENGTH_PER_TIME;
+
+ if (filament_data.action == 1) { // load filament
+ if (!filament_data.heated) {
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_LOADING);
+ filament_data.heated = true;
+ }
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder)+movevalue;
+ }
+ else { // unload filament
+ if (!filament_data.heated) {
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_UNLOADING);
+ filament_data.heated = true;
+ }
+ // Before unloading extrude to prevent jamming
+ if (filament_data.purge_length >= 0) {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ filament_data.purge_length -= movevalue;
+ }
+ else
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue;
+ }
+ ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder);
+ }
+ }
+#endif
+
+void DGUSScreenHandler::UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup) {
+ DEBUG_ECHOLNPAIR("SetNewScreen: ", newscreen);
+
+ if (!popup) {
+ memmove(&past_screens[1], &past_screens[0], sizeof(past_screens) - 1);
+ past_screens[0] = current_screen;
+ }
+
+ current_screen = newscreen;
+ skipVP = 0;
+ ForceCompleteUpdate();
+}
+
+void DGUSScreenHandler::PopToOldScreen() {
+ DEBUG_ECHOLNPAIR("PopToOldScreen s=", past_screens[0]);
+ GotoScreen(past_screens[0], true);
+ memmove(&past_screens[0], &past_screens[1], sizeof(past_screens) - 1);
+ past_screens[sizeof(past_screens) - 1] = DGUSLCD_SCREEN_MAIN;
+}
+
+void DGUSScreenHandler::UpdateScreenVPData() {
+ DEBUG_ECHOPAIR(" UpdateScreenVPData Screen: ", current_screen);
+
+ const uint16_t *VPList = DGUSLCD_FindScreenVPMapList(current_screen);
+ if (!VPList) {
+ DEBUG_ECHOLNPAIR(" NO SCREEN FOR: ", current_screen);
+ ScreenComplete = true;
+ return; // nothing to do, likely a bug or boring screen.
+ }
+
+ // Round-robin updating of all VPs.
+ VPList += update_ptr;
+
+ bool sent_one = false;
+ do {
+ uint16_t VP = pgm_read_word(VPList);
+ DEBUG_ECHOPAIR(" VP: ", VP);
+ if (!VP) {
+ update_ptr = 0;
+ DEBUG_ECHOLNPGM(" UpdateScreenVPData done");
+ ScreenComplete = true;
+ return; // Screen completed.
+ }
+
+ if (VP == skipVP) { skipVP = 0; continue; }
+
+ DGUS_VP_Variable rcpy;
+ if (populate_VPVar(VP, &rcpy)) {
+ uint8_t expected_tx = 6 + rcpy.size; // expected overhead is 6 bytes + payload.
+ // Send the VP to the display, but try to avoid overrunning the Tx Buffer.
+ // But send at least one VP, to avoid getting stalled.
+ if (rcpy.send_to_display_handler && (!sent_one || expected_tx <= dgusdisplay.GetFreeTxBuffer())) {
+ //DEBUG_ECHOPAIR(" calling handler for ", rcpy.VP);
+ sent_one = true;
+ rcpy.send_to_display_handler(rcpy);
+ }
+ else {
+ //auto x=dgusdisplay.GetFreeTxBuffer();
+ //DEBUG_ECHOLNPAIR(" tx almost full: ", x);
+ //DEBUG_ECHOPAIR(" update_ptr ", update_ptr);
+ ScreenComplete = false;
+ return; // please call again!
+ }
+ }
+
+ } while (++update_ptr, ++VPList, true);
+}
+
+void DGUSScreenHandler::GotoScreen(DGUSLCD_Screens screen, bool ispopup) {
+ dgusdisplay.RequestScreen(screen);
+ UpdateNewScreen(screen, ispopup);
+}
+
+bool DGUSScreenHandler::loop() {
+ dgusdisplay.loop();
+
+ const millis_t ms = millis();
+ static millis_t next_event_ms = 0;
+
+ if (!IsScreenComplete() || ELAPSED(ms, next_event_ms)) {
+ next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
+ UpdateScreenVPData();
+ }
+
+ #if ENABLED(SHOW_BOOTSCREEN)
+ static bool booted = false;
+ if (!booted && TERN0(POWER_LOSS_RECOVERY, recovery.valid()))
+ booted = true;
+ if (!booted && ELAPSED(ms, BOOTSCREEN_TIMEOUT)) {
+ booted = true;
+ GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+ #endif
+ return IsScreenComplete();
+}
+
+void DGUSDisplay::RequestScreen(DGUSLCD_Screens screen) {
+ DEBUG_ECHOLNPAIR("GotoScreen ", screen);
+ const unsigned char gotoscreen[] = { 0x5A, 0x01, (unsigned char) (screen >> 8U), (unsigned char) (screen & 0xFFU) };
+ WriteVariable(0x84, gotoscreen, sizeof(gotoscreen));
+}
+
+#endif // HAS_DGUS_LCD
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.h b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.h
new file mode 100644
index 0000000..df738db
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.h
@@ -0,0 +1,232 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "DGUSDisplay.h"
+#include "DGUSVPVariable.h"
+
+#include "../../../../inc/MarlinConfig.h"
+
+enum DGUSLCD_Screens : uint8_t;
+
+class DGUSScreenHandler {
+public:
+ DGUSScreenHandler() = default;
+
+ static bool loop();
+
+ /// Send all 4 strings that are displayed on the infoscreen, confirmation screen and kill screen
+ /// The bools specifing whether the strings are in RAM or FLASH.
+ static void sendinfoscreen(const char* line1, const char* line2, const char* line3, const char* line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash);
+
+ static void HandleUserConfirmationPopUp(uint16_t ConfirmVP, const char* line1, const char* line2, const char* line3, const char* line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash);
+
+ /// "M117" Message -- msg is a RAM ptr.
+ static void setstatusmessage(const char* msg);
+ /// The same for messages from Flash
+ static void setstatusmessagePGM(PGM_P const msg);
+ // Callback for VP "Display wants to change screen on idle printer"
+ static void ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr);
+ // Callback for VP "Screen has been changed"
+ static void ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr);
+ // Callback for VP "All Heaters Off"
+ static void HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for "Change this temperature"
+ static void HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for "Change Flowrate"
+ static void HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr);
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ // Hook for manual move option
+ static void HandleManualMoveOption(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ // Hook for manual move.
+ static void HandleManualMove(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for manual extrude.
+ static void HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for motor lock and unlook
+ static void HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr);
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ // Hook for power loss recovery.
+ static void HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ // Hook for settings
+ static void HandleSettings(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr);
+ #if HAS_PID_HEATING
+ // Hook for "Change this temperature PID para"
+ static void HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for PID autotune
+ static void HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if HAS_BED_PROBE
+ // Hook for "Change probe offset z"
+ static void HandleProbeOffsetZChanged(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if ENABLED(BABYSTEPPING)
+ // Hook for live z adjust action
+ static void HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if HAS_FAN
+ // Hook for fan control
+ static void HandleFanControl(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ // Hook for heater control
+ static void HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr);
+ #if ENABLED(DGUS_PREHEAT_UI)
+ // Hook for preheat
+ static void HandlePreheat(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ // Hook for filament load and unload filament option
+ static void HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for filament load and unload
+ static void HandleFilamentLoadUnload(DGUS_VP_Variable &var);
+ #endif
+
+ #if ENABLED(SDSUPPORT)
+ // Callback for VP "Display wants to change screen when there is a SD card"
+ static void ScreenChangeHookIfSD(DGUS_VP_Variable &var, void *val_ptr);
+ /// Scroll buttons on the file listing screen.
+ static void DGUSLCD_SD_ScrollFilelist(DGUS_VP_Variable &var, void *val_ptr);
+ /// File touched.
+ static void DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr);
+ /// start print after confirmation received.
+ static void DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr);
+ /// User hit the pause, resume or abort button.
+ static void DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr);
+ /// User confirmed the abort action
+ static void DGUSLCD_SD_ReallyAbort(DGUS_VP_Variable &var, void *val_ptr);
+ /// User hit the tune button
+ static void DGUSLCD_SD_PrintTune(DGUS_VP_Variable &var, void *val_ptr);
+ /// Send a single filename to the display.
+ static void DGUSLCD_SD_SendFilename(DGUS_VP_Variable &var);
+ /// Marlin informed us that a new SD has been inserted.
+ static void SDCardInserted();
+ /// Marlin informed us that the SD Card has been removed().
+ static void SDCardRemoved();
+ /// Marlin informed us about a bad SD Card.
+ static void SDCardError();
+ #endif
+
+ // OK Button the Confirm screen.
+ static void ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr);
+
+ // Update data after went to new screen (by display or by GotoScreen)
+ // remember: store the last-displayed screen, so it can get returned to.
+ // (e.g for pop up messages)
+ static void UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup=false);
+
+ // Recall the remembered screen.
+ static void PopToOldScreen();
+
+ // Make the display show the screen and update all VPs in it.
+ static void GotoScreen(DGUSLCD_Screens screen, bool ispopup = false);
+
+ static void UpdateScreenVPData();
+
+ // Helpers to convert and transfer data to the display.
+ static void DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var);
+ #if ENABLED(PRINTCOUNTER)
+ static void DGUSLCD_SendPrintAccTimeToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPrintsTotalToDisplay(DGUS_VP_Variable &var);
+ #endif
+ #if HAS_FAN
+ static void DGUSLCD_SendFanStatusToDisplay(DGUS_VP_Variable &var);
+ #endif
+ static void DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var);
+ #if ENABLED(DGUS_UI_WAITING)
+ static void DGUSLCD_SendWaitingStatusToDisplay(DGUS_VP_Variable &var);
+ #endif
+
+ /// Send a value from 0..100 to a variable with a range from 0..255
+ static void DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr);
+
+ template<typename T>
+ static void DGUSLCD_SetValueDirectly(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!var.memadr) return;
+ union { unsigned char tmp[sizeof(T)]; T t; } x;
+ unsigned char *ptr = (unsigned char*)val_ptr;
+ LOOP_L_N(i, sizeof(T)) x.tmp[i] = ptr[sizeof(T) - i - 1];
+ *(T*)var.memadr = x.t;
+ }
+
+ /// Send a float value to the display.
+ /// Display will get a 4-byte integer scaled to the number of digits:
+ /// Tell the display the number of digits and it cheats by displaying a dot between...
+ template<unsigned int decimals>
+ static void DGUSLCD_SendFloatAsLongValueToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ float f = *(float *)var.memadr;
+ f *= cpow(10, decimals);
+ dgusdisplay.WriteVariable(var.VP, (long)f);
+ }
+ }
+
+ /// Send a float value to the display.
+ /// Display will get a 2-byte integer scaled to the number of digits:
+ /// Tell the display the number of digits and it cheats by displaying a dot between...
+ template<unsigned int decimals>
+ static void DGUSLCD_SendFloatAsIntValueToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ float f = *(float *)var.memadr;
+ DEBUG_ECHOLNPAIR_F(" >> ", f, 6);
+ f *= cpow(10, decimals);
+ dgusdisplay.WriteVariable(var.VP, (int16_t)f);
+ }
+ }
+
+ /// Force an update of all VP on the current screen.
+ static inline void ForceCompleteUpdate() { update_ptr = 0; ScreenComplete = false; }
+ /// Has all VPs sent to the screen
+ static inline bool IsScreenComplete() { return ScreenComplete; }
+
+ static inline DGUSLCD_Screens getCurrentScreen() { return current_screen; }
+
+ static inline void SetupConfirmAction( void (*f)()) { confirm_action_cb = f; }
+
+private:
+ static DGUSLCD_Screens current_screen; ///< currently on screen
+ static constexpr uint8_t NUM_PAST_SCREENS = 4;
+ static DGUSLCD_Screens past_screens[NUM_PAST_SCREENS]; ///< LIFO with past screens for the "back" button.
+
+ static uint8_t update_ptr; ///< Last sent entry in the VPList for the actual screen.
+ static uint16_t skipVP; ///< When updating the screen data, skip this one, because the user is interacting with it.
+ static bool ScreenComplete; ///< All VPs sent to screen?
+
+ static uint16_t ConfirmVP; ///< context for confirm screen (VP that will be emulated-sent on "OK").
+
+ #if ENABLED(SDSUPPORT)
+ static int16_t top_file; ///< file on top of file chooser
+ static int16_t file_to_print; ///< touched file to be confirmed
+ #endif
+
+ static void (*confirm_action_cb)();
+};
+
+extern DGUSScreenHandler ScreenHandler;
diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSVPVariable.h b/Marlin/src/lcd/extui/lib/dgus/DGUSVPVariable.h
new file mode 100644
index 0000000..8c193c7
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/DGUSVPVariable.h
@@ -0,0 +1,49 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+
+/**
+ * DGUSVPVariable.h
+ *
+ * Created on: Feb 9, 2019
+ * Author: tobi
+ */
+
+struct DGUS_VP_Variable {
+ uint16_t VP;
+ void* memadr; // If nullptr, the value cannot be uploaded to the display.
+ uint8_t size;
+
+ // Callback that will be called if the display modified the value.
+ // nullptr makes it readonly for the display.
+ void (*set_by_display_handler)(DGUS_VP_Variable &var, void *val_ptr);
+ void (*send_to_display_handler)(DGUS_VP_Variable &var);
+
+ template<typename T>
+ DGUS_VP_Variable& operator =(T &o) {
+ *(T*)memadr = o; // warning this is not typesafe.
+ // TODO: Call out the display or mark as dirty for the next update.
+ return *this;
+ }
+};
diff --git a/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.cpp
new file mode 100644
index 0000000..467444c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.cpp
@@ -0,0 +1,486 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/* DGUS VPs changed by George Fu in 2019 for Marlin */
+
+#include "../../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_FYSETC)
+
+#include "DGUSDisplayDef.h"
+#include "../DGUSDisplay.h"
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../../module/temperature.h"
+#include "../../../../../module/motion.h"
+#include "../../../../../module/planner.h"
+
+#include "../../../ui_api.h"
+#include "../../../../marlinui.h"
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ uint16_t distanceToMove = 10;
+#endif
+
+const uint16_t VPList_Boot[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ 0x0000
+};
+
+const uint16_t VPList_Main[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded. */
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set, VP_E0_STATUS,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set, VP_BED_STATUS,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage, VP_FAN0_STATUS,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
+ VP_PrintProgress_Percentage,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Temp[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Status[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded */
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ VP_PrintProgress_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_Status2[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded */
+ #if HOTENDS >= 1
+ VP_Flowrate_E0,
+ #endif
+ #if HOTENDS >= 2
+ VP_Flowrate_E1,
+ #endif
+ VP_PrintProgress_Percentage,
+ VP_PrintTime,
+ 0x0000
+};
+
+const uint16_t VPList_Preheat[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_ManualMove[] PROGMEM = {
+ VP_XPos, VP_YPos, VP_ZPos,
+ 0x0000
+};
+
+const uint16_t VPList_ManualExtrude[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ VP_EPos,
+ 0x0000
+};
+
+const uint16_t VPList_FanAndFeedrate[] PROGMEM = {
+ VP_Feedrate_Percentage, VP_Fan0_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_SD_FlowRates[] PROGMEM = {
+ VP_Flowrate_E0, VP_Flowrate_E1,
+ 0x0000
+};
+
+const uint16_t VPList_Filament_heating[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ VP_E1_FILAMENT_LOAD_UNLOAD,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Filament_load_unload[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #endif
+ #if HOTENDS >= 2
+ VP_E1_FILAMENT_LOAD_UNLOAD,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_SDFileList[] PROGMEM = {
+ VP_SD_FileName0, VP_SD_FileName1, VP_SD_FileName2, VP_SD_FileName3, VP_SD_FileName4,
+ 0x0000
+};
+
+const uint16_t VPList_SD_PrintManipulation[] PROGMEM = {
+ VP_PrintProgress_Percentage, VP_PrintTime,
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #if FAN_COUNT > 1
+ VP_Fan1_Percentage,
+ #endif
+ #endif
+ VP_Flowrate_E0,
+ 0x0000
+};
+
+const uint16_t VPList_SDPrintTune[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set, VP_Flowrate_E0,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set, VP_Flowrate_E1,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ VP_Feedrate_Percentage,
+ VP_SD_Print_ProbeOffsetZ,
+ 0x0000
+};
+
+const uint16_t VPList_StepPerMM[] PROGMEM = {
+ VP_X_STEP_PER_MM,
+ VP_Y_STEP_PER_MM,
+ VP_Z_STEP_PER_MM,
+ #if HOTENDS >= 1
+ VP_E0_STEP_PER_MM,
+ #endif
+ #if HOTENDS >= 2
+ VP_E1_STEP_PER_MM,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDE0[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_E0_PID_P,
+ VP_E0_PID_I,
+ VP_E0_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDBED[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_BED_PID_P,
+ VP_BED_PID_I,
+ VP_BED_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Infos[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ VP_PrintTime,
+ #if ENABLED(PRINTCOUNTER)
+ VP_PrintAccTime,
+ VP_PrintsTotal,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDTuningWaiting[] PROGMEM = {
+ VP_WAITING_STATUS,
+ 0x0000
+};
+
+const uint16_t VPList_FLCPreheat[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_FLCPrinting[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Z_Offset[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const struct VPMapping VPMap[] PROGMEM = {
+ { DGUSLCD_SCREEN_BOOT, VPList_Boot },
+ { DGUSLCD_SCREEN_MAIN, VPList_Main },
+ { DGUSLCD_SCREEN_TEMPERATURE, VPList_Temp },
+ { DGUSLCD_SCREEN_STATUS, VPList_Status },
+ { DGUSLCD_SCREEN_STATUS2, VPList_Status2 },
+ { DGUSLCD_SCREEN_PREHEAT, VPList_Preheat },
+ { DGUSLCD_SCREEN_MANUALMOVE, VPList_ManualMove },
+ { DGUSLCD_SCREEN_MANUALEXTRUDE, VPList_ManualExtrude },
+ { DGUSLCD_SCREEN_FILAMENT_HEATING, VPList_Filament_heating },
+ { DGUSLCD_SCREEN_FILAMENT_LOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_FILAMENT_UNLOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_SDPRINTMANIPULATION, VPList_SD_PrintManipulation },
+ { DGUSLCD_SCREEN_SDFILELIST, VPList_SDFileList },
+ { DGUSLCD_SCREEN_SDPRINTTUNE, VPList_SDPrintTune },
+ { DGUSLCD_SCREEN_WAITING, VPList_PIDTuningWaiting },
+ { DGUSLCD_SCREEN_FLC_PREHEAT, VPList_FLCPreheat },
+ { DGUSLCD_SCREEN_FLC_PRINTING, VPList_FLCPrinting },
+ { DGUSLCD_SCREEN_Z_OFFSET, VPList_Z_Offset },
+ { DGUSLCD_SCREEN_STEPPERMM, VPList_StepPerMM },
+ { DGUSLCD_SCREEN_PID_E, VPList_PIDE0 },
+ { DGUSLCD_SCREEN_PID_BED, VPList_PIDBED },
+ { DGUSLCD_SCREEN_INFOS, VPList_Infos },
+ { 0 , nullptr } // List is terminated with an nullptr as table entry.
+};
+
+const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
+
+// Helper to define a DGUS_VP_Variable for common use cases.
+#define VPHELPER(VPADR, VPADRVAR, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=sizeof(VPADRVAR), \
+ .set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
+
+// Helper to define a DGUS_VP_Variable when the sizeo of the var cannot be determined automaticalyl (eg. a string)
+#define VPHELPER_STR(VPADR, VPADRVAR, STRLEN, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=STRLEN, \
+ .set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
+
+const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
+ // Helper to detect touch events
+ VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
+ VPHELPER(VP_SCREENCHANGE_ASK, nullptr, ScreenHandler.ScreenChangeHookIfIdle, nullptr),
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SCREENCHANGE_WHENSD, nullptr, ScreenHandler.ScreenChangeHookIfSD, nullptr),
+ #endif
+ VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
+
+ VPHELPER(VP_TEMP_ALL_OFF, nullptr, &ScreenHandler.HandleAllHeatersOff, nullptr),
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_OPTION, &distanceToMove, &ScreenHandler.HandleManualMoveOption, nullptr),
+ #endif
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_X, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ #else
+ VPHELPER(VP_MOVE_X, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ #endif
+ VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, &ScreenHandler.HandleMotorLockUnlock, nullptr),
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, &ScreenHandler.HandlePowerLossRecovery, nullptr),
+ #endif
+ VPHELPER(VP_SETTINGS, nullptr, &ScreenHandler.HandleSettings, nullptr),
+ #if ENABLED(SINGLE_Z_CALIBRATION)
+ VPHELPER(VP_Z_CALIBRATE, nullptr, &ScreenHandler.HandleZCalibration, nullptr),
+ #endif
+
+ #if ENABLED(FIRST_LAYER_CAL)
+ VPHELPER(VP_Z_FIRST_LAYER_CAL, nullptr, &ScreenHandler.HandleFirstLayerCal, nullptr),
+ #endif
+
+ { .VP = VP_MARLIN_VERSION, .memadr = (void*)MarlinVersion, .size = VP_MARLIN_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ // M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
+ { .VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplay },
+
+ // Temperature Data
+ #if HOTENDS >= 1
+ VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], ScreenHandler.HandleFlowRateChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_EPos, &destination.e, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_MOVE_E0, nullptr, &ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E0_STATUS, &thermalManager.temp_hotend[0].target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(DGUS_PREHEAT_UI)
+ VPHELPER(VP_E0_BED_PREHEAT, nullptr, &ScreenHandler.HandlePreheat, nullptr),
+ #endif
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_E0_PID_P, &thermalManager.temp_hotend[0].pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_I, &thermalManager.temp_hotend[0].pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_D, &thermalManager.temp_hotend[0].pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_E0, nullptr, &ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_E0_FILAMENT_LOAD_UNLOAD, nullptr, &ScreenHandler.HandleFilamentOption, &ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #endif
+ #if HOTENDS >= 2
+ VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[ExtUI::extruder_t::E1], ScreenHandler.HandleFlowRateChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_MOVE_E1, nullptr, &ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_PID_AUTOTUNE_E1, nullptr, &ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ VPHELPER(VP_E1_FILAMENT_LOAD_UNLOAD, nullptr, &ScreenHandler.HandleFilamentOption, &ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #if HAS_HEATED_BED
+ VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_BED_CONTROL, &thermalManager.temp_bed.target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_BED_STATUS, &thermalManager.temp_bed.target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMPBED)
+ VPHELPER(VP_BED_PID_P, &thermalManager.temp_bed.pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_I, &thermalManager.temp_bed.pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_D, &thermalManager.temp_bed.pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_BED, nullptr, &ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+
+ // Fan Data
+ #if HAS_FAN
+ #define FAN_VPHELPER(N) \
+ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], ScreenHandler.DGUSLCD_PercentageToUint8, &ScreenHandler.DGUSLCD_SendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], &ScreenHandler.HandleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, &ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
+ REPEAT(FAN_COUNT, FAN_VPHELPER)
+ #endif
+
+ // Feedrate
+ VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay ),
+
+ // Position Data
+ VPHELPER(VP_XPos, &current_position.x, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_YPos, &current_position.y, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_ZPos, &current_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+
+ // Print Progress
+ VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay ),
+
+ // Print Time
+ VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay),
+ #if ENABLED(PRINTCOUNTER)
+ VPHELPER_STR(VP_PrintAccTime, nullptr, VP_PrintAccTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintAccTimeToDisplay),
+ VPHELPER_STR(VP_PrintsTotal, nullptr, VP_PrintsTotal_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintsTotalToDisplay),
+ #endif
+
+ VPHELPER(VP_X_STEP_PER_MM, &planner.settings.axis_steps_per_mm[X_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Y_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Y_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Z_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Z_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HOTENDS >= 1
+ VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+ #if HOTENDS >= 2
+ VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+
+ // SDCard File listing.
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
+ VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
+ VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER(VP_SD_ResumePauseAbort, nullptr, ScreenHandler.DGUSLCD_SD_ResumePauseAbort, nullptr),
+ VPHELPER(VP_SD_AbortPrintConfirmed, nullptr, ScreenHandler.DGUSLCD_SD_ReallyAbort, nullptr),
+ VPHELPER(VP_SD_Print_Setting, nullptr, ScreenHandler.DGUSLCD_SD_PrintTune, nullptr),
+ #if HAS_BED_PROBE
+ VPHELPER(VP_SD_Print_ProbeOffsetZ, &probe.offset.z, ScreenHandler.HandleProbeOffsetZChanged, &ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
+ #if ENABLED(BABYSTEPPING)
+ VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, nullptr),
+ #endif
+ #endif
+ #endif
+
+ #if ENABLED(DGUS_UI_WAITING)
+ VPHELPER(VP_WAITING_STATUS, nullptr, nullptr, ScreenHandler.DGUSLCD_SendWaitingStatusToDisplay),
+ #endif
+
+ // Messages for the User, shared by the popup and the kill screen. They cant be autouploaded as we do not buffer content.
+ { .VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+
+ VPHELPER(0, 0, 0, 0) // must be last entry.
+};
+
+#endif // DGUS_LCD_UI_FYSETC
diff --git a/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.h
new file mode 100644
index 0000000..910f5f7
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.h
@@ -0,0 +1,296 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../DGUSDisplayDef.h"
+
+enum DGUSLCD_Screens : uint8_t {
+ DGUSLCD_SCREEN_BOOT = 0,
+ DGUSLCD_SCREEN_MAIN = 1,
+ DGUSLCD_SCREEN_STATUS = 1,
+ DGUSLCD_SCREEN_STATUS2 = 1,
+ DGUSLCD_SCREEN_TEMPERATURE = 10,
+ DGUSLCD_SCREEN_PREHEAT = 18,
+ DGUSLCD_SCREEN_POWER_LOSS = 100,
+ DGUSLCD_SCREEN_MANUALMOVE = 192,
+ DGUSLCD_SCREEN_UTILITY = 120,
+ DGUSLCD_SCREEN_FILAMENT_HEATING = 146,
+ DGUSLCD_SCREEN_FILAMENT_LOADING = 148,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING = 158,
+ DGUSLCD_SCREEN_MANUALEXTRUDE = 160,
+ DGUSLCD_SCREEN_SDFILELIST = 71,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 73,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 75,
+ DGUSLCD_SCREEN_FLC_PREHEAT = 94,
+ DGUSLCD_SCREEN_FLC_PRINTING = 96,
+ DGUSLCD_SCREEN_STEPPERMM = 212,
+ DGUSLCD_SCREEN_PID_E = 214,
+ DGUSLCD_SCREEN_PID_BED = 218,
+ DGUSLCD_SCREEN_Z_OFFSET = 222,
+ DGUSLCD_SCREEN_INFOS = 36,
+ DGUSLCD_SCREEN_CONFIRM = 240,
+ DGUSLCD_SCREEN_KILL = 250, ///< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version")
+ DGUSLCD_SCREEN_WAITING = 251,
+ DGUSLCD_SCREEN_POPUP = 252, ///< special target, popup screen will also return this code to say "return to previous screen"
+ DGUSLDC_SCREEN_UNUSED = 255
+};
+
+// Display Memory layout used (T5UID)
+// Except system variables this is arbitrary, just to organize stuff....
+
+// 0x0000 .. 0x0FFF -- System variables and reserved by the display
+// 0x1000 .. 0x1FFF -- Variables to never change location, regardless of UI Version
+// 0x2000 .. 0x2FFF -- Controls (VPs that will trigger some action)
+// 0x3000 .. 0x4FFF -- Marlin Data to be displayed
+// 0x5000 .. -- SPs (if we want to modify display elements, e.g change color or like) -- currently unused
+
+// As there is plenty of space (at least most displays have >8k RAM), we do not pack them too tight,
+// so that we can keep variables nicely together in the address space.
+
+// UI Version always on 0x1000...0x1002 so that the firmware can check this and bail out.
+constexpr uint16_t VP_UI_VERSION_MAJOR = 0x1000; // Major -- incremented when incompatible
+constexpr uint16_t VP_UI_VERSION_MINOR = 0x1001; // Minor -- incremented on new features, but compatible
+constexpr uint16_t VP_UI_VERSION_PATCH = 0x1002; // Patch -- fixed which do not change functionality.
+constexpr uint16_t VP_UI_FLAVOUR = 0x1010; // lets reserve 16 bytes here to determine if UI is suitable for this Marlin. tbd.
+
+// Storage space for the Killscreen messages. 0x1100 - 0x1200 . Reused for the popup.
+constexpr uint16_t VP_MSGSTR1 = 0x1100;
+constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
+constexpr uint16_t VP_MSGSTR2 = 0x1140;
+constexpr uint8_t VP_MSGSTR2_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR3 = 0x1180;
+constexpr uint8_t VP_MSGSTR3_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR4 = 0x11C0;
+constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
+
+// Screenchange request for screens that only make sense when printer is idle.
+// e.g movement is only allowed if printer is not printing.
+// Marlin must confirm by setting the screen manually.
+constexpr uint16_t VP_SCREENCHANGE_ASK = 0x2000;
+constexpr uint16_t VP_SCREENCHANGE = 0x2001; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
+constexpr uint16_t VP_TEMP_ALL_OFF = 0x2002; // Turn all heaters off. Value arbitrary ;)=
+constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x2003; // "Print" Button touched -- go only there if there is an SD Card.
+
+constexpr uint16_t VP_CONFIRMED = 0x2010; // OK on confirm screen.
+
+// Buttons on the SD-Card File listing.
+constexpr uint16_t VP_SD_ScrollEvent = 0x2020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
+constexpr uint16_t VP_SD_FileSelected = 0x2022; // Number of file field selected.
+constexpr uint16_t VP_SD_FileSelectConfirm = 0x2024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
+
+constexpr uint16_t VP_SD_ResumePauseAbort = 0x2026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
+constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x2028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
+constexpr uint16_t VP_SD_Print_Setting = 0x2040;
+constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x2050; // Data: 0 down, 1 up
+
+// Controls for movement (we can't use the incremental / decremental feature of the display at this feature works only with 16 bit values
+// (which would limit us to 655.35mm, which is likely not a problem for common setups, but i don't want to rule out hangprinters support)
+// A word about the coding: The VP will be per axis and the return code will be an signed 16 bit value in 0.01 mm resolution, telling us
+// the relative travel amount t he user wants to do. So eg. if the display sends us VP=2100 with value 100, the user wants us to move X by +1 mm.
+constexpr uint16_t VP_MOVE_X = 0x2100;
+constexpr uint16_t VP_MOVE_Y = 0x2102;
+constexpr uint16_t VP_MOVE_Z = 0x2104;
+constexpr uint16_t VP_MOVE_E0 = 0x2110;
+constexpr uint16_t VP_MOVE_E1 = 0x2112;
+//constexpr uint16_t VP_MOVE_E2 = 0x2114;
+//constexpr uint16_t VP_MOVE_E3 = 0x2116;
+//constexpr uint16_t VP_MOVE_E4 = 0x2118;
+//constexpr uint16_t VP_MOVE_E5 = 0x211A;
+constexpr uint16_t VP_HOME_ALL = 0x2120;
+constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130;
+
+// Power loss recovery
+constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180;
+
+// Fan Control Buttons , switch between "off" and "on"
+constexpr uint16_t VP_FAN0_CONTROL = 0x2200;
+constexpr uint16_t VP_FAN1_CONTROL = 0x2202;
+constexpr uint16_t VP_FAN2_CONTROL = 0x2204;
+constexpr uint16_t VP_FAN3_CONTROL = 0x2206;
+
+// Heater Control Buttons , triged between "cool down" and "heat PLA" state
+constexpr uint16_t VP_E0_CONTROL = 0x2210;
+constexpr uint16_t VP_E1_CONTROL = 0x2212;
+//constexpr uint16_t VP_E2_CONTROL = 0x2214;
+//constexpr uint16_t VP_E3_CONTROL = 0x2216;
+//constexpr uint16_t VP_E4_CONTROL = 0x2218;
+//constexpr uint16_t VP_E5_CONTROL = 0x221A;
+constexpr uint16_t VP_BED_CONTROL = 0x221C;
+
+// Preheat
+constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220;
+constexpr uint16_t VP_E1_BED_PREHEAT = 0x2222;
+//constexpr uint16_t VP_E2_BED_PREHEAT = 0x2224;
+//constexpr uint16_t VP_E3_BED_PREHEAT = 0x2226;
+//constexpr uint16_t VP_E4_BED_PREHEAT = 0x2228;
+//constexpr uint16_t VP_E5_BED_PREHEAT = 0x222A;
+
+// Filament load and unload
+constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300;
+constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2302;
+
+// Settings store , reset
+constexpr uint16_t VP_SETTINGS = 0x2400;
+
+// PID autotune
+constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x2410;
+constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x2412;
+//constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x2414;
+//constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x2416;
+//constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x2418;
+//constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x241A;
+constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x2420;
+
+// Calibrate Z
+constexpr uint16_t VP_Z_CALIBRATE = 0x2430;
+
+// First layer cal
+constexpr uint16_t VP_Z_FIRST_LAYER_CAL = 0x2500; // Data: 0 - Cancel first layer cal progress, >0 filament type have loaded
+
+// Firmware version on the boot screen.
+constexpr uint16_t VP_MARLIN_VERSION = 0x3000;
+constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed.
+
+// Place for status messages.
+constexpr uint16_t VP_M117 = 0x3020;
+constexpr uint8_t VP_M117_LEN = 0x20;
+
+// Temperatures.
+constexpr uint16_t VP_T_E0_Is = 0x3060; // 4 Byte Integer
+constexpr uint16_t VP_T_E0_Set = 0x3062; // 2 Byte Integer
+constexpr uint16_t VP_T_E1_Is = 0x3064; // 4 Byte Integer
+
+// reserved to support up to 6 Extruders:
+constexpr uint16_t VP_T_E1_Set = 0x3066; // 2 Byte Integer
+//constexpr uint16_t VP_T_E2_Is = 0x3068; // 4 Byte Integer
+//constexpr uint16_t VP_T_E2_Set = 0x306A; // 2 Byte Integer
+//constexpr uint16_t VP_T_E3_Is = 0x306C; // 4 Byte Integer
+//constexpr uint16_t VP_T_E3_Set = 0x306E; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3070; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3072; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3074; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3076; // 2 Byte Integer
+//constexpr uint16_t VP_T_E5_Is = 0x3078; // 4 Byte Integer
+//constexpr uint16_t VP_T_E5_Set = 0x307A; // 2 Byte Integer
+
+constexpr uint16_t VP_T_Bed_Is = 0x3080; // 4 Byte Integer
+constexpr uint16_t VP_T_Bed_Set = 0x3082; // 2 Byte Integer
+
+constexpr uint16_t VP_Flowrate_E0 = 0x3090; // 2 Byte Integer
+constexpr uint16_t VP_Flowrate_E1 = 0x3092; // 2 Byte Integer
+
+// reserved for up to 6 Extruders:
+//constexpr uint16_t VP_Flowrate_E2 = 0x3094;
+//constexpr uint16_t VP_Flowrate_E3 = 0x3096;
+//constexpr uint16_t VP_Flowrate_E4 = 0x3098;
+//constexpr uint16_t VP_Flowrate_E5 = 0x309A;
+
+constexpr uint16_t VP_Fan0_Percentage = 0x3100; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan1_Percentage = 0x3102; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan2_Percentage = 0x3104; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan3_Percentage = 0x3106; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Feedrate_Percentage = 0x3108; // 2 Byte Integer (0..100)
+
+// Actual Position
+constexpr uint16_t VP_XPos = 0x3110; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_YPos = 0x3112; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_ZPos = 0x3114; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_EPos = 0x3120; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_PrintProgress_Percentage = 0x3130; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_PrintTime = 0x3140;
+constexpr uint16_t VP_PrintTime_LEN = 32;
+
+constexpr uint16_t VP_PrintAccTime = 0x3160;
+constexpr uint16_t VP_PrintAccTime_LEN = 32;
+
+constexpr uint16_t VP_PrintsTotal = 0x3180;
+constexpr uint16_t VP_PrintsTotal_LEN = 16;
+
+// SDCard File Listing
+constexpr uint16_t VP_SD_FileName_LEN = 32; // LEN is shared for all entries.
+constexpr uint16_t DGUS_SD_FILESPERSCREEN = 5; // FIXME move that info to the display and read it from there.
+constexpr uint16_t VP_SD_FileName0 = 0x3200;
+constexpr uint16_t VP_SD_FileName1 = 0x3220;
+constexpr uint16_t VP_SD_FileName2 = 0x3240;
+constexpr uint16_t VP_SD_FileName3 = 0x3260;
+constexpr uint16_t VP_SD_FileName4 = 0x3280;
+
+constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0; //
+constexpr uint16_t VP_SD_Print_Filename = 0x32C0;
+
+// Fan status
+constexpr uint16_t VP_FAN0_STATUS = 0x3300;
+constexpr uint16_t VP_FAN1_STATUS = 0x3302;
+constexpr uint16_t VP_FAN2_STATUS = 0x3304;
+constexpr uint16_t VP_FAN3_STATUS = 0x3306;
+
+// Heater status
+constexpr uint16_t VP_E0_STATUS = 0x3310;
+constexpr uint16_t VP_E1_STATUS = 0x3312;
+//constexpr uint16_t VP_E2_STATUS = 0x3314;
+//constexpr uint16_t VP_E3_STATUS = 0x3316;
+//constexpr uint16_t VP_E4_STATUS = 0x3318;
+//constexpr uint16_t VP_E5_STATUS = 0x331A;
+constexpr uint16_t VP_BED_STATUS = 0x331C;
+
+constexpr uint16_t VP_MOVE_OPTION = 0x3400;
+
+// Step per mm
+constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , 2 byte unsigned int , 0~1638.4
+//constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602;
+constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604;
+//constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606;
+constexpr uint16_t VP_Z_STEP_PER_MM = 0x3608;
+//constexpr uint16_t VP_Z2_STEP_PER_MM = 0x360A;
+constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610;
+constexpr uint16_t VP_E1_STEP_PER_MM = 0x3612;
+//constexpr uint16_t VP_E2_STEP_PER_MM = 0x3614;
+//constexpr uint16_t VP_E3_STEP_PER_MM = 0x3616;
+//constexpr uint16_t VP_E4_STEP_PER_MM = 0x3618;
+//constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A;
+
+// PIDs
+constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E0_PID_I = 0x3702;
+constexpr uint16_t VP_E0_PID_D = 0x3704;
+constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E1_PID_I = 0x3708;
+constexpr uint16_t VP_E1_PID_D = 0x370A;
+constexpr uint16_t VP_BED_PID_P = 0x3710;
+constexpr uint16_t VP_BED_PID_I = 0x3712;
+constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+// Wating screen status
+constexpr uint16_t VP_WAITING_STATUS = 0x3800;
+
+// SPs for certain variables...
+// located at 0x5000 and up
+// Not used yet!
+// This can be used e.g to make controls / data display invisible
+constexpr uint16_t SP_T_E0_Is = 0x5000;
+constexpr uint16_t SP_T_E0_Set = 0x5010;
+constexpr uint16_t SP_T_E1_Is = 0x5020;
+constexpr uint16_t SP_T_Bed_Is = 0x5030;
+constexpr uint16_t SP_T_Bed_Set = 0x5040;
diff --git a/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.cpp
new file mode 100644
index 0000000..536640e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.cpp
@@ -0,0 +1,485 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/* DGUS VPs changed by George Fu in 2019 for Marlin */
+
+#include "../../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_HIPRECY)
+
+#include "DGUSDisplayDef.h"
+#include "../DGUSDisplay.h"
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../../module/temperature.h"
+#include "../../../../../module/motion.h"
+#include "../../../../../module/planner.h"
+
+#include "../../../ui_api.h"
+#include "../../../../marlinui.h"
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ uint16_t distanceToMove = 10;
+#endif
+
+const uint16_t VPList_Boot[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ 0x0000
+};
+
+const uint16_t VPList_Main[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded. */
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set, VP_E0_STATUS,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set, VP_BED_STATUS,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage, VP_FAN0_STATUS,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
+ VP_PrintProgress_Percentage,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Temp[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Status[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded */
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ VP_PrintProgress_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_Status2[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded */
+ #if HOTENDS >= 1
+ VP_Flowrate_E0,
+ #endif
+ #if HOTENDS >= 2
+ VP_Flowrate_E1,
+ #endif
+ VP_PrintProgress_Percentage,
+ VP_PrintTime,
+ 0x0000
+};
+
+const uint16_t VPList_Preheat[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_ManualMove[] PROGMEM = {
+ VP_XPos, VP_YPos, VP_ZPos,
+ 0x0000
+};
+
+const uint16_t VPList_ManualExtrude[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ VP_EPos,
+ 0x0000
+};
+
+const uint16_t VPList_FanAndFeedrate[] PROGMEM = {
+ VP_Feedrate_Percentage, VP_Fan0_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_SD_FlowRates[] PROGMEM = {
+ VP_Flowrate_E0, VP_Flowrate_E1,
+ 0x0000
+};
+
+const uint16_t VPList_Filament_heating[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Filament_load_unload[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #endif
+ #if HOTENDS >= 2
+ VP_E1_FILAMENT_LOAD_UNLOAD,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_SDFileList[] PROGMEM = {
+ VP_SD_FileName0, VP_SD_FileName1, VP_SD_FileName2, VP_SD_FileName3, VP_SD_FileName4,
+ 0x0000
+};
+
+const uint16_t VPList_SD_PrintManipulation[] PROGMEM = {
+ VP_PrintProgress_Percentage, VP_PrintTime,
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #if FAN_COUNT > 1
+ VP_Fan1_Percentage,
+ #endif
+ #endif
+ VP_Flowrate_E0,
+ 0x0000
+};
+
+const uint16_t VPList_SDPrintTune[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ VP_Feedrate_Percentage,
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_Flowrate_E0,
+ VP_SD_Print_ProbeOffsetZ,
+ 0x0000
+};
+
+const uint16_t VPList_StepPerMM[] PROGMEM = {
+ VP_X_STEP_PER_MM,
+ VP_Y_STEP_PER_MM,
+ VP_Z_STEP_PER_MM,
+ #if HOTENDS >= 1
+ VP_E0_STEP_PER_MM,
+ #endif
+ #if HOTENDS >= 2
+ VP_E1_STEP_PER_MM,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDE0[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_E0_PID_P,
+ VP_E0_PID_I,
+ VP_E0_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDBED[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_BED_PID_P,
+ VP_BED_PID_I,
+ VP_BED_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Infos[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ VP_PrintTime,
+ #if ENABLED(PRINTCOUNTER)
+ VP_PrintAccTime,
+ VP_PrintsTotal,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDTuningWaiting[] PROGMEM = {
+ VP_WAITING_STATUS,
+ 0x0000
+};
+
+const uint16_t VPList_FLCPreheat[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_FLCPrinting[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Z_Offset[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const struct VPMapping VPMap[] PROGMEM = {
+ { DGUSLCD_SCREEN_BOOT, VPList_Boot },
+ { DGUSLCD_SCREEN_MAIN, VPList_Main },
+ { DGUSLCD_SCREEN_TEMPERATURE, VPList_Temp },
+ { DGUSLCD_SCREEN_STATUS, VPList_Status },
+ { DGUSLCD_SCREEN_STATUS2, VPList_Status2 },
+ { DGUSLCD_SCREEN_PREHEAT, VPList_Preheat },
+ { DGUSLCD_SCREEN_MANUALMOVE, VPList_ManualMove },
+ { DGUSLCD_SCREEN_Z_OFFSET, VPList_Z_Offset },
+ { DGUSLCD_SCREEN_MANUALEXTRUDE, VPList_ManualExtrude },
+ { DGUSLCD_SCREEN_FILAMENT_HEATING, VPList_Filament_heating },
+ { DGUSLCD_SCREEN_FILAMENT_LOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_FILAMENT_UNLOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_SDPRINTMANIPULATION, VPList_SD_PrintManipulation },
+ { DGUSLCD_SCREEN_SDFILELIST, VPList_SDFileList },
+ { DGUSLCD_SCREEN_SDPRINTTUNE, VPList_SDPrintTune },
+ { DGUSLCD_SCREEN_WAITING, VPList_PIDTuningWaiting },
+ { DGUSLCD_SCREEN_FLC_PREHEAT, VPList_FLCPreheat },
+ { DGUSLCD_SCREEN_FLC_PRINTING, VPList_FLCPrinting },
+ { DGUSLCD_SCREEN_STEPPERMM, VPList_StepPerMM },
+ { DGUSLCD_SCREEN_PID_E, VPList_PIDE0 },
+ { DGUSLCD_SCREEN_PID_BED, VPList_PIDBED },
+ { DGUSLCD_SCREEN_INFOS, VPList_Infos },
+ { 0 , nullptr } // List is terminated with an nullptr as table entry.
+};
+
+const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
+
+// Helper to define a DGUS_VP_Variable for common use cases.
+#define VPHELPER(VPADR, VPADRVAR, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=sizeof(VPADRVAR), \
+ .set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
+
+// Helper to define a DGUS_VP_Variable when the sizeo of the var cannot be determined automaticalyl (eg. a string)
+#define VPHELPER_STR(VPADR, VPADRVAR, STRLEN, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=STRLEN, \
+ .set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
+
+const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
+ // Helper to detect touch events
+ VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
+ VPHELPER(VP_SCREENCHANGE_ASK, nullptr, ScreenHandler.ScreenChangeHookIfIdle, nullptr),
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SCREENCHANGE_WHENSD, nullptr, ScreenHandler.ScreenChangeHookIfSD, nullptr),
+ #endif
+ VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
+
+ VPHELPER(VP_TEMP_ALL_OFF, nullptr, &ScreenHandler.HandleAllHeatersOff, nullptr),
+
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_OPTION, &distanceToMove, &ScreenHandler.HandleManualMoveOption, nullptr),
+ #endif
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_X, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ #else
+ VPHELPER(VP_MOVE_X, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ #endif
+ VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, &ScreenHandler.HandleMotorLockUnlock, nullptr),
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, &ScreenHandler.HandlePowerLossRecovery, nullptr),
+ #endif
+ VPHELPER(VP_SETTINGS, nullptr, &ScreenHandler.HandleSettings, nullptr),
+ #if ENABLED(SINGLE_Z_CALIBRATION)
+ VPHELPER(VP_Z_CALIBRATE, nullptr, &ScreenHandler.HandleZCalibration, nullptr),
+ #endif
+ #if ENABLED(FIRST_LAYER_CAL)
+ VPHELPER(VP_Z_FIRST_LAYER_CAL, nullptr, &ScreenHandler.HandleFirstLayerCal, nullptr),
+ #endif
+
+ { .VP = VP_MARLIN_VERSION, .memadr = (void*)MarlinVersion, .size = VP_MARLIN_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ // M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
+ { .VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplay },
+
+ // Temperature Data
+ #if HOTENDS >= 1
+ VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], ScreenHandler.HandleFlowRateChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_EPos, &destination.e, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_MOVE_E0, nullptr, &ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E0_STATUS, &thermalManager.temp_hotend[0].target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(DGUS_PREHEAT_UI)
+ VPHELPER(VP_E0_BED_PREHEAT, nullptr, &ScreenHandler.HandlePreheat, nullptr),
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_E0_FILAMENT_LOAD_UNLOAD, nullptr, &ScreenHandler.HandleFilamentOption, &ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_E0_PID_P, &thermalManager.temp_hotend[0].pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_I, &thermalManager.temp_hotend[0].pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_D, &thermalManager.temp_hotend[0].pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_E0, nullptr, &ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+ #if HOTENDS >= 2
+ VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E1, nullptr, ScreenHandler.HandleFlowRateChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_MOVE_E1, nullptr, &ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #endif
+ #if HAS_HEATED_BED
+ VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_BED_CONTROL, &thermalManager.temp_bed.target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_BED_STATUS, &thermalManager.temp_bed.target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_BED_PID_P, &thermalManager.temp_bed.pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_I, &thermalManager.temp_bed.pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_D, &thermalManager.temp_bed.pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_BED, nullptr, &ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+
+ // Fan Data
+ #if HAS_FAN
+ #define FAN_VPHELPER(N) \
+ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], ScreenHandler.DGUSLCD_PercentageToUint8, &ScreenHandler.DGUSLCD_SendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], &ScreenHandler.HandleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, &ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
+ REPEAT(FAN_COUNT, FAN_VPHELPER)
+ #endif
+
+ // Feedrate
+ VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay ),
+
+ // Position Data
+ VPHELPER(VP_XPos, &current_position.x, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_YPos, &current_position.y, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_ZPos, &current_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+
+ // Print Progress
+ VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay ),
+
+ // Print Time
+ VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay ),
+ #if ENABLED(PRINTCOUNTER)
+ VPHELPER_STR(VP_PrintAccTime, nullptr, VP_PrintAccTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintAccTimeToDisplay ),
+ VPHELPER_STR(VP_PrintsTotal, nullptr, VP_PrintsTotal_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintsTotalToDisplay ),
+ #endif
+
+ VPHELPER(VP_X_STEP_PER_MM, &planner.settings.axis_steps_per_mm[X_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Y_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Y_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Z_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Z_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HOTENDS >= 1
+ VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+ #if HOTENDS >= 2
+ VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+
+ // SDCard File listing.
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
+ VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
+ VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER(VP_SD_ResumePauseAbort, nullptr, ScreenHandler.DGUSLCD_SD_ResumePauseAbort, nullptr),
+ VPHELPER(VP_SD_AbortPrintConfirmed, nullptr, ScreenHandler.DGUSLCD_SD_ReallyAbort, nullptr),
+ VPHELPER(VP_SD_Print_Setting, nullptr, ScreenHandler.DGUSLCD_SD_PrintTune, nullptr),
+ #if HAS_BED_PROBE
+ VPHELPER(VP_SD_Print_ProbeOffsetZ, &probe.offset.z, ScreenHandler.HandleProbeOffsetZChanged, &ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
+ #if ENABLED(BABYSTEPPING)
+ VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, nullptr),
+ #endif
+ #endif
+ #endif
+
+ #if ENABLED(DGUS_UI_WAITING)
+ VPHELPER(VP_WAITING_STATUS, nullptr, nullptr, ScreenHandler.DGUSLCD_SendWaitingStatusToDisplay),
+ #endif
+
+ // Messages for the User, shared by the popup and the kill screen. They cant be autouploaded as we do not buffer content.
+ { .VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+
+ VPHELPER(0, 0, 0, 0) // must be last entry.
+};
+
+#endif // DGUS_LCD_UI_HIPRECY
diff --git a/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.h
new file mode 100644
index 0000000..d18989a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.h
@@ -0,0 +1,292 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../DGUSDisplayDef.h"
+
+enum DGUSLCD_Screens : uint8_t {
+ DGUSLCD_SCREEN_BOOT = 160,
+ DGUSLCD_SCREEN_MAIN = 1,
+ DGUSLCD_SCREEN_STATUS = 1,
+ DGUSLCD_SCREEN_STATUS2 = 1,
+ DGUSLCD_SCREEN_POWER_LOSS = 17,
+ DGUSLCD_SCREEN_TEMPERATURE = 40,
+ DGUSLCD_SCREEN_MANUALMOVE = 86,
+ DGUSLCD_SCREEN_PREHEAT = 48,
+ DGUSLCD_SCREEN_UTILITY = 70,
+ DGUSLCD_SCREEN_FILAMENT_HEATING = 80,
+ DGUSLCD_SCREEN_FILAMENT_LOADING = 76,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING = 82,
+ DGUSLCD_SCREEN_MANUALEXTRUDE = 84,
+ DGUSLCD_SCREEN_Z_OFFSET = 88,
+ DGUSLCD_SCREEN_SDFILELIST = 3,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 7,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 9,
+ DGUSLCD_SCREEN_FLC_PREHEAT = 94,
+ DGUSLCD_SCREEN_FLC_PRINTING = 96,
+ DGUSLCD_SCREEN_STEPPERMM = 122,
+ DGUSLCD_SCREEN_PID_E = 126,
+ DGUSLCD_SCREEN_PID_BED = 128,
+ DGUSLCD_SCREEN_INFOS = 131,
+ DGUSLCD_SCREEN_CONFIRM = 240,
+ DGUSLCD_SCREEN_KILL = 250, ///< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version")
+ DGUSLCD_SCREEN_WAITING = 251,
+ DGUSLCD_SCREEN_POPUP = 252, ///< special target, popup screen will also return this code to say "return to previous screen"
+ DGUSLDC_SCREEN_UNUSED = 255
+};
+
+// Display Memory layout used (T5UID)
+// Except system variables this is arbitrary, just to organize stuff....
+
+// 0x0000 .. 0x0FFF -- System variables and reserved by the display
+// 0x1000 .. 0x1FFF -- Variables to never change location, regardless of UI Version
+// 0x2000 .. 0x2FFF -- Controls (VPs that will trigger some action)
+// 0x3000 .. 0x4FFF -- Marlin Data to be displayed
+// 0x5000 .. -- SPs (if we want to modify display elements, e.g change color or like) -- currently unused
+
+// As there is plenty of space (at least most displays have >8k RAM), we do not pack them too tight,
+// so that we can keep variables nicely together in the address space.
+
+// UI Version always on 0x1000...0x1002 so that the firmware can check this and bail out.
+constexpr uint16_t VP_UI_VERSION_MAJOR = 0x1000; // Major -- incremented when incompatible
+constexpr uint16_t VP_UI_VERSION_MINOR = 0x1001; // Minor -- incremented on new features, but compatible
+constexpr uint16_t VP_UI_VERSION_PATCH = 0x1002; // Patch -- fixed which do not change functionality.
+constexpr uint16_t VP_UI_FLAVOUR = 0x1010; // lets reserve 16 bytes here to determine if UI is suitable for this Marlin. tbd.
+
+// Storage space for the Killscreen messages. 0x1100 - 0x1200 . Reused for the popup.
+constexpr uint16_t VP_MSGSTR1 = 0x1100;
+constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
+constexpr uint16_t VP_MSGSTR2 = 0x1140;
+constexpr uint8_t VP_MSGSTR2_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR3 = 0x1180;
+constexpr uint8_t VP_MSGSTR3_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR4 = 0x11C0;
+constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
+
+// Screenchange request for screens that only make sense when printer is idle.
+// e.g movement is only allowed if printer is not printing.
+// Marlin must confirm by setting the screen manually.
+constexpr uint16_t VP_SCREENCHANGE_ASK = 0x2000;
+constexpr uint16_t VP_SCREENCHANGE = 0x2001; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
+constexpr uint16_t VP_TEMP_ALL_OFF = 0x2002; // Turn all heaters off. Value arbitrary ;)=
+constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x2003; // "Print" Button touched -- go only there if there is an SD Card.
+
+constexpr uint16_t VP_CONFIRMED = 0x2010; // OK on confirm screen.
+
+// Buttons on the SD-Card File listing.
+constexpr uint16_t VP_SD_ScrollEvent = 0x2020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
+constexpr uint16_t VP_SD_FileSelected = 0x2022; // Number of file field selected.
+constexpr uint16_t VP_SD_FileSelectConfirm = 0x2024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
+
+constexpr uint16_t VP_SD_ResumePauseAbort = 0x2026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
+constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x2028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
+constexpr uint16_t VP_SD_Print_Setting = 0x2040;
+constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x2050; // Data: 0 down, 1 up
+
+// Controls for movement (we can't use the incremental / decremental feature of the display at this feature works only with 16 bit values
+// (which would limit us to 655.35mm, which is likely not a problem for common setups, but i don't want to rule out hangprinters support)
+// A word about the coding: The VP will be per axis and the return code will be an signed 16 bit value in 0.01 mm resolution, telling us
+// the relative travel amount t he user wants to do. So eg. if the display sends us VP=2100 with value 100, the user wants us to move X by +1 mm.
+constexpr uint16_t VP_MOVE_X = 0x2100;
+constexpr uint16_t VP_MOVE_Y = 0x2102;
+constexpr uint16_t VP_MOVE_Z = 0x2104;
+constexpr uint16_t VP_MOVE_E0 = 0x2110;
+constexpr uint16_t VP_MOVE_E1 = 0x2112;
+//constexpr uint16_t VP_MOVE_E2 = 0x2114;
+//constexpr uint16_t VP_MOVE_E3 = 0x2116;
+//constexpr uint16_t VP_MOVE_E4 = 0x2118;
+//constexpr uint16_t VP_MOVE_E5 = 0x211A;
+constexpr uint16_t VP_HOME_ALL = 0x2120;
+constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130;
+
+// Power loss recovery
+constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180;
+
+// Fan Control Buttons , switch between "off" and "on"
+constexpr uint16_t VP_FAN0_CONTROL = 0x2200;
+constexpr uint16_t VP_FAN1_CONTROL = 0x2202;
+//constexpr uint16_t VP_FAN2_CONTROL = 0x2204;
+//constexpr uint16_t VP_FAN3_CONTROL = 0x2206;
+
+// Heater Control Buttons , triged between "cool down" and "heat PLA" state
+constexpr uint16_t VP_E0_CONTROL = 0x2210;
+constexpr uint16_t VP_E1_CONTROL = 0x2212;
+//constexpr uint16_t VP_E2_CONTROL = 0x2214;
+//constexpr uint16_t VP_E3_CONTROL = 0x2216;
+//constexpr uint16_t VP_E4_CONTROL = 0x2218;
+//constexpr uint16_t VP_E5_CONTROL = 0x221A;
+constexpr uint16_t VP_BED_CONTROL = 0x221C;
+
+// Preheat
+constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220;
+//constexpr uint16_t VP_E1_BED_PREHEAT = 0x2222;
+//constexpr uint16_t VP_E2_BED_PREHEAT = 0x2224;
+//constexpr uint16_t VP_E3_BED_PREHEAT = 0x2226;
+//constexpr uint16_t VP_E4_BED_PREHEAT = 0x2228;
+//constexpr uint16_t VP_E5_BED_PREHEAT = 0x222A;
+
+// Filament load and unload
+constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300;
+
+// Settings store , reset
+constexpr uint16_t VP_SETTINGS = 0x2400;
+
+// PID autotune
+constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x2410;
+//constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x2412;
+//constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x2414;
+//constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x2416;
+//constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x2418;
+//constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x241A;
+constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x2420;
+
+// Calibrate Z
+constexpr uint16_t VP_Z_CALIBRATE = 0x2430;
+
+// First layer cal
+constexpr uint16_t VP_Z_FIRST_LAYER_CAL = 0x2500; // Data: 0 - Cancel first layer cal progress, >0 filament type have loaded
+
+// Firmware version on the boot screen.
+constexpr uint16_t VP_MARLIN_VERSION = 0x3000;
+constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed.
+
+// Place for status messages.
+constexpr uint16_t VP_M117 = 0x3020;
+constexpr uint8_t VP_M117_LEN = 0x20;
+
+// Temperatures.
+constexpr uint16_t VP_T_E0_Is = 0x3060; // 4 Byte Integer
+constexpr uint16_t VP_T_E0_Set = 0x3062; // 2 Byte Integer
+constexpr uint16_t VP_T_E1_Is = 0x3064; // 4 Byte Integer
+
+// reserved to support up to 6 Extruders:
+//constexpr uint16_t VP_T_E1_Set = 0x3066; // 2 Byte Integer
+//constexpr uint16_t VP_T_E2_Is = 0x3068; // 4 Byte Integer
+//constexpr uint16_t VP_T_E2_Set = 0x306A; // 2 Byte Integer
+//constexpr uint16_t VP_T_E3_Is = 0x306C; // 4 Byte Integer
+//constexpr uint16_t VP_T_E3_Set = 0x306E; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3070; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3072; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3074; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3076; // 2 Byte Integer
+//constexpr uint16_t VP_T_E5_Is = 0x3078; // 4 Byte Integer
+//constexpr uint16_t VP_T_E5_Set = 0x307A; // 2 Byte Integer
+
+constexpr uint16_t VP_T_Bed_Is = 0x3080; // 4 Byte Integer
+constexpr uint16_t VP_T_Bed_Set = 0x3082; // 2 Byte Integer
+
+constexpr uint16_t VP_Flowrate_E0 = 0x3090; // 2 Byte Integer
+constexpr uint16_t VP_Flowrate_E1 = 0x3092; // 2 Byte Integer
+
+// reserved for up to 6 Extruders:
+//constexpr uint16_t VP_Flowrate_E2 = 0x3094;
+//constexpr uint16_t VP_Flowrate_E3 = 0x3096;
+//constexpr uint16_t VP_Flowrate_E4 = 0x3098;
+//constexpr uint16_t VP_Flowrate_E5 = 0x309A;
+
+constexpr uint16_t VP_Fan0_Percentage = 0x3100; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan1_Percentage = 0x3102; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan2_Percentage = 0x3104; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan3_Percentage = 0x3106; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Feedrate_Percentage = 0x3108; // 2 Byte Integer (0..100)
+
+// Actual Position
+constexpr uint16_t VP_XPos = 0x3110; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_YPos = 0x3112; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_ZPos = 0x3114; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_EPos = 0x3120; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_PrintProgress_Percentage = 0x3130; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_PrintTime = 0x3140;
+constexpr uint16_t VP_PrintTime_LEN = 32;
+
+constexpr uint16_t VP_PrintAccTime = 0x3160;
+constexpr uint16_t VP_PrintAccTime_LEN = 32;
+
+constexpr uint16_t VP_PrintsTotal = 0x3180;
+constexpr uint16_t VP_PrintsTotal_LEN = 16;
+
+// SDCard File Listing
+constexpr uint16_t VP_SD_FileName_LEN = 32; // LEN is shared for all entries.
+constexpr uint16_t DGUS_SD_FILESPERSCREEN = 5; // FIXME move that info to the display and read it from there.
+constexpr uint16_t VP_SD_FileName0 = 0x3200;
+constexpr uint16_t VP_SD_FileName1 = 0x3220;
+constexpr uint16_t VP_SD_FileName2 = 0x3240;
+constexpr uint16_t VP_SD_FileName3 = 0x3260;
+constexpr uint16_t VP_SD_FileName4 = 0x3280;
+
+constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0; //
+
+constexpr uint16_t VP_SD_Print_Filename = 0x32C0; //
+// Fan status
+constexpr uint16_t VP_FAN0_STATUS = 0x3300;
+constexpr uint16_t VP_FAN1_STATUS = 0x3302;
+//constexpr uint16_t VP_FAN2_STATUS = 0x3304;
+//constexpr uint16_t VP_FAN3_STATUS = 0x3306;
+
+// Heater status
+constexpr uint16_t VP_E0_STATUS = 0x3310;
+//constexpr uint16_t VP_E1_STATUS = 0x3312;
+//constexpr uint16_t VP_E2_STATUS = 0x3314;
+//constexpr uint16_t VP_E3_STATUS = 0x3316;
+//constexpr uint16_t VP_E4_STATUS = 0x3318;
+//constexpr uint16_t VP_E5_STATUS = 0x331A;
+constexpr uint16_t VP_BED_STATUS = 0x331C;
+
+constexpr uint16_t VP_MOVE_OPTION = 0x3400;
+
+// Step per mm
+constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , 2 byte unsigned int , 0~1638.4
+//constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602;
+constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604;
+//constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606;
+constexpr uint16_t VP_Z_STEP_PER_MM = 0x3608;
+//constexpr uint16_t VP_Z2_STEP_PER_MM = 0x360A;
+constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610;
+//constexpr uint16_t VP_E1_STEP_PER_MM = 0x3612;
+//constexpr uint16_t VP_E2_STEP_PER_MM = 0x3614;
+//constexpr uint16_t VP_E3_STEP_PER_MM = 0x3616;
+//constexpr uint16_t VP_E4_STEP_PER_MM = 0x3618;
+//constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A;
+
+// PIDs
+constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E0_PID_I = 0x3702;
+constexpr uint16_t VP_E0_PID_D = 0x3704;
+constexpr uint16_t VP_BED_PID_P = 0x3710;
+constexpr uint16_t VP_BED_PID_I = 0x3712;
+constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+// Wating screen status
+constexpr uint16_t VP_WAITING_STATUS = 0x3800;
+
+// SPs for certain variables...
+// located at 0x5000 and up
+// Not used yet!
+// This can be used e.g to make controls / data display invisible
+constexpr uint16_t SP_T_E0_Is = 0x5000;
+constexpr uint16_t SP_T_E0_Set = 0x5010;
+constexpr uint16_t SP_T_E1_Is = 0x5020;
+constexpr uint16_t SP_T_Bed_Is = 0x5030;
+constexpr uint16_t SP_T_Bed_Set = 0x5040;
diff --git a/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.cpp
new file mode 100644
index 0000000..28e66e5
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.cpp
@@ -0,0 +1,310 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/* DGUS implementation written by coldtobi in 2019 for Marlin */
+
+#include "../../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_ORIGIN)
+
+#include "DGUSDisplayDef.h"
+#include "../DGUSDisplay.h"
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../../module/temperature.h"
+#include "../../../../../module/motion.h"
+#include "../../../../../module/planner.h"
+
+#include "../../../../marlinui.h"
+#include "../../../ui_api.h"
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ uint16_t distanceToMove = 10;
+#endif
+using namespace ExtUI;
+
+const uint16_t VPList_Boot[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ 0x0000
+};
+
+const uint16_t VPList_Main[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded. */
+ 0x0000
+};
+
+const uint16_t VPList_Temp[] PROGMEM = {
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Status[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded */
+ #if HOTENDS >= 1
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HOTENDS >= 2
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ VP_PrintProgress_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_Status2[] PROGMEM = {
+ /* VP_M117, for completeness, but it cannot be auto-uploaded */
+ #if HOTENDS >= 1
+ VP_Flowrate_E0,
+ #endif
+ #if HOTENDS >= 2
+ VP_Flowrate_E1,
+ #endif
+ VP_PrintProgress_Percentage,
+ VP_PrintTime,
+ 0x0000
+};
+
+const uint16_t VPList_ManualMove[] PROGMEM = {
+ VP_XPos, VP_YPos, VP_ZPos,
+ 0x0000
+};
+
+const uint16_t VPList_ManualExtrude[] PROGMEM = {
+ VP_EPos,
+ 0x0000
+};
+
+const uint16_t VPList_FanAndFeedrate[] PROGMEM = {
+ VP_Feedrate_Percentage, VP_Fan0_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_SD_FlowRates[] PROGMEM = {
+ VP_Flowrate_E0, VP_Flowrate_E1,
+ 0x0000
+};
+
+const uint16_t VPList_SDFileList[] PROGMEM = {
+ VP_SD_FileName0, VP_SD_FileName1, VP_SD_FileName2, VP_SD_FileName3, VP_SD_FileName4,
+ 0x0000
+};
+
+const uint16_t VPList_SD_PrintManipulation[] PROGMEM = {
+ VP_PrintProgress_Percentage, VP_PrintTime,
+ 0x0000
+};
+
+const struct VPMapping VPMap[] PROGMEM = {
+ { DGUSLCD_SCREEN_BOOT, VPList_Boot },
+ { DGUSLCD_SCREEN_MAIN, VPList_Main },
+ { DGUSLCD_SCREEN_TEMPERATURE, VPList_Temp },
+ { DGUSLCD_SCREEN_STATUS, VPList_Status },
+ { DGUSLCD_SCREEN_STATUS2, VPList_Status2 },
+ { DGUSLCD_SCREEN_MANUALMOVE, VPList_ManualMove },
+ { DGUSLCD_SCREEN_MANUALEXTRUDE, VPList_ManualExtrude },
+ { DGUSLCD_SCREEN_FANANDFEEDRATE, VPList_FanAndFeedrate },
+ { DGUSLCD_SCREEN_FLOWRATES, VPList_SD_FlowRates },
+ { DGUSLCD_SCREEN_SDPRINTMANIPULATION, VPList_SD_PrintManipulation },
+ { DGUSLCD_SCREEN_SDFILELIST, VPList_SDFileList },
+ { 0 , nullptr } // List is terminated with an nullptr as table entry.
+};
+
+const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
+
+// Helper to define a DGUS_VP_Variable for common use cases.
+#define VPHELPER(VPADR, VPADRVAR, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=sizeof(VPADRVAR), \
+ .set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
+
+// Helper to define a DGUS_VP_Variable when the sizeo of the var cannot be determined automaticalyl (eg. a string)
+#define VPHELPER_STR(VPADR, VPADRVAR, STRLEN, RXFPTR, TXFPTR ) { .VP=VPADR, .memadr=VPADRVAR, .size=STRLEN, \
+ .set_by_display_handler = RXFPTR, .send_to_display_handler = TXFPTR }
+
+const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
+ // Helper to detect touch events
+ VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
+ VPHELPER(VP_SCREENCHANGE_ASK, nullptr, ScreenHandler.ScreenChangeHookIfIdle, nullptr),
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SCREENCHANGE_WHENSD, nullptr, ScreenHandler.ScreenChangeHookIfSD, nullptr),
+ #endif
+ VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
+
+ VPHELPER(VP_TEMP_ALL_OFF, nullptr, &ScreenHandler.HandleAllHeatersOff, nullptr),
+
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_OPTION, &distanceToMove, &ScreenHandler.HandleManualMoveOption, nullptr),
+ #endif
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_X, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, &distanceToMove, &ScreenHandler.HandleManualMove, nullptr),
+ #else
+ VPHELPER(VP_MOVE_X, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, nullptr, &ScreenHandler.HandleManualMove, nullptr),
+ #endif
+
+ VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, &ScreenHandler.HandleMotorLockUnlock, nullptr),
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, &ScreenHandler.HandlePowerLossRecovery, nullptr),
+ #endif
+ VPHELPER(VP_SETTINGS, nullptr, &ScreenHandler.HandleSettings, nullptr),
+
+ { .VP = VP_MARLIN_VERSION, .memadr = (void*)MarlinVersion, .size = VP_MARLIN_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ // M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
+ { .VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler =&ScreenHandler.DGUSLCD_SendStringToDisplay },
+
+ // Temperature Data
+ #if HOTENDS >= 1
+ VPHELPER(VP_T_E0_Is, nullptr, nullptr, SET_VARIABLE(getActualTemp_celsius, E0, long)),
+ VPHELPER(VP_T_E0_Set, nullptr, GET_VARIABLE(setTargetTemp_celsius, E0),
+ SET_VARIABLE(getTargetTemp_celsius, E0)),
+ VPHELPER(VP_Flowrate_E0, nullptr, ScreenHandler.HandleFlowRateChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_EPos, &destination.e, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_MOVE_E0, nullptr, &ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E0_STATUS, &thermalManager.temp_hotend[0].target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(DGUS_PREHEAT_UI)
+ VPHELPER(VP_E0_BED_PREHEAT, nullptr, &ScreenHandler.HandlePreheat, nullptr),
+ #endif
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_E0_PID_P, &thermalManager.temp_hotend[0].pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_I, &thermalManager.temp_hotend[0].pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_D, &thermalManager.temp_hotend[0].pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_E0, nullptr, &ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_E0_FILAMENT_LOAD_UNLOAD, nullptr, &ScreenHandler.HandleFilamentOption, &ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #endif
+ #if HOTENDS >= 2
+ VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E1, nullptr, ScreenHandler.HandleFlowRateChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_MOVE_E1, nullptr, &ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_PID_AUTOTUNE_E1, nullptr, &ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_BED_CONTROL, &thermalManager.temp_bed.target, &ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_BED_STATUS, &thermalManager.temp_bed.target, nullptr, &ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMPBED)
+ VPHELPER(VP_BED_PID_P, &thermalManager.temp_bed.pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_I, &thermalManager.temp_bed.pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_D, &thermalManager.temp_bed.pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ #endif
+ #endif
+
+ // Fan Data
+ #if HAS_FAN
+ #define FAN_VPHELPER(N) \
+ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], ScreenHandler.DGUSLCD_PercentageToUint8, &ScreenHandler.DGUSLCD_SendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], &ScreenHandler.HandleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, &ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
+ REPEAT(FAN_COUNT, FAN_VPHELPER)
+ #endif
+
+ // Feedrate
+ VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly<int16_t>, &ScreenHandler.DGUSLCD_SendWordValueToDisplay ),
+
+ // Position Data
+ VPHELPER(VP_XPos, &current_position.x, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_YPos, &current_position.y, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_ZPos, &current_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+
+ // Print Progress
+ VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay ),
+
+ // Print Time
+ VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay ),
+ #if ENABLED(PRINTCOUNTER)
+ VPHELPER_STR(VP_PrintAccTime, nullptr, VP_PrintAccTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintAccTimeToDisplay ),
+ VPHELPER_STR(VP_PrintsTotal, nullptr, VP_PrintsTotal_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintsTotalToDisplay ),
+ #endif
+
+ VPHELPER(VP_X_STEP_PER_MM, &planner.settings.axis_steps_per_mm[X_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Y_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Y_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Z_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Z_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HOTENDS >= 1
+ VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+ #if HOTENDS >= 2
+ VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+
+ // SDCard File listing.
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
+ VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
+ VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename ),
+ VPHELPER(VP_SD_ResumePauseAbort, nullptr, ScreenHandler.DGUSLCD_SD_ResumePauseAbort, nullptr),
+ VPHELPER(VP_SD_AbortPrintConfirmed, nullptr, ScreenHandler.DGUSLCD_SD_ReallyAbort, nullptr),
+ VPHELPER(VP_SD_Print_Setting, nullptr, ScreenHandler.DGUSLCD_SD_PrintTune, nullptr),
+ #if HAS_BED_PROBE
+ VPHELPER(VP_SD_Print_ProbeOffsetZ, &probe.offset.z, ScreenHandler.HandleProbeOffsetZChanged, &ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
+ #if ENABLED(BABYSTEPPING)
+ VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, nullptr),
+ #endif
+ #endif
+ #endif
+
+ #if ENABLED(DGUS_UI_WAITING)
+ VPHELPER(VP_WAITING_STATUS, nullptr, nullptr, ScreenHandler.DGUSLCD_SendWaitingStatusToDisplay),
+ #endif
+
+ // Messages for the User, shared by the popup and the kill screen. They cant be autouploaded as we do not buffer content.
+ { .VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = &ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+
+ VPHELPER(0, 0, 0, 0) // must be last entry.
+};
+
+#endif // DGUS_LCD_UI_ORIGIN
diff --git a/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.h
new file mode 100644
index 0000000..5c5a315
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.h
@@ -0,0 +1,282 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../DGUSDisplayDef.h"
+
+enum DGUSLCD_Screens : uint8_t {
+ DGUSLCD_SCREEN_BOOT = 0,
+ DGUSLCD_SCREEN_MAIN = 10,
+ DGUSLCD_SCREEN_TEMPERATURE = 20,
+ DGUSLCD_SCREEN_STATUS = 30,
+ DGUSLCD_SCREEN_STATUS2 = 32,
+ DGUSLCD_SCREEN_MANUALMOVE = 40,
+ DGUSLCD_SCREEN_MANUALEXTRUDE=42,
+ DGUSLCD_SCREEN_FANANDFEEDRATE = 44,
+ DGUSLCD_SCREEN_FLOWRATES = 46,
+ DGUSLCD_SCREEN_SDFILELIST = 50,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 52,
+ DGUSLCD_SCREEN_POWER_LOSS = 100,
+ DGUSLCD_SCREEN_PREHEAT=120,
+ DGUSLCD_SCREEN_UTILITY=110,
+ DGUSLCD_SCREEN_FILAMENT_HEATING=146,
+ DGUSLCD_SCREEN_FILAMENT_LOADING=148,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING=158,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 170,
+ DGUSLCD_SCREEN_CONFIRM = 240,
+ DGUSLCD_SCREEN_KILL = 250, ///< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version")
+ DGUSLCD_SCREEN_WAITING = 251,
+ DGUSLCD_SCREEN_POPUP = 252, ///< special target, popup screen will also return this code to say "return to previous screen"
+ DGUSLDC_SCREEN_UNUSED = 255
+};
+
+// Display Memory layout used (T5UID)
+// Except system variables this is arbitrary, just to organize stuff....
+
+// 0x0000 .. 0x0FFF -- System variables and reserved by the display
+// 0x1000 .. 0x1FFF -- Variables to never change location, regardless of UI Version
+// 0x2000 .. 0x2FFF -- Controls (VPs that will trigger some action)
+// 0x3000 .. 0x4FFF -- Marlin Data to be displayed
+// 0x5000 .. -- SPs (if we want to modify display elements, e.g change color or like) -- currently unused
+
+// As there is plenty of space (at least most displays have >8k RAM), we do not pack them too tight,
+// so that we can keep variables nicely together in the address space.
+
+// UI Version always on 0x1000...0x1002 so that the firmware can check this and bail out.
+constexpr uint16_t VP_UI_VERSION_MAJOR = 0x1000; // Major -- incremented when incompatible
+constexpr uint16_t VP_UI_VERSION_MINOR = 0x1001; // Minor -- incremented on new features, but compatible
+constexpr uint16_t VP_UI_VERSION_PATCH = 0x1002; // Patch -- fixed which do not change functionality.
+constexpr uint16_t VP_UI_FLAVOUR = 0x1010; // lets reserve 16 bytes here to determine if UI is suitable for this Marlin. tbd.
+
+// Storage space for the Killscreen messages. 0x1100 - 0x1200 . Reused for the popup.
+constexpr uint16_t VP_MSGSTR1 = 0x1100;
+constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
+constexpr uint16_t VP_MSGSTR2 = 0x1140;
+constexpr uint8_t VP_MSGSTR2_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR3 = 0x1180;
+constexpr uint8_t VP_MSGSTR3_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR4 = 0x11C0;
+constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
+
+// Screenchange request for screens that only make sense when printer is idle.
+// e.g movement is only allowed if printer is not printing.
+// Marlin must confirm by setting the screen manually.
+constexpr uint16_t VP_SCREENCHANGE_ASK = 0x2000;
+constexpr uint16_t VP_SCREENCHANGE = 0x2001; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
+constexpr uint16_t VP_TEMP_ALL_OFF = 0x2002; // Turn all heaters off. Value arbitrary ;)=
+constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x2003; // "Print" Button touched -- go only there if there is an SD Card.
+
+constexpr uint16_t VP_CONFIRMED = 0x2010; // OK on confirm screen.
+
+// Buttons on the SD-Card File listing.
+constexpr uint16_t VP_SD_ScrollEvent = 0x2020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
+constexpr uint16_t VP_SD_FileSelected = 0x2022; // Number of file field selected.
+constexpr uint16_t VP_SD_FileSelectConfirm = 0x2024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
+
+constexpr uint16_t VP_SD_ResumePauseAbort = 0x2026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
+constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x2028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
+constexpr uint16_t VP_SD_Print_Setting = 0x2040;
+constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x2050; // Data: 0 down, 1 up
+
+// Controls for movement (we can't use the incremental / decremental feature of the display at this feature works only with 16 bit values
+// (which would limit us to 655.35mm, which is likely not a problem for common setups, but i don't want to rule out hangprinters support)
+// A word about the coding: The VP will be per axis and the return code will be an signed 16 bit value in 0.01 mm resolution, telling us
+// the relative travel amount t he user wants to do. So eg. if the display sends us VP=2100 with value 100, the user wants us to move X by +1 mm.
+constexpr uint16_t VP_MOVE_X = 0x2100;
+constexpr uint16_t VP_MOVE_Y = 0x2102;
+constexpr uint16_t VP_MOVE_Z = 0x2104;
+constexpr uint16_t VP_MOVE_E0 = 0x2110;
+constexpr uint16_t VP_MOVE_E1 = 0x2112;
+//constexpr uint16_t VP_MOVE_E2 = 0x2114;
+//constexpr uint16_t VP_MOVE_E3 = 0x2116;
+//constexpr uint16_t VP_MOVE_E4 = 0x2118;
+//constexpr uint16_t VP_MOVE_E5 = 0x211A;
+constexpr uint16_t VP_HOME_ALL = 0x2120;
+constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130;
+
+// Power loss recovery
+constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180;
+
+// Fan Control Buttons , switch between "off" and "on"
+constexpr uint16_t VP_FAN0_CONTROL = 0x2200;
+constexpr uint16_t VP_FAN1_CONTROL = 0x2202;
+//constexpr uint16_t VP_FAN2_CONTROL = 0x2204;
+//constexpr uint16_t VP_FAN3_CONTROL = 0x2206;
+
+// Heater Control Buttons , triged between "cool down" and "heat PLA" state
+constexpr uint16_t VP_E0_CONTROL = 0x2210;
+constexpr uint16_t VP_E1_CONTROL = 0x2212;
+//constexpr uint16_t VP_E2_CONTROL = 0x2214;
+//constexpr uint16_t VP_E3_CONTROL = 0x2216;
+//constexpr uint16_t VP_E4_CONTROL = 0x2218;
+//constexpr uint16_t VP_E5_CONTROL = 0x221A;
+constexpr uint16_t VP_BED_CONTROL = 0x221C;
+
+// Preheat
+constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220;
+constexpr uint16_t VP_E1_BED_CONTROL = 0x2222;
+//constexpr uint16_t VP_E2_BED_CONTROL = 0x2224;
+//constexpr uint16_t VP_E3_BED_CONTROL = 0x2226;
+//constexpr uint16_t VP_E4_BED_CONTROL = 0x2228;
+//constexpr uint16_t VP_E5_BED_CONTROL = 0x222A;
+
+// Filament load and unload
+constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300;
+constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2302;
+
+// Settings store , reset
+constexpr uint16_t VP_SETTINGS = 0x2400;
+
+// PID autotune
+constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x2410;
+//constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x2412;
+//constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x2414;
+//constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x2416;
+//constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x2418;
+//constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x241A;
+constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x2420;
+
+// Firmware version on the boot screen.
+constexpr uint16_t VP_MARLIN_VERSION = 0x3000;
+constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed.
+
+// Place for status messages.
+constexpr uint16_t VP_M117 = 0x3020;
+constexpr uint8_t VP_M117_LEN = 0x20;
+
+// Temperatures.
+constexpr uint16_t VP_T_E0_Is = 0x3060; // 4 Byte Integer
+constexpr uint16_t VP_T_E0_Set = 0x3062; // 2 Byte Integer
+constexpr uint16_t VP_T_E1_Is = 0x3064; // 4 Byte Integer
+
+// reserved to support up to 6 Extruders:
+//constexpr uint16_t VP_T_E1_Set = 0x3066; // 2 Byte Integer
+//constexpr uint16_t VP_T_E2_Is = 0x3068; // 4 Byte Integer
+//constexpr uint16_t VP_T_E2_Set = 0x306A; // 2 Byte Integer
+//constexpr uint16_t VP_T_E3_Is = 0x306C; // 4 Byte Integer
+//constexpr uint16_t VP_T_E3_Set = 0x306E; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3070; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3072; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3074; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3076; // 2 Byte Integer
+//constexpr uint16_t VP_T_E5_Is = 0x3078; // 4 Byte Integer
+//constexpr uint16_t VP_T_E5_Set = 0x307A; // 2 Byte Integer
+
+constexpr uint16_t VP_T_Bed_Is = 0x3080; // 4 Byte Integer
+constexpr uint16_t VP_T_Bed_Set = 0x3082; // 2 Byte Integer
+
+constexpr uint16_t VP_Flowrate_E0 = 0x3090; // 2 Byte Integer
+constexpr uint16_t VP_Flowrate_E1 = 0x3092; // 2 Byte Integer
+
+// reserved for up to 6 Extruders:
+//constexpr uint16_t VP_Flowrate_E2 = 0x3094;
+//constexpr uint16_t VP_Flowrate_E3 = 0x3096;
+//constexpr uint16_t VP_Flowrate_E4 = 0x3098;
+//constexpr uint16_t VP_Flowrate_E5 = 0x309A;
+
+constexpr uint16_t VP_Fan0_Percentage = 0x3100; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan1_Percentage = 0x33A2; // 2 Byte Integer (0..100)
+//constexpr uint16_t VP_Fan2_Percentage = 0x33A4; // 2 Byte Integer (0..100)
+//constexpr uint16_t VP_Fan3_Percentage = 0x33A6; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_Feedrate_Percentage = 0x3102; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_PrintProgress_Percentage = 0x3104; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_PrintTime = 0x3106;
+constexpr uint16_t VP_PrintTime_LEN = 10;
+
+constexpr uint16_t VP_PrintAccTime = 0x3160;
+constexpr uint16_t VP_PrintAccTime_LEN = 32;
+
+constexpr uint16_t VP_PrintsTotal = 0x3180;
+constexpr uint16_t VP_PrintsTotal_LEN = 16;
+
+// Actual Position
+constexpr uint16_t VP_XPos = 0x3110; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_YPos = 0x3112; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_ZPos = 0x3114; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_EPos = 0x3120; // 4 Byte Fixed point number; format xxx.yy
+
+// SDCard File Listing
+constexpr uint16_t VP_SD_FileName_LEN = 32; // LEN is shared for all entries.
+constexpr uint16_t DGUS_SD_FILESPERSCREEN = 5; // FIXME move that info to the display and read it from there.
+constexpr uint16_t VP_SD_FileName0 = 0x3200;
+constexpr uint16_t VP_SD_FileName1 = 0x3220;
+constexpr uint16_t VP_SD_FileName2 = 0x3240;
+constexpr uint16_t VP_SD_FileName3 = 0x3260;
+constexpr uint16_t VP_SD_FileName4 = 0x3280;
+
+constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0; //
+constexpr uint16_t VP_SD_Print_Filename = 0x32C0; //
+
+// Fan status
+constexpr uint16_t VP_FAN0_STATUS = 0x3300;
+constexpr uint16_t VP_FAN1_STATUS = 0x3302;
+//constexpr uint16_t VP_FAN2_STATUS = 0x3304;
+//constexpr uint16_t VP_FAN3_STATUS = 0x3306;
+
+// Heater status
+constexpr uint16_t VP_E0_STATUS = 0x3310;
+//constexpr uint16_t VP_E1_STATUS = 0x3312;
+//constexpr uint16_t VP_E2_STATUS = 0x3314;
+//constexpr uint16_t VP_E3_STATUS = 0x3316;
+//constexpr uint16_t VP_E4_STATUS = 0x3318;
+//constexpr uint16_t VP_E5_STATUS = 0x331A;
+constexpr uint16_t VP_BED_STATUS = 0x331C;
+
+constexpr uint16_t VP_MOVE_OPTION = 0x3400;
+
+// Step per mm
+constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , 2 byte unsigned int , 0~1638.4
+//constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602;
+constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604;
+//constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606;
+constexpr uint16_t VP_Z_STEP_PER_MM = 0x3608;
+//constexpr uint16_t VP_Z2_STEP_PER_MM = 0x360A;
+constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610;
+//constexpr uint16_t VP_E1_STEP_PER_MM = 0x3612;
+//constexpr uint16_t VP_E2_STEP_PER_MM = 0x3614;
+//constexpr uint16_t VP_E3_STEP_PER_MM = 0x3616;
+//constexpr uint16_t VP_E4_STEP_PER_MM = 0x3618;
+//constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A;
+
+// PIDs
+constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E0_PID_I = 0x3702;
+constexpr uint16_t VP_E0_PID_D = 0x3704;
+constexpr uint16_t VP_BED_PID_P = 0x3710;
+constexpr uint16_t VP_BED_PID_I = 0x3712;
+constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+// Wating screen status
+constexpr uint16_t VP_WAITING_STATUS = 0x3800;
+
+// SPs for certain variables...
+// located at 0x5000 and up
+// Not used yet!
+// This can be used e.g to make controls / data display invisible
+constexpr uint16_t SP_T_E0_Is = 0x5000;
+constexpr uint16_t SP_T_E0_Set = 0x5010;
+constexpr uint16_t SP_T_E1_Is = 0x5020;
+constexpr uint16_t SP_T_Bed_Is = 0x5030;
+constexpr uint16_t SP_T_Bed_Set = 0x5040;
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp
new file mode 100644
index 0000000..a64c237
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp
@@ -0,0 +1,553 @@
+/*********************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../compat.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#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_MSG("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_MSG("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_MSG("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_MSG("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_MSG("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_MSG("Unable to find media file");
+ return FILE_NOT_FOUND;
+ }
+
+ if (get_media_file_size(slot) != 0xFFFFFFFFUL) {
+ SERIAL_ECHO_MSG("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;
+
+ TERN_(EXTENSIBLE_UI, ExtUI::yield());
+ }
+
+ 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;
+ TERN_(EXTENSIBLE_UI, ExtUI::yield());
+ };
+
+ if (verifyOk) {
+ SERIAL_ECHOLNPGM("DONE");
+ return SUCCESS;
+ }
+ else {
+ SERIAL_ECHOLNPGM("FAIL");
+ return VERIFY_ERROR;
+ }
+ #else
+ return VERIFY_ERROR;
+ #endif // 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;
+ }
+ 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 // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.h
new file mode 100644
index 0000000..eef8cf8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.h
@@ -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: <https://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 = 0x4D524C4E; // 'MRLN'
+ 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);
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp
new file mode 100644
index 0000000..9868492
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp
@@ -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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../compat.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+ #include "media_file_reader.h"
+
+ #if ENABLED(SDSUPPORT)
+ bool MediaFileReader::open(const char* filename) {
+ card.init(SD_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 // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h
new file mode 100644
index 0000000..be393a9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h
@@ -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: <https://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);
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h
new file mode 100644
index 0000000..c01d45e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h
@@ -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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * This following provides compatibility whether compiling
+ * as a part of Marlin or outside it
+ */
+
+#ifdef __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"
+ #undef max
+ #define max(a,b) ((a)>(b)?(a):(b))
+ #undef min
+ #define min(a,b) ((a)<(b)?(a):(b))
+#else
+ namespace UI {
+ static inline uint32_t safe_millis() { return millis(); }
+ static inline void yield() {}
+ };
+#endif
+
+class __FlashStringHelper;
+typedef const __FlashStringHelper *progmem_str;
+extern const char G28_STR[];
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/config.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/config.h
new file mode 100644
index 0000000..76b2315
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/config.h
@@ -0,0 +1,26 @@
+/************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "compat.h"
+
+// Configure this display with options in Configuration_adv.h
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt
new file mode 100644
index 0000000..e600086
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://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 <https://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
+<https://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
+<https://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/README.md b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/README.md
new file mode 100644
index 0000000..6ba985d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/README.md
@@ -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.
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h
new file mode 100644
index 0000000..6bb9208
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h
@@ -0,0 +1,184 @@
+/************
+ * 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: <https://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)
+ * and 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:
+ * https://www.hantronix.com/files/data/1278363262430-3.pdf
+ * https://www.haoyuelectronics.com/Attachment/HY43-LCD/LCD%20DataSheet.pdf
+ * https://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:
+ * https://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)
+ * https://4dsystems.com.au/4dlcd-ft843
+ * Datasheet:
+ * https://4dsystems.com.au/mwdownloads/download/link/id/52/
+ */
+#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
+ * Datasheet https://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 */
+ }
+
+/**
+ * FYSETC Color LCD
+ * https://www.aliexpress.com/item/4000627651757.html
+ * Product information:
+ * https://github.com/FYSETC/TFT81050
+ */
+#elif defined(LCD_FYSETC_TFT81050)
+ #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 TOUCH_UI_FTDI_EVE board specified. To add a new board, modify this file."
+
+#endif
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp
new file mode 100644
index 0000000..1db1175
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp
@@ -0,0 +1,1194 @@
+/****************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_basic.h"
+
+#ifdef FTDI_BASIC
+
+#define MULTIPLE_OF_4(val) ((((val)+3)>>2)<<2)
+
+using namespace FTDI;
+using namespace FTDI::SPI;
+
+void CLCD::enable() {
+ mem_write_8(REG::PCLK, Pclk);
+}
+
+void CLCD::disable() {
+ mem_write_8(REG::PCLK, 0x00);
+}
+
+void CLCD::set_brightness(uint8_t brightness) {
+ mem_write_8(REG::PWM_DUTY, min(128,brightness));
+}
+
+uint8_t CLCD::get_brightness() {
+ return mem_read_8(REG::PWM_DUTY);
+}
+
+void CLCD::turn_on_backlight() {
+ mem_write_8(REG::PWM_DUTY, 128);
+}
+
+void CLCD::FontMetrics::load(const uint8_t font) {
+ static_assert(sizeof(FontMetrics) == 148, "Sizeof font metrics is incorrect");
+ uint32_t rom_fontroot = mem_read_32(MAP::ROM_FONT_ADDR);
+ mem_read_bulk(rom_fontroot + 148 * (font - 16), (uint8_t*) this, 148);
+}
+
+uint16_t CLCD::FontMetrics::get_text_width(const char *str, size_t n) const {
+ uint16_t width = 0;
+ const uint8_t *p = (const uint8_t *) str;
+ for (;;) {
+ const uint8_t val = *p++; n--;
+ if (!val || n == 0) break;
+ width += val < 128 ? char_widths[val] : 0;
+ }
+ return width;
+}
+
+uint16_t CLCD::FontMetrics::get_text_width(progmem_str str, size_t n) const {
+ uint16_t width = 0;
+ const uint8_t *p = (const uint8_t *) str;
+ for (;;) {
+ const uint8_t val = pgm_read_byte(p++); n--;
+ if (!val || n == 0) break;
+ width += val < 128 ? char_widths[val] : 0;
+ }
+ return width;
+}
+
+/************************** HOST COMMAND FUNCTION *********************************/
+
+void CLCD::host_cmd(unsigned char host_command, unsigned char byte2) { // Sends 24-Bit Host Command to LCD
+ if (host_command != FTDI::ACTIVE) {
+ host_command |= 0x40;
+ }
+ spi_ftdi_select();
+ spi_send(host_command);
+ spi_send(byte2);
+ spi_send(0x00);
+ spi_ftdi_deselect();
+}
+
+/************************** MEMORY READ FUNCTIONS *********************************/
+
+void CLCD::spi_read_addr(uint32_t reg_address) {
+ spi_send((reg_address >> 16) & 0x3F); // Address [21:16]
+ spi_send((reg_address >> 8 ) & 0xFF); // Address [15:8]
+ spi_send((reg_address >> 0) & 0xFF); // Address [7:0]
+ spi_send(0x00); // Dummy Byte
+}
+
+// Write 4-Byte Address, Read Multiple Bytes
+void CLCD::mem_read_bulk(uint32_t reg_address, uint8_t *data, uint16_t len) {
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ spi_read_bulk (data, len);
+ spi_ftdi_deselect();
+}
+
+// Write 4-Byte Address, Read 1-Byte Data
+uint8_t CLCD::mem_read_8(uint32_t reg_address) {
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ uint8_t r_data = spi_read_8();
+ spi_ftdi_deselect();
+ return r_data;
+}
+
+// Write 4-Byte Address, Read 2-Bytes Data
+uint16_t CLCD::mem_read_16(uint32_t reg_address) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ uint16_t r_data = spi_read_16();
+ spi_ftdi_deselect();
+ return r_data;
+}
+
+// Write 4-Byte Address, Read 4-Bytes Data
+uint32_t CLCD::mem_read_32(uint32_t reg_address) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ uint32_t r_data = spi_read_32();
+ spi_ftdi_deselect();
+ return r_data;
+}
+
+/************************** MEMORY WRITE FUNCTIONS *********************************/
+
+// Generic operations for transforming a byte, for use with _mem_write_bulk:
+static inline uint8_t reverse_byte(uint8_t a) {
+ return ((a & 0x1) << 7) | ((a & 0x2) << 5) |
+ ((a & 0x4) << 3) | ((a & 0x8) << 1) |
+ ((a & 0x10) >> 1) | ((a & 0x20) >> 3) |
+ ((a & 0x40) >> 5) | ((a & 0x80) >> 7);
+}
+static inline uint8_t xbm_write(const uint8_t *p) {return reverse_byte(pgm_read_byte(p));}
+
+void CLCD::spi_write_addr(uint32_t reg_address) {
+ spi_send((reg_address >> 16) | 0x80); // Address [21:16]
+ spi_send((reg_address >> 8 ) & 0xFF); // Address [15:8]
+ spi_send((reg_address >> 0) & 0xFF); // Address [7:0]
+}
+
+// Write 3-Byte Address, Multiple Bytes, plus padding bytes, from RAM
+void CLCD::mem_write_bulk(uint32_t reg_address, const void *data, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk<ram_write>(data, len, padding);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Multiple Bytes, plus padding bytes, from PROGMEM
+void CLCD::mem_write_bulk(uint32_t reg_address, progmem_str str, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk<pgm_write>(str, len, padding);
+ spi_ftdi_deselect();
+}
+
+ // Write 3-Byte Address, Multiple Bytes, plus padding bytes, from PROGMEM
+void CLCD::mem_write_pgm(uint32_t reg_address, const void *data, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk<pgm_write>(data, len, padding);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Multiple Bytes, plus padding bytes, from PROGMEM, reversing bytes (suitable for loading XBM images)
+void CLCD::mem_write_xbm(uint32_t reg_address, progmem_str data, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk<xbm_write>(data, len, padding);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Write 1-Byte Data
+void CLCD::mem_write_8(uint32_t reg_address, uint8_t data) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_8(data);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Write 2-Bytes Data
+void CLCD::mem_write_16(uint32_t reg_address, uint16_t data) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_16(data);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Write 4-Bytes Data
+void CLCD::mem_write_32(uint32_t reg_address, uint32_t data) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_32(data);
+ spi_ftdi_deselect();
+}
+
+// Fill area of len size with repeated data bytes
+void CLCD::mem_write_fill(uint32_t reg_address, uint8_t data, uint16_t len) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ while (len--) spi_write_8(data);
+ spi_ftdi_deselect();
+}
+
+/******************* FT800/810 Co-processor Commands *********************************/
+
+#if FTDI_API_LEVEL == 800
+uint32_t CLCD::CommandFifo::command_write_ptr = 0xFFFFFFFFul;
+#endif
+
+void CLCD::CommandFifo::cmd(uint32_t cmd32) {
+ write((void*)&cmd32, sizeof(uint32_t));
+}
+
+void CLCD::CommandFifo::cmd(void* data, uint16_t len) {
+ write(data, len);
+}
+
+void CLCD::CommandFifo::bgcolor(uint32_t rgb) {
+ cmd(CMD_BGCOLOR);
+ cmd(rgb);
+}
+
+void CLCD::CommandFifo::fgcolor(uint32_t rgb) {
+ cmd(CMD_FGCOLOR);
+ cmd(rgb);
+}
+
+void CLCD::CommandFifo::gradcolor(uint32_t rgb) {
+ cmd(CMD_GRADCOLOR);
+ cmd(rgb);
+}
+
+// This sends the a text command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::button(int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t option) {
+ struct {
+ int32_t type = CMD_BUTTON;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ int16_t font;
+ uint16_t option;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.font = font;
+ cmd_data.option = option;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+// This sends the a text command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::text(int16_t x, int16_t y, int16_t font, uint16_t options) {
+ struct {
+ int32_t type = CMD_TEXT;
+ int16_t x;
+ int16_t y;
+ int16_t font;
+ uint16_t options;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.font = font;
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+// This sends the a toggle command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::toggle(int16_t x, int16_t y, int16_t w, int16_t font, uint16_t options, bool state) {
+ struct {
+ int32_t type = CMD_TOGGLE;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t font;
+ uint16_t options;
+ uint16_t state;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.font = font;
+ cmd_data.options = options;
+ cmd_data.state = state ? 65535 : 0;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+// This sends the a keys command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::keys(int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t options) {
+ struct {
+ int32_t type = CMD_KEYS;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ int16_t font;
+ uint16_t options;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.font = font;
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::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)
+{
+ struct {
+ int32_t type = CMD_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;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.r = r;
+ cmd_data.options = options;
+ cmd_data.h = h;
+ cmd_data.m = m;
+ cmd_data.s = s;
+ cmd_data.ms = ms;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::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)
+{
+ struct {
+ int32_t type = CMD_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;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.r = r;
+ cmd_data.options = options;
+ cmd_data.major = major;
+ cmd_data.minor = minor;
+ cmd_data.val = val;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::dial(int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t val)
+{
+ struct {
+ int32_t type = CMD_DIAL;
+ int16_t x;
+ int16_t y;
+ int16_t r;
+ uint16_t options;
+ uint16_t val;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.r = r;
+ cmd_data.options = options;
+ cmd_data.val = val;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::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) {
+ struct {
+ int32_t type = CMD_SCROLLBAR;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ uint16_t h;
+ uint16_t options;
+ uint16_t val;
+ uint16_t size;
+ uint16_t range;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.options = options;
+ cmd_data.val = val;
+ cmd_data.size = size;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::progress(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range) {
+ struct {
+ int32_t type = CMD_PROGRESS;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ uint16_t options;
+ uint16_t val;
+ uint16_t range;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.options = options;
+ cmd_data.val = val;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::slider(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range) {
+ struct {
+ int32_t type = CMD_SLIDER;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ uint16_t options;
+ uint16_t val;
+ uint16_t range;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.options = options;
+ cmd_data.val = val;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::gradient(int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1) {
+ struct {
+ int32_t type = CMD_GRADIENT;
+ int16_t x0;
+ int16_t y0;
+ uint32_t rgb0;
+ int16_t x1;
+ int16_t y1;
+ uint32_t rgb1;
+ } cmd_data;
+
+ cmd_data.x0 = x0;
+ cmd_data.y0 = y0;
+ cmd_data.rgb0 = rgb0;
+ cmd_data.x1 = x1;
+ cmd_data.y1 = y1;
+ cmd_data.rgb1 = rgb1;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::number(int16_t x, int16_t y, int16_t font, uint16_t options, int32_t n) {
+ struct {
+ int32_t type = CMD_NUMBER;
+ int16_t x;
+ int16_t y;
+ int16_t font;
+ uint16_t options;
+ int16_t n;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.font = font;
+ cmd_data.options = options;
+ cmd_data.n = n;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memzero(uint32_t ptr, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEMZERO;
+ uint32_t ptr;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memset(uint32_t ptr, uint32_t val, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEMSET;
+ uint32_t ptr;
+ uint32_t val;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.val = val;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memcpy(uint32_t dst, uint32_t src, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEMCPY;
+ uint32_t dst;
+ uint32_t src;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.dst = dst;
+ cmd_data.src = src;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memcrc(uint32_t ptr, uint32_t num, uint32_t result) {
+ struct {
+ uint32_t type = CMD_MEMCRC;
+ uint32_t ptr;
+ uint32_t num;
+ uint32_t result;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.num = num;
+ cmd_data.result = result;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memwrite(uint32_t ptr, uint32_t value) {
+ struct {
+ uint32_t type = CMD_MEMWRITE;
+ uint32_t ptr;
+ uint32_t num;
+ uint32_t value;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.num = 4;
+ cmd_data.value = value;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::append(uint32_t ptr, uint32_t size) {
+ struct {
+ uint32_t type = CMD_APPEND;
+ uint32_t ptr;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::inflate(uint32_t ptr) {
+ struct {
+ uint32_t type = CMD_INFLATE;
+ uint32_t ptr;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::getptr(uint32_t result) {
+ struct {
+ uint32_t type = CMD_GETPTR;
+ uint32_t result;
+ } cmd_data;
+
+ cmd_data.result = result;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::track(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t tag) {
+ struct {
+ uint32_t type = CMD_TRACK;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ int16_t tag;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.tag = tag;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::sketch(int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t ptr, uint16_t format) {
+ struct {
+ uint32_t type = CMD_SKETCH;
+ int16_t x;
+ int16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint32_t ptr;
+ uint16_t format;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.ptr = ptr;
+ cmd_data.format = format;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::snapshot(uint32_t ptr) {
+ struct {
+ uint32_t type = CMD_SNAPSHOT;
+ uint32_t ptr;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::spinner(int16_t x, int16_t y, uint16_t style, uint16_t scale) {
+ struct {
+ uint32_t type = CMD_SPINNER;
+ uint16_t x;
+ uint16_t y;
+ uint16_t style;
+ uint16_t scale;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.style = style;
+ cmd_data.scale = scale;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::loadimage(uint32_t ptr, uint32_t options) {
+ struct {
+ uint32_t type = CMD_LOADIMAGE;
+ uint32_t ptr;
+ uint32_t options;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::getprops(uint32_t ptr, uint32_t width, uint32_t height) {
+ struct {
+ uint32_t type = CMD_GETPROPS;
+ uint32_t ptr;
+ uint32_t width;
+ uint32_t height;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.width = width;
+ cmd_data.height = height;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::scale(int32_t sx, int32_t sy) {
+ struct {
+ uint32_t type = CMD_SCALE;
+ int32_t sx;
+ int32_t sy;
+ } cmd_data;
+
+ cmd_data.sx = sx;
+ cmd_data.sy = sy;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::rotate(int32_t a) {
+ struct {
+ uint32_t type = CMD_ROTATE;
+ int32_t a;
+ } cmd_data;
+
+ cmd_data.a = a;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::translate(int32_t tx, int32_t ty) {
+ struct {
+ uint32_t type = CMD_TRANSLATE;
+ int32_t tx;
+ int32_t ty;
+ } cmd_data;
+
+ cmd_data.tx = tx;
+ cmd_data.ty = ty;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::setbase(uint8_t base) {
+ struct {
+ int32_t type = CMD_SETBASE;
+ uint32_t base;
+ } cmd_data;
+
+ cmd_data.base = base;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::setbitmap(uint32_t addr, uint16_t fmt, uint16_t w, uint16_t h) {
+ struct {
+ uint32_t type = CMD_SETBITMAP;
+ uint32_t addr;
+ uint16_t fmt;
+ uint16_t w;
+ uint16_t h;
+ uint16_t dummy;
+ } cmd_data;
+
+ cmd_data.addr = addr;
+ cmd_data.fmt = fmt;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.dummy = 0;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::snapshot2(uint32_t format, uint32_t ptr, int16_t x, int16_t y, uint16_t w, uint16_t h) {
+ struct {
+ uint32_t type = CMD_SNAPSHOT2;
+ uint32_t format;
+ uint32_t ptr;
+ int16_t x;
+ int16_t y;
+ uint16_t w;
+ uint16_t h;
+ } cmd_data;
+
+ cmd_data.format = format;
+ cmd_data.ptr = ptr;
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::mediafifo(uint32_t ptr, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEDIAFIFO;
+ uint32_t ptr;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::videostart() {
+ cmd( CMD_VIDEOSTART );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::videoframe(uint32_t dst, uint32_t ptr) {
+ struct {
+ uint32_t type = CMD_VIDEOFRAME;
+ uint32_t dst;
+ uint32_t ptr;
+ } cmd_data;
+
+ cmd_data.dst = dst;
+ cmd_data.ptr = ptr;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::playvideo(uint32_t options) {
+ struct {
+ uint32_t type = CMD_PLAYVIDEO;
+ uint32_t options;
+ } cmd_data;
+
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::setrotate(uint8_t rotation) {
+ struct {
+ uint32_t type = CMD_SETROTATE;
+ uint32_t rotation;
+ } cmd_data;
+
+ cmd_data.rotation = rotation;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::romfont(uint8_t font, uint8_t romslot) {
+ struct {
+ uint32_t type = CMD_ROMFONT;
+ uint32_t font;
+ uint32_t romslot;
+ } cmd_data;
+
+ cmd_data.font = font;
+ cmd_data.romslot = romslot;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+/**************************** FT800/810 Co-Processor Command FIFO ****************************/
+
+bool CLCD::CommandFifo::is_processing() {
+ return (mem_read_32(REG::CMD_READ) & 0x0FFF) != (mem_read_32(REG::CMD_WRITE) & 0x0FFF);
+}
+
+bool CLCD::CommandFifo::has_fault() {
+ uint16_t Cmd_Read_Reg = mem_read_32(REG::CMD_READ) & 0x0FFF;
+ return Cmd_Read_Reg == 0x0FFF;
+}
+
+#if FTDI_API_LEVEL == 800
+void CLCD::CommandFifo::start() {
+ if (command_write_ptr == 0xFFFFFFFFul) {
+ command_write_ptr = mem_read_32(REG::CMD_WRITE) & 0x0FFF;
+ }
+}
+
+void CLCD::CommandFifo::execute() {
+ if (command_write_ptr != 0xFFFFFFFFul) {
+ mem_write_32(REG::CMD_WRITE, command_write_ptr);
+ }
+}
+
+void CLCD::CommandFifo::reset() {
+ safe_delay(100);
+ mem_write_32(REG::CPURESET, 0x00000001);
+ mem_write_32(REG::CMD_WRITE, 0x00000000);
+ mem_write_32(REG::CMD_READ, 0x00000000);
+ mem_write_32(REG::CPURESET, 0x00000000);
+ safe_delay(300);
+ command_write_ptr = 0xFFFFFFFFul;
+};
+
+template <class T> bool CLCD::CommandFifo::_write_unaligned(T data, uint16_t len) {
+ const char *ptr = (const char*)data;
+ uint32_t bytes_tail, bytes_head;
+ uint32_t command_read_ptr;
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ if (command_write_ptr == 0xFFFFFFFFul)
+ SERIAL_ECHO_MSG("Attempt to write to FIFO before CommandFifo::Cmd_Start().");
+ #endif
+
+ /* Wait until there is enough space in the circular buffer for the transfer */
+ do {
+ command_read_ptr = mem_read_32(REG::CMD_READ) & 0x0FFF;
+ if (command_read_ptr <= command_write_ptr) {
+ bytes_tail = 4096U - command_write_ptr;
+ bytes_head = command_read_ptr;
+ }
+ else {
+ bytes_tail = command_read_ptr - command_write_ptr;
+ bytes_head = 0;
+ }
+ // Check for faults which can lock up the command processor
+ if (has_fault()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("Fault waiting for space in the command processor");
+ #endif
+ return false;
+ }
+ } while ((bytes_tail + bytes_head) < len);
+
+ /* Write as many bytes as possible following REG::CMD_WRITE */
+ uint16_t bytes_to_write = min(len, bytes_tail);
+ mem_write_bulk (MAP::RAM_CMD + command_write_ptr, T(ptr), bytes_to_write);
+ command_write_ptr += bytes_to_write;
+ ptr += bytes_to_write;
+ len -= bytes_to_write;
+
+ if (len > 0) {
+ /* Write remaining bytes at start of circular buffer */
+ mem_write_bulk (MAP::RAM_CMD, T(ptr), len);
+ command_write_ptr = len;
+ }
+
+ if (command_write_ptr == 4096U) {
+ command_write_ptr = 0;
+ }
+ return true;
+}
+
+// Writes len bytes into the FIFO, if len is not
+// divisible by four, zero bytes will be written
+// to align to the boundary.
+
+template <class T> bool CLCD::CommandFifo::write(T data, uint16_t len) {
+ const uint8_t padding = MULTIPLE_OF_4(len) - len;
+
+ uint8_t pad_bytes[] = {0, 0, 0, 0};
+ return _write_unaligned(data, len) &&
+ _write_unaligned(pad_bytes, padding);
+}
+#else
+void CLCD::CommandFifo::start() {
+}
+
+void CLCD::CommandFifo::execute() {
+}
+
+void CLCD::CommandFifo::reset() {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("Resetting command processor");
+ #endif
+ safe_delay(100);
+ mem_write_32(REG::CPURESET, 0x00000001);
+ mem_write_32(REG::CMD_WRITE, 0x00000000);
+ mem_write_32(REG::CMD_READ, 0x00000000);
+ mem_write_32(REG::CPURESET, 0x00000000);
+ safe_delay(300);
+};
+
+// Writes len bytes into the FIFO, if len is not
+// divisible by four, zero bytes will be written
+// to align to the boundary.
+
+template <class T> bool CLCD::CommandFifo::write(T data, uint16_t len) {
+ const uint8_t padding = MULTIPLE_OF_4(len) - len;
+
+ if (has_fault()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("Faulted... ignoring write.");
+ #endif
+ return false;
+ }
+ // The FT810 provides a special register that can be used
+ // for writing data without us having to do our own FIFO
+ // management.
+ uint16_t Command_Space = mem_read_32(REG::CMDB_SPACE) & 0x0FFF;
+ if (Command_Space < (len + padding)) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPAIR("Waiting for ", len + padding);
+ SERIAL_ECHOLNPAIR(" bytes in command queue, now free: ", Command_Space);
+ #endif
+ do {
+ Command_Space = mem_read_32(REG::CMDB_SPACE) & 0x0FFF;
+ if (has_fault()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("... fault");
+ #endif
+ return false;
+ }
+ } while (Command_Space < len + padding);
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("... done");
+ #endif
+ }
+ mem_write_bulk(REG::CMDB_WRITE, data, len, padding);
+ return true;
+}
+#endif
+
+template bool CLCD::CommandFifo::write(const void*, uint16_t);
+template bool CLCD::CommandFifo::write(progmem_str, uint16_t);
+
+// CO_PROCESSOR COMMANDS
+
+void CLCD::CommandFifo::str(const char * data) {
+ write(data, strlen(data)+1);
+}
+
+void CLCD::CommandFifo::str(progmem_str data) {
+ write(data, strlen_P((const char*)data)+1);
+}
+
+/******************* LCD INITIALIZATION ************************/
+
+void CLCD::init() {
+ spi_init(); // Set Up I/O Lines for SPI and FT800/810 Control
+ ftdi_reset(); // Power down/up the FT8xx with the apropriate delays
+
+ host_cmd(Use_Crystal ? CLKEXT : CLKINT, 0);
+ host_cmd(FTDI::ACTIVE, 0); // Activate the System Clock
+
+ delay(40); // FTDI/BRT recommendation: no SPI traffic during startup. EVE needs at the very least 45ms to start, so leave her alone for a little while.
+
+ /* read the device-id until it returns 0x7C or times out, should take less than 150ms */
+ uint8_t counter;
+ for (counter = 0; counter < 250; counter++) {
+ uint8_t device_id = mem_read_8(REG::ID); // Read Device ID, Should Be 0x7C;
+ if (device_id == 0x7C) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("FTDI chip initialized ");
+ #endif
+ break;
+ }
+ else
+ delay(1);
+
+ if (counter == 249) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOLNPAIR("Timeout waiting for device ID, should be 124, got ", device_id);
+ #endif
+ }
+ }
+
+ /* make sure that all units are in working conditions, usually the touch-controller needs a little more time */
+ for (counter = 0; counter < 100; counter++) {
+ uint8_t reset_status = mem_read_8(REG::CPURESET) & 0x03;
+ if (reset_status == 0x00) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("FTDI chip all units running ");
+ #endif
+ break;
+ }
+ else
+ delay(1);
+
+ if (ENABLED(TOUCH_UI_DEBUG) && counter == 99) {
+ SERIAL_ECHO_START();
+ SERIAL_ECHOLNPAIR("Timeout waiting for reset status. Should be 0x00, got ", reset_status);
+ }
+ }
+
+ mem_write_8(REG::PWM_DUTY, 0); // turn off Backlight, Frequency already is set to 250Hz default
+
+ /* Configure the FT8xx Registers */
+ mem_write_16(REG::HCYCLE, FTDI::Hcycle);
+ mem_write_16(REG::HOFFSET, FTDI::Hoffset);
+ mem_write_16(REG::HSYNC0, FTDI::Hsync0);
+ mem_write_16(REG::HSYNC1, FTDI::Hsync1);
+ mem_write_16(REG::VCYCLE, FTDI::Vcycle);
+ mem_write_16(REG::VOFFSET, FTDI::Voffset);
+ mem_write_16(REG::VSYNC0, FTDI::Vsync0);
+ mem_write_16(REG::VSYNC1, FTDI::Vsync1);
+ mem_write_16(REG::HSIZE, FTDI::Hsize);
+ mem_write_16(REG::VSIZE, FTDI::Vsize);
+ mem_write_8(REG::SWIZZLE, FTDI::Swizzle);
+ mem_write_8(REG::PCLK_POL, FTDI::Pclkpol);
+ mem_write_8(REG::CSPREAD, FTDI::CSpread);
+
+ /* write a basic display-list to get things started */
+ mem_write_32(MAP::RAM_DL, DL::CLEAR_COLOR_RGB);
+ mem_write_32(MAP::RAM_DL + 4, (DL::CLEAR | 0x07)); /* clear color, stencil and tag buffer */
+ mem_write_32(MAP::RAM_DL + 8, DL::DL_DISPLAY); /* end of display list */
+
+ mem_write_8(REG::DLSWAP, 0x02); // activate display list, Bad Magic Cookie 2 = switch to new list after current frame is scanned out
+
+ //mem_write_8(REG::TOUCH_MODE, 0x03); // Configure the Touch Screen, Bad Magic Cookie, 3 = CONTINUOUS = Reset Default
+ //mem_write_8(REG::TOUCH_ADC_MODE, 0x01); // Bad Magic Cookie, 1 = single touch = Reset Default
+ //mem_write_8(REG::TOUCH_OVERSAMPLE, 0x0F); // Reset Default = 7 - why 15?
+ mem_write_16(REG::TOUCH_RZTHRESH, touch_threshold); /* setup touch sensitivity */
+ mem_write_8(REG::VOL_SOUND, 0x00); // Turn Synthesizer Volume Off
+
+ /* turn on the display by setting DISP high */
+ /* turn on the Audio Amplifier by setting GPIO_1 high for the select few modules supporting this */
+ /* no need to use GPIOX here since DISP/GPIO_0 and GPIO_1 are on REG::GPIO for FT81x as well */
+ if (GPIO_1_Audio_Shutdown) {
+ mem_write_8(REG::GPIO_DIR, GPIO_DISP | GPIO_GP1);
+ mem_write_8(REG::GPIO, GPIO_DISP | GPIO_GP1);
+ } else if (GPIO_0_Audio_Enable) {
+ mem_write_8(REG::GPIO_DIR, GPIO_DISP | GPIO_GP0);
+ mem_write_8(REG::GPIO, GPIO_DISP | GPIO_GP0);
+ }
+ else {
+ mem_write_8(REG::GPIO, GPIO_DISP); /* REG::GPIO_DIR is set to output for GPIO_DISP by default */
+ }
+
+ mem_write_8(REG::PCLK, Pclk); // Turns on Clock by setting PCLK Register to the value necessary for the module
+
+ mem_write_16(REG::PWM_HZ, 0x00FA);
+
+ // Turning off dithering seems to help prevent horizontal line artifacts on certain colors
+ mem_write_8(REG::DITHER, 0);
+
+ default_touch_transform();
+ default_display_orientation();
+}
+
+void CLCD::default_touch_transform() {
+ // Set Initial Values for Touch Transform Registers
+ mem_write_32(REG::ROTATE, 0);
+ mem_write_32(REG::TOUCH_TRANSFORM_A, FTDI::default_transform_a);
+ mem_write_32(REG::TOUCH_TRANSFORM_B, FTDI::default_transform_b);
+ mem_write_32(REG::TOUCH_TRANSFORM_C, FTDI::default_transform_c);
+ mem_write_32(REG::TOUCH_TRANSFORM_D, FTDI::default_transform_d);
+ mem_write_32(REG::TOUCH_TRANSFORM_E, FTDI::default_transform_e);
+ mem_write_32(REG::TOUCH_TRANSFORM_F, FTDI::default_transform_f);
+}
+
+void CLCD::default_display_orientation() {
+ #if FTDI_API_LEVEL >= 810
+ // Set the initial display orientation. On the FT810, we use the command
+ // processor to do this since it will also update the transform matrices.
+ CommandFifo cmd;
+ cmd.setrotate(
+ ENABLED(TOUCH_UI_MIRRORED) * 4
+ + ENABLED(TOUCH_UI_PORTRAIT) * 2
+ + ENABLED(TOUCH_UI_INVERTED) * 1
+ );
+ cmd.execute();
+ #elif ANY(TOUCH_UI_PORTRAIT, TOUCH_UI_MIRRORED)
+ #error "PORTRAIT or MIRRORED orientation not supported on the FT800."
+ #elif ENABLED(TOUCH_UI_INVERTED)
+ mem_write_32(REG::ROTATE, 1);
+ #endif
+}
+
+#endif // FTDI_BASIC
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h
new file mode 100644
index 0000000..376beae
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h
@@ -0,0 +1,262 @@
+/****************
+ * 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: <https://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_fill (uint32_t reg_address, uint8_t w_data, uint16_t len);
+ 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();
+ static void default_touch_transform();
+ static void default_display_orientation();
+ static void turn_on_backlight();
+ static void enable();
+ static void disable();
+ static void set_brightness (uint8_t brightness);
+ static uint8_t get_brightness();
+ static void host_cmd (unsigned char host_command, unsigned char byte2);
+ static uint32_t dl_size() {return CLCD::mem_read_32(REG::CMD_DL) & 0x1FFF;}
+
+ 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() {}
+ 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(progmem_str 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();
+
+ public:
+ template <class T> bool write(T data, uint16_t len);
+
+ public:
+ CommandFifo() {start();}
+
+ static void reset();
+ static bool is_processing();
+ static bool has_fault();
+
+ void execute();
+
+ 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);
+ void romfont (uint8_t font, uint8_t romslot);
+ #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);
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h
new file mode 100644
index 0000000..507e251
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h
@@ -0,0 +1,414 @@
+/***************
+ * 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: <https://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_SETFONT2 = 0xFFFFFF3B;
+ constexpr uint32_t CMD_SETSCRATCH = 0xFFFFFF3C;
+ constexpr uint32_t CMD_ROMFONT = 0xFFFFFF3F;
+ constexpr uint32_t CMD_VIDEOSTART = 0xFFFFFF40;
+ constexpr uint32_t CMD_VIDEOFRAME = 0xFFFFFF41;
+ constexpr uint32_t CMD_SETBITMAP = 0xFFFFFF43;
+}
+
+namespace FTDI {
+ enum effect_t : unsigned char {
+ 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 : unsigned char {
+ 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,
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h
new file mode 100644
index 0000000..99a9e0e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h
@@ -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);}
+ 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
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h
new file mode 100644
index 0000000..47cd698
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h
@@ -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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../compat.h"
+
+#ifndef __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
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h
new file mode 100644
index 0000000..2605370
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h
@@ -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: <https://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)
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h
new file mode 100644
index 0000000..e57d11c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h
@@ -0,0 +1,187 @@
+/*********************
+ * 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: <https://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 *
+ * *
+ * 0x201EE0 0x2029DC 2812 B ROM_FONT_ROOT ROM font table *
+ * *
+ * 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
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h
new file mode 100644
index 0000000..5b29816
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h
@@ -0,0 +1,127 @@
+/*****************
+ * 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: <https://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");
+
+#if ENABLED(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 TOUCH_UI_FTDI_EVE display resolution specified. To add a display resolution, modify 'ftdi_eve_resolutions.h'."
+#endif
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp
new file mode 100644
index 0000000..006cbe8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp
@@ -0,0 +1,175 @@
+/***********
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_basic.h"
+
+#ifdef FTDI_BASIC
+
+/********************************* SPI Functions *********************************/
+
+namespace FTDI {
+
+ #ifndef CLCD_USE_SOFT_SPI
+ #ifdef CLCD_SPI_BUS
+ SPIClass EVE_SPI(CLCD_SPI_BUS);
+ #endif
+ #ifndef CLCD_HW_SPI_SPEED
+ #define CLCD_HW_SPI_SPEED 8000000 >> SD_SPI_SPEED
+ #endif
+ SPISettings SPI::spi_settings(CLCD_HW_SPI_SPEED, MSBFIRST, SPI_MODE0);
+ #endif
+
+ void SPI::spi_init() {
+ 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 CLCD_SPI_EXTRA_CS
+ SET_OUTPUT(CLCD_SPI_EXTRA_CS);
+ WRITE(CLCD_SPI_EXTRA_CS, 1);
+ #endif
+
+ #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_OBJ.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
+ WRITE(CLCD_SOFT_SPI_MOSI, (spiOutByte & spiIndex) ? 1 : 0); // Output MOSI Bit
+ WRITE(CLCD_SOFT_SPI_SCLK, 1); // Pulse Clock
+ if (READ(CLCD_SOFT_SPI_MISO)) spiInByte |= spiIndex; // MISO changes on the falling edge of clock, so sample it before
+ WRITE(CLCD_SOFT_SPI_SCLK, 0);
+ spiIndex >>= 1;
+ }
+ interrupts();
+ return spiInByte;
+ }
+ #endif
+
+ #ifdef CLCD_USE_SOFT_SPI
+ void SPI::_soft_spi_send(uint8_t spiOutByte) {
+ uint8_t k, spiIndex = 0x80;
+
+ noInterrupts();
+ for (k = 0; k < 8; k++) { // Output each bit of spiOutByte
+ WRITE(CLCD_SOFT_SPI_MOSI, (spiOutByte & spiIndex) ? 1 : 0); // Output MOSI Bit
+ 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;
+ while (len--) *p++ = spi_recv();
+ }
+
+ 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() {
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.beginTransaction(spi_settings);
+ #endif
+ WRITE(CLCD_SPI_CS, 0);
+ #ifdef CLCD_SPI_EXTRA_CS
+ WRITE(CLCD_SPI_EXTRA_CS, 0);
+ #endif
+ delayMicroseconds(1);
+ }
+
+ // CLCD SPI - Chip Deselect
+ void SPI::spi_ftdi_deselect() {
+ WRITE(CLCD_SPI_CS, 1);
+ #ifdef CLCD_SPI_EXTRA_CS
+ WRITE(CLCD_SPI_EXTRA_CS, 1);
+ #endif
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.endTransaction();
+ #endif
+ }
+
+ #ifdef SPI_FLASH_SS
+ // Serial SPI Flash SPI - Chip Select
+ void SPI::spi_flash_select() {
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.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);
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.endTransaction();
+ #endif
+ }
+ #endif
+
+ // Not really a SPI signal...
+ void SPI::ftdi_reset() {
+ 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() {
+ #ifdef CLCD_AUX_0
+ WRITE(CLCD_AUX_0, 1);
+ delayMicroseconds(10);
+ WRITE(CLCD_AUX_0, 0);
+ #endif
+ }
+}
+#endif // FTDI_BASIC
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h
new file mode 100644
index 0000000..e3a23d7
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h
@@ -0,0 +1,136 @@
+/*********
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#ifndef CLCD_USE_SOFT_SPI
+ #include <SPI.h>
+#endif
+
+namespace FTDI {
+
+ #if !defined(CLCD_SPI_BUS) || defined(CLCD_USE_SOFT_SPI)
+ #define SPI_OBJ ::SPI
+ #else
+ extern SPIClass EVE_SPI;
+ #define SPI_OBJ EVE_SPI
+ #endif
+
+ namespace SPI {
+ #ifndef 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_OBJ.transfer(0x00);
+ #endif
+ };
+
+ inline void spi_send (uint8_t val) {
+ #ifdef CLCD_USE_SOFT_SPI
+ _soft_spi_send(val);
+ #else
+ SPI_OBJ.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 test_pulse();
+ }
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h
new file mode 100644
index 0000000..9be7882
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h
@@ -0,0 +1,278 @@
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../config.h"
+
+#ifdef __MARLIN_FIRMWARE__
+
+ // Marlin will define the I/O functions for us
+ #if ENABLED(TOUCH_UI_FTDI_EVE)
+ #define FTDI_BASIC
+ #define FTDI_EXTENDED
+ #endif
+
+#else // !__MARLIN_FIRMWARE__
+
+ #include <Arduino.h>
+
+ #ifndef 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) do{ fast_io::pin::set_input(); fast_io::pin::set_high(); }while(0)
+ #define SET_INPUT_PULLDOWN SET_INPUT
+ #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_ECHO_MSG(str) Serial.println(str)
+ #define SERIAL_ECHOLNPAIR(str, val) do{ Serial.print(F(str)); Serial.println(val); }while(0)
+ #define SERIAL_ECHOPAIR(str, val) do{ Serial.print(F(str)); Serial.print(val); }while(0)
+
+ #define safe_delay delay
+
+ // Define macros for compatibility
+
+ // Use NUM_ARGS(__VA_ARGS__) to get the number of variadic arguments
+ #define _NUM_ARGS(_,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
+ #define NUM_ARGS(V...) _NUM_ARGS(0,V,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
+
+ #define _CAT(a,V...) a##V
+ #define CAT(a,V...) _CAT(a,V)
+
+ #define FIRST(a,...) a
+ #define SECOND(a,b,...) b
+ #define THIRD(a,b,c,...) c
+
+ #define IS_PROBE(V...) SECOND(V, 0) // Get the second item passed, or 0
+ #define PROBE() ~, 1 // Second item will be 1 if this is passed
+ #define _NOT_0 PROBE()
+ #define NOT(x) IS_PROBE(_CAT(_NOT_, x)) // NOT('0') gets '1'. Anything else gets '0'.
+ #define _BOOL(x) NOT(NOT(x)) // NOT('0') gets '0'. Anything else gets '1'.
+
+ #define _DO_1(W,C,A) (_##W##_1(A))
+ #define _DO_2(W,C,A,B) (_##W##_1(A) C _##W##_1(B))
+ #define _DO_3(W,C,A,V...) (_##W##_1(A) C _DO_2(W,C,V))
+ #define _DO_4(W,C,A,V...) (_##W##_1(A) C _DO_3(W,C,V))
+ #define _DO_5(W,C,A,V...) (_##W##_1(A) C _DO_4(W,C,V))
+ #define _DO_6(W,C,A,V...) (_##W##_1(A) C _DO_5(W,C,V))
+ #define _DO_7(W,C,A,V...) (_##W##_1(A) C _DO_6(W,C,V))
+ #define _DO_8(W,C,A,V...) (_##W##_1(A) C _DO_7(W,C,V))
+ #define _DO_9(W,C,A,V...) (_##W##_1(A) C _DO_8(W,C,V))
+ #define _DO_10(W,C,A,V...) (_##W##_1(A) C _DO_9(W,C,V))
+ #define _DO_11(W,C,A,V...) (_##W##_1(A) C _DO_10(W,C,V))
+ #define _DO_12(W,C,A,V...) (_##W##_1(A) C _DO_11(W,C,V))
+ #define __DO_N(W,C,N,V...) _DO_##N(W,C,V)
+ #define _DO_N(W,C,N,V...) __DO_N(W,C,N,V)
+ #define DO(W,C,V...) _DO_N(W,C,NUM_ARGS(V),V)
+
+ #define _ISENA_ ~,1
+ #define _ISENA_1 ~,1
+ #define _ISENA_0x1 ~,1
+ #define _ISENA_true ~,1
+ #define _ISENA(V...) IS_PROBE(V)
+ #define _ENA_1(O) _ISENA(CAT(_IS,CAT(ENA_, O)))
+ #define _DIS_1(O) NOT(_ENA_1(O))
+ #define ENABLED(V...) DO(ENA,&&,V)
+ #define DISABLED(V...) DO(DIS,&&,V)
+
+ #define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION converted to '0' or '1'
+ #define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION converted to A or '0'
+ #define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION converted to A or '1'
+ #define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION converted to A or '<nul>'
+ #define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1'
+ #define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1'
+ #define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B.
+
+ #define IF_ENABLED TERN_
+ #define IF_DISABLED(O,A) _TERN(_ENA_1(O),,A)
+
+ #define ANY(V...) !DISABLED(V)
+ #define NONE(V...) DISABLED(V)
+ #define ALL(V...) ENABLED(V)
+ #define BOTH(V1,V2) ALL(V1,V2)
+ #define EITHER(V1,V2) ANY(V1,V2)
+
+ // 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__
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h
new file mode 100644
index 0000000..7326070
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h
@@ -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: <https://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);}
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp
new file mode 100644
index 0000000..e324cb9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp
@@ -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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+CommandProcessor::btn_style_func_t *CommandProcessor::_btn_style_callback = CommandProcessor::default_button_style_func;
+bool CommandProcessor::is_tracking = false;
+
+#endif // FTDI_EXTENDED
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h
new file mode 100644
index 0000000..da51ee6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h
@@ -0,0 +1,437 @@
+/***********************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+typedef struct {
+ uint32_t bg;
+ uint32_t grad;
+ uint32_t fg;
+ uint32_t rgb;
+} btn_colors;
+
+// Disable TOUCH_UI_FIT_TEXT on a case-by-case basis
+namespace FTDI {
+ constexpr uint16_t OPT_NOFIT = OPT_NOTICKS;
+}
+
+/**************************** 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 - th) / 2;
+ w -= tracker ? th * 5.0 : th * 2;
+ h = th;
+ }
+ else {
+ x += (w - 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=false) {
+ 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;}
+ inline CommandProcessor& romfont(uint8_t font, uint8_t slot) {CLCD::CommandFifo::romfont(font, slot); 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 - widget_h) / 2 + fudge_y, w - h, _font, options, state);
+ CLCD::CommandFifo::str(text);
+ return *this;
+ }
+
+ CommandProcessor& toggle2(int16_t x, int16_t y, int16_t w, int16_t h, progmem_str no, progmem_str yes, bool state, uint16_t options = FTDI::OPT_3D) {
+ char text[strlen_P((const char *)no) + strlen_P((const char *)yes) + 2];
+ strcpy_P(text, (const char *)no);
+ strcat(text, "\xFF");
+ strcat_P(text, (const char *)yes);
+ return toggle(x, y, w, h, text, state, options);
+ }
+
+ // 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;
+ }
+
+ void apply_text_alignment(int16_t &x, int16_t &y, int16_t w, int16_t h, uint16_t options) {
+ using namespace FTDI;
+ x += ((options & OPT_CENTERX) ? w/2 : ((options & OPT_RIGHTX) ? w : 0));
+ y += ((options & OPT_CENTERY) ? h/2 : h);
+ }
+
+ // Reduce font size until text fits the enclosing box.
+ template<typename T>
+ int8_t apply_fit_text(int16_t w, int16_t h, T text) {
+ using namespace FTDI;
+ int8_t font = _font;
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ const bool is_utf8 = has_utf8_chars(text);
+ #endif
+ for (;font > 26;) {
+ int16_t width, height;
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (is_utf8) {
+ width = get_utf8_text_width(text, font_size_t::from_romfont(font));
+ height = font_size_t::from_romfont(font).get_height();
+ }
+ else
+ #endif
+ {
+ CLCD::FontMetrics fm(font);
+ width = fm.get_text_width(text);
+ height = fm.height;
+ }
+ if (width < w && height < h) break;
+ font--;
+ }
+ return font;
+ }
+
+ 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;
+ apply_text_alignment(x, y, w, h, options);
+ CLCD::CommandFifo::number(x, y, _font, options, n);
+ return *this;
+ }
+
+ template<typename T>
+ uint16_t text_width(T text) {
+ using namespace FTDI;
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(text))
+ return get_utf8_text_width(text, font_size_t::from_romfont(_font));
+ #endif
+ CLCD::FontMetrics fm(_font);
+ return fm.get_text_width(text);
+ }
+
+ template<typename T>
+ 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;
+ apply_text_alignment(x, y, w, h, options);
+ #ifdef TOUCH_UI_FIT_TEXT
+ const int8_t font = (options & OPT_NOFIT) ? _font : apply_fit_text(w, h, text);
+ #else
+ const int8_t font = _font;
+ #endif
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(text))
+ draw_utf8_text(*this, x, y, text, font_size_t::from_romfont(font), options);
+ else
+ #endif
+ {
+ CLCD::CommandFifo::text(x, y, 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);
+ #ifdef TOUCH_UI_FIT_TEXT
+ const int8_t font = (options & OPT_NOFIT) ? _font : apply_fit_text(w, h, text);
+ #else
+ const int8_t font = _font;
+ #endif
+ CLCD::CommandFifo::button(x, y, w, h, font, options);
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(text)) {
+ CLCD::CommandFifo::str(F(""));
+ apply_text_alignment(x, y, w, h, OPT_CENTER);
+ if (!(options & FTDI::OPT_FLAT)) {
+ // Reproduce the black "shadow" the FTDI adds to the button label
+ CLCD::CommandFifo::cmd(SAVE_CONTEXT());
+ CLCD::CommandFifo::cmd(COLOR_RGB(0x00000));
+ draw_utf8_text(*this, x-1, y-1, text, font_size_t::from_romfont(font), OPT_CENTER);
+ CLCD::CommandFifo::cmd(RESTORE_CONTEXT());
+ }
+ // Draw the button label
+ draw_utf8_text(*this, x, y, text, font_size_t::from_romfont(font), OPT_CENTER);
+ }
+ else
+ #endif
+ 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;
+ }
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp
new file mode 100644
index 0000000..a13c362
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp
@@ -0,0 +1,180 @@
+/****************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(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, size and used bytes 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
+ * slot0_used 4
+ * slot1_addr 4
+ * slot1_size 4
+ * slot1_used 4
+ * ...
+ * slotN_addr 4
+ * slotN_size 4
+ * slotN_used 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 * 12
+
+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, 0);
+}
+
+bool DLCache::has_data() {
+ return dl_slot_size != 0;
+}
+
+bool DLCache::wait_until_idle() {
+ const unsigned long startTime = millis();
+ do {
+ if ((millis() - startTime) > 250) {
+ SERIAL_ECHO_MSG("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 min_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 min_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
+ const uint32_t dl_size = CLCD::dl_size();
+
+ if (dl_slot_addr == 0) {
+ // If we are allocating new space...
+ dl_slot_addr = CLCD::mem_read_32(DL_FREE_ADDR);
+ dl_slot_size = max(dl_size, min_bytes);
+
+ const uint32_t free_space = MAP::RAM_G_SIZE - dl_slot_addr;
+ if (dl_slot_size <= free_space) {
+ CLCD::mem_write_32(DL_FREE_ADDR, dl_slot_addr + dl_slot_size);
+ }
+ else {
+ dl_slot_addr = 0;
+ dl_slot_size = 0;
+ dl_slot_used = 0;
+ }
+ }
+
+ if (dl_size > dl_slot_size) {
+ // Not enough memory to cache the display list.
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPAIR ("Not enough space in GRAM to cache display list, free space: ", dl_slot_size);
+ SERIAL_ECHOLNPAIR(" Required: ", dl_size);
+ #endif
+ dl_slot_used = 0;
+ save_slot();
+ return false;
+ }
+ else {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPAIR ("Saving DL to RAMG cache, bytes: ", dl_slot_used);
+ SERIAL_ECHOLNPAIR(" Free space: ", dl_slot_size);
+ #endif
+ dl_slot_used = dl_size;
+ save_slot();
+ cmd.memcpy(dl_slot_addr, MAP::RAM_DL, dl_slot_used);
+ cmd.execute();
+ return true;
+ }
+}
+
+void DLCache::save_slot(uint8_t indx, uint32_t addr, uint16_t size, uint16_t used) {
+ CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 0, addr);
+ CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 4, size);
+ CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 8, used);
+}
+
+void DLCache::load_slot(uint8_t indx, uint32_t &addr, uint16_t &size, uint16_t &used) {
+ addr = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 0);
+ size = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 4);
+ used = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 8);
+}
+
+void DLCache::append() {
+ CLCD::CommandFifo cmd;
+ cmd.append(dl_slot_addr, dl_slot_used);
+ #if ENABLED(TOUCH_UI_DEBUG)
+ cmd.execute();
+ wait_until_idle();
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPAIR ("Appending to DL from RAMG cache, bytes: ", dl_slot_used);
+ SERIAL_ECHOLNPAIR(" REG_CMD_DL: ", CLCD::mem_read_32(REG::CMD_DL));
+ #endif
+}
+
+#endif // FTDI_EXTENDED
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h
new file mode 100644
index 0000000..73b4b0b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h
@@ -0,0 +1,70 @@
+/**************
+ * 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: <https://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:
+ *
+ * DLCache dlcache(UNIQUE_ID);
+ *
+ * if (dlcache.hasData())
+ * dlcache.append();
+ * else
+ * dlcache.store(); // Add stuff to the DL
+ */
+class DLCache {
+ private:
+ typedef FTDI::ftdi_registers REG;
+ typedef FTDI::ftdi_memory_map MAP;
+
+ uint8_t dl_slot_indx;
+ uint32_t dl_slot_addr;
+ uint16_t dl_slot_size;
+ uint16_t dl_slot_used;
+
+ void load_slot() {load_slot(dl_slot_indx, dl_slot_addr, dl_slot_size, dl_slot_used);}
+ void save_slot() {save_slot(dl_slot_indx, dl_slot_addr, dl_slot_size, dl_slot_used);}
+
+ static void load_slot(uint8_t indx, uint32_t &addr, uint16_t &size, uint16_t &used);
+ static void save_slot(uint8_t indx, uint32_t addr, uint16_t size, uint16_t used);
+
+ bool wait_until_idle();
+
+ public:
+ static void init();
+
+ DLCache(uint8_t slot) {
+ dl_slot_indx = slot;
+ load_slot();
+ }
+
+ bool has_data();
+ bool store(uint32_t min_bytes = 0);
+ void append();
+};
+
+#define DL_CACHE_SLOTS 250
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp
new file mode 100644
index 0000000..6c0392c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp
@@ -0,0 +1,228 @@
+/******************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(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) {
+ #if ENABLED(TOUCH_UI_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);
+ }
+
+ // 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 = (lastScreen != current_screen.getScreen());
+ }
+ 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)) {
+ if (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);
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOLNPAIR("Touch end: ", pressed_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
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h
new file mode 100644
index 0000000..c5f0829
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h
@@ -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: <https://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();
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h
new file mode 100644
index 0000000..fd84c79
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h
@@ -0,0 +1,52 @@
+/*******************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../compat.h"
+#include "../basic/ftdi_basic.h"
+
+#ifndef __MARLIN_FIRMWARE__
+ #define FTDI_EXTENDED
+#endif
+
+#if ENABLED(FTDI_EXTENDED)
+ #include "unicode/font_size_t.h"
+ #include "unicode/unicode.h"
+ #include "unicode/standard_char_set.h"
+ #include "unicode/western_char_set.h"
+ #include "unicode/cyrillic_char_set.h"
+ #include "unicode/font_bitmaps.h"
+ #include "rgb_t.h"
+ #include "bitmap_info.h"
+ #include "tiny_timer.h"
+ #include "grid_layout.h"
+ #include "dl_cache.h"
+ #include "event_loop.h"
+ #include "command_processor.h"
+ #include "screen_types.h"
+ #include "sound_player.h"
+ #include "sound_list.h"
+ #include "polygon.h"
+ #include "text_box.h"
+ #include "text_ellipsis.h"
+#endif
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h
new file mode 100644
index 0000000..82bb8ab
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h
@@ -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: <https://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 {
+ #if ENABLED(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
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h
new file mode 100644
index 0000000..6aa52f0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h
@@ -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: <https://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
+ #if ENABLED(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));}
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h
new file mode 100644
index 0000000..62762ee
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h
@@ -0,0 +1,84 @@
+/***********
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * Implementation of hsl_to_rgb as constexpr functions based on:
+ *
+ * https://www.rapidtables.com/convert/color/hsl-to-rgb.html
+ */
+
+constexpr float _hsl_fmod(float x, float y) {
+ return x - int(x/y)*y;
+}
+
+constexpr float _hsl_c(float, float S, float L) {
+ return (1.0f - fabs(2*L-1.0f)) * S;
+}
+
+constexpr float _hsl_x(float H, float S, float L) {
+ return _hsl_c(H,S,L) * (1.0f - fabs(_hsl_fmod(H/60, 2) - 1));
+}
+
+constexpr float _hsl_m(float H, float S, float L) {
+ return L - _hsl_c(H,S,L)/2;
+}
+
+constexpr float _hsl_rgb(float H, float S, float L, float r, float g, float b) {
+ return ((uint32_t((r + _hsl_m(H,S,L))*255+0.5) << 16) |
+ (uint32_t((g + _hsl_m(H,S,L))*255+0.5) << 8) |
+ (uint32_t((b + _hsl_m(H,S,L))*255+0.5) << 0));
+}
+
+constexpr uint32_t hsl_to_rgb(float H, float S, float L) {
+ return (H < 60) ? _hsl_rgb(H,S,L,_hsl_c(H,S,L), _hsl_x(H,S,L), 0) :
+ (H < 120) ? _hsl_rgb(H,S,L,_hsl_x(H,S,L), _hsl_c(H,S,L), 0) :
+ (H < 180) ? _hsl_rgb(H,S,L, 0, _hsl_c(H,S,L), _hsl_x(H,S,L)) :
+ (H < 240) ? _hsl_rgb(H,S,L, 0, _hsl_x(H,S,L), _hsl_c(H,S,L)) :
+ (H < 300) ? _hsl_rgb(H,S,L,_hsl_x(H,S,L), 0, _hsl_c(H,S,L)) :
+ _hsl_rgb(H,S,L,_hsl_c(H,S,L), 0, _hsl_x(H,S,L));
+}
+
+/**
+ * Structure for RGB colors
+ */
+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;}
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp
new file mode 100644
index 0000000..944237b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp
@@ -0,0 +1,105 @@
+/******************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(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;
+ }
+ }
+ #if ENABLED(TOUCH_UI_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);
+ #if ENABLED(TOUCH_UI_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
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h
new file mode 100644
index 0000000..1581cbb
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h
@@ -0,0 +1,241 @@
+/********************
+ * 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: <https://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();
+ typedef void onEntry_func_t();
+ typedef void onExit_func_t();
+ typedef void onIdle_func_t();
+ typedef void onRefresh_func_t();
+ 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;
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART);
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd);
+ #endif
+
+ 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 void gfxError() {
+ using namespace FTDI;
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR(true,true,true))
+ .font(30)
+ .text(0, 0, display_width, display_height, F("GFX MEM FULL"));
+ }
+
+ static bool storeBackground() {
+ DLCache dlcache(DL_SLOT);
+ if (!dlcache.store(DL_SIZE)) {
+ SERIAL_ECHO_MSG("CachedScreen::storeBackground() failed: not enough DL cache space");
+ gfxError(); // Try to cache a shorter error message instead.
+ dlcache.store(DL_SIZE);
+ return false;
+ }
+ return true;
+ }
+
+ static void repaintBackground() {
+ using namespace FTDI;
+ DLCache dlcache(DL_SLOT);
+ CommandProcessor cmd;
+
+ cmd.cmd(CMD_DLSTART);
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd);
+ #endif
+ current_screen.onRedraw(BACKGROUND);
+
+ dlcache.store(DL_SIZE);
+ }
+
+ public:
+ static void onRefresh() {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ const uint32_t start_time = millis();
+ #endif
+ using namespace FTDI;
+ DLCache dlcache(DL_SLOT);
+ CommandProcessor cmd;
+
+ cmd.cmd(CMD_DLSTART);
+
+ if (dlcache.has_data()) {
+ dlcache.append();
+ }
+ else {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd);
+ #endif
+ current_screen.onRedraw(BACKGROUND);
+ dlcache.store(DL_SIZE);
+ }
+
+ current_screen.onRedraw(FOREGROUND);
+
+ cmd.cmd(DL::DL_DISPLAY);
+ cmd.cmd(CMD_SWAP);
+ cmd.execute();
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPAIR("Time to draw screen (ms): ", millis() - start_time);
+ #endif
+ }
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h
new file mode 100644
index 0000000..20df15a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h
@@ -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: <https://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_far(&list[val].name);
+ }
+ static inline FTDI::SoundPlayer::sound_t* data(uint8_t val) {
+ return (FTDI::SoundPlayer::sound_t*) pgm_read_ptr_far(&list[val].data);
+ }
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp
new file mode 100644
index 0000000..07d1ff5
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp
@@ -0,0 +1,110 @@
+/********************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(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) {
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPAIR ("Playing note ", int(note));
+ SERIAL_ECHOLNPAIR(", instrument ", int(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();
+ TERN_(TOUCH_UI_FTDI_EVE, ExtUI::yield());
+ }
+ }
+
+ 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
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h
new file mode 100644
index 0000000..fcfe70b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h
@@ -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: <https://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}
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp
new file mode 100644
index 0000000..b7422a0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp
@@ -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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(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 FontMetrics &fm, uint16_t w, const char *str, const char *&end) {
+ w -= fm.get_char_width(' ');
+ const char *p = str;
+ end = str;
+ uint16_t lw = 0, result = 0;
+ for (;;) {
+ utf8_char_t c = get_utf8_char_and_inc(p);
+ if (c == ' ' || c == '\n' || c == '\0') {
+ if (lw < w || end == str) {
+ end = (c == '\0') ? p-1 : p;
+ result = lw;
+ }
+ if (c == '\0' || c == '\n') break;
+ }
+ lw += fm.get_char_width(c);
+ }
+ if (end == str) {
+ end = p-1;
+ result = lw;
+ }
+ return result;
+ }
+
+ /**
+ * This function returns a measurements of the word-wrapped text box.
+ */
+ static void measure_text_box(const 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.get_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) {
+ uint16_t box_width, box_height;
+
+ FontMetrics fm(font);
+
+ // Shrink the font until we find a font that fits
+ 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;
+
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(line)) {
+ draw_utf8_text(cmd, x + dx, y + dy, line, fm.fs, options & ~OPT_CENTERY);
+ } else
+ #endif
+ {
+ cmd.CLCD::CommandFifo::text(x + dx, y + dy, font, options & ~OPT_CENTERY);
+ cmd.CLCD::CommandFifo::str(line);
+ }
+ }
+ y += fm.get_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
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h
new file mode 100644
index 0000000..9d8cd44
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h
@@ -0,0 +1,30 @@
+/**************
+ * text_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * This function draws text inside a bounding box, doing word wrapping and using the largest font that will fit.
+ */
+namespace FTDI {
+ void draw_text_box(class CommandProcessor& cmd, int x, int y, int w, int h, progmem_str str, uint16_t options = 0, uint8_t font = 31);
+ void draw_text_box(class CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options = 0, uint8_t font = 31);
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp
new file mode 100644
index 0000000..5fc89f1
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp
@@ -0,0 +1,91 @@
+/*********************
+ * text_ellipsis.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+namespace FTDI {
+
+ /**
+ * Helper function for drawing text with ellipses. The str buffer may be modified and should have space for up to two extra characters.
+ */
+ static void _draw_text_with_ellipsis(CommandProcessor& cmd, int16_t x, int16_t y, int16_t w, int16_t h, char *str, uint16_t options, uint8_t font) {
+ FontMetrics fm(font);
+ const int16_t ellipsisWidth = fm.get_char_width('.') * 3;
+
+ // Compute the total line length, as well as
+ // the location in the string where it can
+ // split and still allow the ellipsis to fit.
+ int16_t lineWidth = 0;
+ char *breakPoint = str;
+ #ifdef TOUCH_UI_USE_UTF8
+ char *tstr = str;
+ while (*tstr) {
+ breakPoint = tstr;
+ const utf8_char_t c = get_utf8_char_and_inc(tstr);
+ lineWidth += fm.get_char_width(c);
+ if (lineWidth + ellipsisWidth < w)
+ break;
+ }
+ #else
+ for (char* c = str; *c; c++) {
+ lineWidth += fm.get_char_width(*c);
+ if (lineWidth + ellipsisWidth < w)
+ breakPoint = c;
+ }
+ #endif
+
+ if (lineWidth > w) {
+ *breakPoint = '\0';
+ strcpy_P(breakPoint,PSTR("..."));
+ }
+
+ cmd.apply_text_alignment(x, y, w, h, options);
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(str)) {
+ draw_utf8_text(cmd, x, y, str, font_size_t::from_romfont(font), options);
+ } else
+ #endif
+ {
+ cmd.CLCD::CommandFifo::text(x, y, font, options);
+ cmd.CLCD::CommandFifo::str(str);
+ }
+ }
+
+ /**
+ * These functions draws text inside a bounding box, truncating the text and
+ * adding ellipsis if the text does not fit.
+ */
+ void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options, uint8_t font) {
+ char tmp[strlen(str) + 3];
+ strcpy(tmp, str);
+ _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font);
+ }
+
+ void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, progmem_str pstr, uint16_t options, uint8_t font) {
+ char tmp[strlen_P((const char*)pstr) + 3];
+ strcpy_P(tmp, (const char*)pstr);
+ _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font);
+ }
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h
new file mode 100644
index 0000000..a2d8aa9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h
@@ -0,0 +1,31 @@
+/*******************
+ * text_ellipsis.h *
+ *******************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2020 - SynDaver Labs, 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * This function draws text inside a bounding box, truncating the text and
+ * showing ellipsis if it does not fit.
+ */
+namespace FTDI {
+ void draw_text_with_ellipsis(class CommandProcessor& cmd, int x, int y, int w, int h, progmem_str str, uint16_t options = 0, uint8_t font = 31);
+ void draw_text_with_ellipsis(class CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options = 0, uint8_t font = 31);
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp
new file mode 100644
index 0000000..5219c0d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp
@@ -0,0 +1,39 @@
+/******************
+ * tiny_timer.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+bool tiny_timer_t::elapsed(tiny_time_t duration) {
+ uint8_t now = tiny_time_t::tiny_time(
+ TERN(__MARLIN_FIRMWARE__, ExtUI::safe_millis(), millis())
+ );
+ uint8_t elapsed = now - _start;
+ return elapsed >= duration._duration;
+}
+
+void tiny_timer_t::start() {
+ _start = tiny_time_t::tiny_time(
+ TERN(__MARLIN_FIRMWARE__, ExtUI::safe_millis(), millis())
+ );
+}
+#endif // FTDI_EXTENDED
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h
new file mode 100644
index 0000000..f64d033
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h
@@ -0,0 +1,56 @@
+/****************
+ * tiny_timer.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/* Helpful Reference:
+ *
+ * https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover
+ */
+
+/* tiny_interval_t downsamples a 32-bit millis() value
+ into a 8-bit value which can record periods of
+ a few seconds with a rougly 1/16th of second
+ resolution. This allows us to measure small
+ intervals without needing to use four-byte counters.
+ */
+class tiny_time_t {
+ private:
+ friend class tiny_timer_t;
+ uint8_t _duration;
+
+ static uint8_t tiny_time(uint32_t ms) {return ceil(float(ms) / 64);};
+
+ public:
+ tiny_time_t() : _duration(0) {}
+ tiny_time_t(uint32_t ms) : _duration(tiny_time(ms)) {}
+ tiny_time_t & operator= (uint32_t ms) {_duration = tiny_time(ms); return *this;}
+ bool operator == (uint32_t ms) {return _duration == tiny_time(ms);}
+};
+
+class tiny_timer_t {
+ private:
+ uint8_t _start;
+
+ public:
+ void start();
+ bool elapsed(tiny_time_t interval);
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt
new file mode 100644
index 0000000..818bf08
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt
@@ -0,0 +1,40 @@
+
+FTDI EVE Unicode Rendering
+--------------------------
+
+The FTDI EVE chips have several fonts in ROM, but these fonts only contain a
+subset of ASCII characters. Notably, this excludes diacritics and accents
+used in most Western languages.
+
+While the FTDI EVE has the capability for user-defined fonts, such fonts only
+support 127 character positions, making them as limiting as the built-in fonts.
+
+As a further complication, high resolution TFT displays require high resolution
+fonts. It is not feasible to put a complete international font into the limited
+flash memory of most microprocessors.
+
+To work around these limitations, this library uses a custom font renderer with
+the following characteristics:
+
+ 1) Rather than providing bitmaps for different font sizes, it uses a single
+ bitmap for the largest font size (romfont 31) and emulates other sizes by
+ scaling the bitmaps using BITMAP_TRANSFORM.
+
+ 2) Rather than loading an entire font, it combines symbols from romfont 31
+ with a limited number of symbols from a custom font. For accented letters,
+ the rendering code combine basic letter shapes from romfont 31 with
+ bitmaps containing only the accent themselves.
+
+ 3) The custom bitmap is RLE compressed into PROGMEM. For accents, which have
+ a fairly small number of non-white pixels, the savings are significant.
+
+These characteristics enable an alphabet for Western languages to be
+synthesized from only a few dozen custom symbols and modest PROGMEM use (~10k)
+
+The text layout is done by the code in "unicode.cpp" with the help of one of
+more character renderers (e.g. "western_char_set.cpp"). Each character render
+is responsible for loading the necessary bitmap data into RAMG and drawing
+characters as requested.
+
+To add symbols for other languages, it will only be necessary to make a bitmap
+and implement a corresponding character renderer.
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp
new file mode 100644
index 0000000..1c193ad
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp
@@ -0,0 +1,139 @@
+/************************
+ * cyrillic_char_set.cpp *
+ ************************/
+
+/****************************************************************************
+ * Written By Kirill Shashlov 2020 *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if ALL(FTDI_EXTENDED, TOUCH_UI_USE_UTF8, TOUCH_UI_UTF8_CYRILLIC_CHARSET)
+
+ #include "cyrillic_char_set_bitmap_31.h"
+
+ #define NUM_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
+
+ #define UTF8(A) uint16_t(utf8(U##A))
+
+ using namespace FTDI;
+
+ constexpr static uint8_t cyrillic_font_handle = 6;
+
+ uint32_t FTDI::CyrillicCharSet::bitmap_addr;
+
+ /**
+ * Load bitmap data into RAMG. This function is called once at the start
+ * of the program.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ *
+ * Returns: Last wrote address
+ */
+
+ uint32_t FTDI::CyrillicCharSet::load_data(uint32_t addr) {
+ if (addr % 4 != 0)
+ addr += 4 - (addr % 4);
+
+ // Load the alternative font metrics
+ CLCD::FontMetrics cyrillic_fm;
+ cyrillic_fm.ptr = addr + 148;
+ cyrillic_fm.format = L4;
+ cyrillic_fm.stride = 20;
+ cyrillic_fm.width = 40;
+ cyrillic_fm.height = 49;
+ LOOP_L_N(i, 127)
+ cyrillic_fm.char_widths[i] = 0;
+
+ // For cyrillic characters, copy the character widths from the widths tables
+ LOOP_L_N(i, NUM_ELEMENTS(cyrillic_font_widths)) {
+ cyrillic_fm.char_widths[i] = cyrillic_font_widths[i];
+ }
+ CLCD::mem_write_bulk(addr, &cyrillic_fm, 148);
+
+ // Decode the RLE data and load it into RAMG as a bitmap
+ uint32_t lastaddr = write_rle_data(addr + 148, cyrillic_font, sizeof(cyrillic_font));
+
+ bitmap_addr = addr;
+
+ return lastaddr;
+ }
+
+ /**
+ * Populates the bitmap handles for the custom into the display list.
+ * This function is called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::CyrillicCharSet::load_bitmaps(CommandProcessor& cmd) {
+ CLCD::FontMetrics cyrillic_fm;
+ cyrillic_fm.ptr = bitmap_addr + 148;
+ cyrillic_fm.format = L4;
+ cyrillic_fm.stride = 20;
+ cyrillic_fm.width = 40;
+ cyrillic_fm.height = 49;
+ set_font_bitmap(cmd, cyrillic_fm, cyrillic_font_handle);
+ }
+
+ /**
+ * Renders a character at location x and y. The x position is incremented
+ * by the width of the character.
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the character. On output,
+ * incremented to the location of the next character.
+ *
+ * fs - A scaling object used to scale the font. The display will
+ * already be configured to scale bitmaps, but positions
+ * must be scaled using fs.scale()
+ *
+ * c - The unicode code point to draw. If the renderer does not
+ * support the character, it should return false.
+ *
+ * Returns: Whether the character was supported.
+ */
+
+ bool FTDI::CyrillicCharSet::render_glyph(CommandProcessor* cmd, int &x, int &y, font_size_t fs, utf8_char_t c) {
+ // A supported character?
+ if ((c < UTF8('А') || c > UTF8('я')) && (c != UTF8('Ё')) && (c != UTF8('ё'))) return false;
+
+ uint8_t idx = (c == UTF8('Ё')) ? 64 :
+ (c == UTF8('ё')) ? 65 :
+ (c < UTF8('р')) ? c - UTF8('А') :
+ c - UTF8('р') + 48
+ ;
+
+ uint8_t width = cyrillic_font_widths[idx];
+
+ // Draw the character
+ if (cmd) ext_vertex2ii(*cmd, x, y, cyrillic_font_handle, idx);
+
+ // Increment X to the next character position
+ x += fs.scale(width);
+ return true;
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8 && TOUCH_UI_UTF8_WESTERN_CHARSET
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h
new file mode 100644
index 0000000..63493b8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h
@@ -0,0 +1,32 @@
+/**********************
+ * cyrillic_char_set.h *
+ **********************/
+
+/****************************************************************************
+ * Written By Kirill Shashlov 2020 *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+namespace FTDI {
+ class CyrillicCharSet {
+ private:
+ static uint32_t bitmap_addr;
+ public:
+ static uint32_t load_data(uint32_t addr);
+ static void load_bitmaps(CommandProcessor&);
+ static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h
new file mode 100644
index 0000000..00bfe37
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h
@@ -0,0 +1,2529 @@
+/********************************
+ * cyrillic_char_set_bitmap_31.h *
+ ********************************/
+
+/****************************************************************************
+ * Written By Kirill Shashlov 2020 *
+ * Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * Used GNU FreeFont FreeSans font (licensed under the GPL) *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+const uint8_t cyrillic_font_widths[] PROGMEM = {
+ 27, // А (0)
+ 26, // Б
+ 26, // В
+ 24, // Г
+ 33, // Д
+ 25, // Е
+ 37, // Ж
+ 26, // З
+
+ 28, // И (8)
+ 28, // Й
+ 26, // К
+ 25, // Л
+ 33, // М
+ 27, // Н
+ 31, // О
+ 27, // П
+
+ 26, // Р (16)
+ 29, // С
+ 28, // Т
+ 26, // У
+ 34, // Ф
+ 27, // Х
+ 30, // Ц
+ 23, // Ч
+
+ 32, // Ш (24)
+ 34, // Щ
+ 26, // Ь
+ 34, // Ы
+ 34, // Ъ
+ 28, // Э
+ 40, // Ю
+ 26, // Я
+
+ 22, // а (32)
+ 21, // б
+ 20, // в
+ 16, // г
+ 24, // д
+ 21, // е
+ 31, // ж
+ 19, // з
+
+ 21, // и (40)
+ 21, // й
+ 20, // к
+ 19, // л
+ 23, // м
+ 21, // н
+ 21, // о
+ 21, // п
+
+ 22, // р (48)
+ 20, // с
+ 17, // т
+ 19, // у
+ 34, // ф
+ 19, // х
+ 23, // ц
+ 19, // ч
+ 26, // ш
+ 28, // щ
+ 20, // ь
+ 26, // ы
+ 26, // ъ
+ 20, // э
+ 30, // ю
+ 20, // я
+
+ 26, // Ё
+ 21, // ё
+};
+
+
+/* This is a dump of "font_bitmaps/cyrillic_char_set_bitmap_31.png"
+ * using the tool "bitmap2cpp.py". The tool converts the image into
+ * 16-level grayscale and packs two pixels per byte. The resulting
+ * bytes are then RLE compressed to yield (count, byte) pairs.
+ */
+
+const unsigned char cyrillic_font[] PROGMEM = {
+ /* 0 */
+ 0xb9, 0x00, 0x01, 0x2f, 0x02, 0xff, 0x01, 0x30, 0x10, 0x00, 0x01, 0x7f,
+ 0x02, 0xff, 0x01, 0x90, 0x10, 0x00, 0x01, 0xdf, 0x02, 0xff, 0x01, 0xe0,
+ 0x0f, 0x00, 0x01, 0x03, 0x03, 0xff, 0x01, 0xf4, 0x0f, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xfb, 0x01, 0xff, 0x01, 0xfa, 0x0f, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xf1, 0x02, 0xff, 0x0f, 0x00, 0x01, 0x5f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x50, 0x0e, 0x00, 0x01, 0xaf,
+ 0x01, 0xff, 0x01, 0x40, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xb0, 0x0d, 0x00,
+ 0x01, 0x01, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xf1, 0x0d, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf8, 0x01, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf7, 0x0d, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x01, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xfc, 0x0d, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0xef, 0x01, 0xff,
+ 0x01, 0x20, 0x0c, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x60, 0x02, 0x00,
+ 0x01, 0x9f, 0x01, 0xff, 0x01, 0x80, 0x0c, 0x00, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0x10, 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xd0, 0x0b, 0x00,
+ 0x01, 0x03, 0x01, 0xff, 0x01, 0xfa, 0x03, 0x00, 0x01, 0x0e, 0x01, 0xff,
+ 0x01, 0xf3, 0x0b, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf5, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xff, 0x01, 0xf9, 0x0b, 0x00, 0x01, 0x0e, 0x01, 0xff,
+ 0x01, 0xe0, 0x03, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0x4f, 0x01, 0xff, 0x01, 0xb4, 0x04, 0x44, 0x02, 0xff, 0x01, 0x40,
+ 0x0a, 0x00, 0x01, 0xaf, 0x08, 0xff, 0x01, 0xa0, 0x0a, 0x00, 0x09, 0xff,
+ 0x01, 0xf0, 0x09, 0x00, 0x01, 0x06, 0x02, 0xff, 0x05, 0xee, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xf5, 0x09, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf5,
+ 0x05, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xfb, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xf0, 0x05, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x90, 0x06, 0x00, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0x70, 0x08, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x40,
+ 0x06, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xfe, 0x07, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xf2,
+ 0x07, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf8, 0x07, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf8, 0x07, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf2,
+ 0x07, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xfd, 0x07, 0x00, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x01, 0x02, 0xff, 0x01, 0x30,
+ 0x06, 0x00, 0x01, 0x8d, 0x01, 0xdd, 0x01, 0x60, 0x08, 0x00, 0x01, 0xad,
+ 0x01, 0xdd, 0x01, 0x70, 0xce, 0x00,
+
+ /* 1 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf4, 0x09, 0x00, 0x01, 0x1f,
+ 0x09, 0xff, 0x01, 0xf4, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf4,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd5, 0x07, 0x55, 0x01, 0x51,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xfe,
+ 0x04, 0xee, 0x01, 0xdb, 0x01, 0x84, 0x0b, 0x00, 0x01, 0x1f, 0x08, 0xff,
+ 0x01, 0xe7, 0x0a, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xd2, 0x09, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd6, 0x04, 0x66, 0x01, 0x68, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0xfd, 0x01, 0x10, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x05, 0x00, 0x01, 0x04, 0x01, 0xef, 0x01, 0xff, 0x01, 0x90,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf5, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf7,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf9, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf7,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf4, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xe0, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x05, 0x02, 0xff, 0x01, 0x80,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe7, 0x04, 0x77, 0x01, 0x89,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0xfe, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff,
+ 0x01, 0xe2, 0x09, 0x00, 0x01, 0x1f, 0x08, 0xff, 0x01, 0xfb, 0x01, 0x10,
+ 0x09, 0x00, 0x01, 0x1d, 0x06, 0xdd, 0x01, 0xdc, 0x01, 0xb7, 0x01, 0x20,
+ 0xd1, 0x00,
+
+ /* 2 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x06, 0xff, 0x01, 0xec, 0x01, 0x94, 0x0b, 0x00,
+ 0x01, 0x1f, 0x08, 0xff, 0x01, 0xc3, 0x0a, 0x00, 0x01, 0x1f, 0x09, 0xff,
+ 0x01, 0x40, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd6, 0x03, 0x66,
+ 0x01, 0x67, 0x01, 0x9d, 0x02, 0xff, 0x01, 0xe1, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x4e, 0x01, 0xff, 0x01, 0xf9,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x04,
+ 0x02, 0xff, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0x20, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x06, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x30, 0x08, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0xaf, 0x01, 0xff,
+ 0x01, 0x20, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00,
+ 0x01, 0xcf, 0x01, 0xff, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x05, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfa, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x1d, 0x01, 0xff, 0x01, 0xf2,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd2, 0x03, 0x22, 0x01, 0x23,
+ 0x01, 0x59, 0x02, 0xff, 0x01, 0x50, 0x09, 0x00, 0x01, 0x1f, 0x08, 0xff,
+ 0x01, 0xd3, 0x0a, 0x00, 0x01, 0x1f, 0x08, 0xff, 0x01, 0xb3, 0x0a, 0x00,
+ 0x01, 0x1f, 0x09, 0xff, 0x01, 0xa0, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xd4, 0x04, 0x44, 0x01, 0x45, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xfd,
+ 0x01, 0x10, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00,
+ 0x01, 0x01, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xa0, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf6, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf9,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x07,
+ 0x01, 0xff, 0x01, 0xf7, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf5, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x05,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x90, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xe7, 0x04, 0x77, 0x01, 0x79, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0x10, 0x08, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xe3, 0x09, 0x00,
+ 0x01, 0x1f, 0x08, 0xff, 0x01, 0xfa, 0x01, 0x10, 0x09, 0x00, 0x01, 0x1d,
+ 0x07, 0xdd, 0x01, 0xb7, 0x01, 0x20, 0xd1, 0x00,
+
+ /* 3 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf4, 0x09, 0x00, 0x01, 0x1f,
+ 0x09, 0xff, 0x01, 0xf4, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf4,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd5, 0x07, 0x55, 0x01, 0x51,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1e,
+ 0x01, 0xee, 0x01, 0xb0, 0xd8, 0x00,
+
+ /* 4 */
+ 0xb8, 0x00, 0x01, 0x08, 0x09, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x09, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x09, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xfa, 0x05, 0x66, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf5, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf5,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xf4, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf3, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf2,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xf0, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xf0, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0xa0, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x70, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0x30,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xfe, 0x06, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xf1,
+ 0x06, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0x22, 0x01, 0x28, 0x02, 0xff, 0x01, 0xc7, 0x06, 0x77, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0x52, 0x01, 0x22, 0x04, 0x00, 0x01, 0x0f, 0x0f, 0xff,
+ 0x04, 0x00, 0x01, 0x0f, 0x0f, 0xff, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xed, 0x0b, 0xdd, 0x01, 0xef, 0x01, 0xff, 0x04, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x04, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x5f, 0x01, 0xff,
+ 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x5f,
+ 0x01, 0xff, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00,
+ 0x01, 0x5f, 0x01, 0xff, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x50,
+ 0x0b, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x04, 0x00, 0x01, 0x06, 0x01, 0x66,
+ 0x01, 0x20, 0x0b, 0x00, 0x01, 0x26, 0x01, 0x66, 0x54, 0x00,
+
+ /* 5 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x0a, 0xff, 0x09, 0x00, 0x01, 0x1f, 0x0a, 0xff,
+ 0x09, 0x00, 0x01, 0x1f, 0x0a, 0xff, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xd6, 0x07, 0x66, 0x01, 0x65, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc1, 0x07, 0x11, 0x01, 0x10, 0x09, 0x00,
+ 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf5, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff,
+ 0x01, 0xf5, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf5, 0x09, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd4, 0x07, 0x44, 0x01, 0x41, 0x09, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe7, 0x08, 0x77, 0x01, 0x50, 0x08, 0x00,
+ 0x01, 0x1f, 0x0a, 0xff, 0x01, 0xb0, 0x08, 0x00, 0x01, 0x1f, 0x0a, 0xff,
+ 0x01, 0xb0, 0x08, 0x00, 0x01, 0x1e, 0x0a, 0xee, 0x01, 0xa0, 0xcf, 0x00,
+
+ /* 6 */
+ 0xb5, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xf3, 0x04, 0x00, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xe1,
+ 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00,
+ 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00, 0x01, 0x0a, 0x02, 0xff,
+ 0x01, 0x30, 0x03, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xff, 0x01, 0xb0,
+ 0x03, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0xf5, 0x05, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xf8,
+ 0x03, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x03,
+ 0x02, 0xff, 0x01, 0x80, 0x05, 0x00, 0x01, 0x05, 0x02, 0xff, 0x01, 0x50,
+ 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x1e,
+ 0x01, 0xff, 0x01, 0xfb, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xf2,
+ 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xfd,
+ 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x07, 0x00, 0x01, 0x01, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0xb0, 0x01, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xf4, 0x09, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xf7, 0x01, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0x02, 0x02, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x05, 0x02, 0xff,
+ 0x01, 0x40, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x1d, 0x01, 0xff,
+ 0x01, 0xfa, 0x0b, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xe2, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0x90, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xc0, 0x0b, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xfc, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x98,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10, 0x0c, 0x00, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xf3, 0x0d, 0x00,
+ 0x01, 0x2e, 0x05, 0xff, 0x01, 0x60, 0x0d, 0x00, 0x01, 0x07, 0x04, 0xff,
+ 0x01, 0xfc, 0x0e, 0x00, 0x01, 0x2e, 0x05, 0xff, 0x01, 0x60, 0x0c, 0x00,
+ 0x01, 0x01, 0x01, 0xef, 0x01, 0xff, 0x01, 0xef, 0x01, 0xff, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xf4, 0x0c, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfd,
+ 0x01, 0x5f, 0x01, 0xff, 0x01, 0x9a, 0x02, 0xff, 0x01, 0x30, 0x0b, 0x00,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0xe2, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0xe2, 0x0a, 0x00, 0x01, 0x09, 0x02, 0xff,
+ 0x01, 0x30, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x0d, 0x01, 0xff,
+ 0x01, 0xfd, 0x01, 0x10, 0x09, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xf4,
+ 0x01, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x01, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xc0, 0x08, 0x00, 0x01, 0x06, 0x02, 0xff, 0x01, 0x50,
+ 0x01, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0xfb, 0x08, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xf7,
+ 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x04,
+ 0x02, 0xff, 0x01, 0x90, 0x06, 0x00, 0x01, 0x03, 0x02, 0xff, 0x01, 0x80,
+ 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0xf7, 0x06, 0x00, 0x01, 0x2e, 0x01, 0xff, 0x01, 0xfa,
+ 0x03, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x08,
+ 0x02, 0xff, 0x01, 0x50, 0x04, 0x00, 0x01, 0x01, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xb0, 0x03, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00,
+ 0x01, 0xaf, 0x01, 0xff, 0x01, 0xf4, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xfc, 0x04, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00,
+ 0x01, 0x0b, 0x02, 0xff, 0x01, 0x20, 0x03, 0x00, 0x01, 0xaf, 0x01, 0xff,
+ 0x01, 0xd1, 0x04, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90, 0x04, 0x00,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0xe1, 0x02, 0x00, 0x01, 0x08, 0x01, 0xff,
+ 0x01, 0xfe, 0x01, 0x20, 0x04, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x2e, 0x01, 0xff, 0x01, 0xfd, 0x01, 0x10, 0x01, 0x00,
+ 0x01, 0x5d, 0x01, 0xdd, 0x01, 0xd3, 0x05, 0x00, 0x01, 0x3d, 0x01, 0xdd,
+ 0x01, 0x80, 0x04, 0x00, 0x01, 0x03, 0x02, 0xdd, 0x01, 0x90, 0xc9, 0x00,
+
+ /* 7 */
+ 0xa5, 0x00, 0x01, 0x45, 0x01, 0x67, 0x01, 0x65, 0x01, 0x20, 0x0e, 0x00,
+ 0x01, 0x06, 0x01, 0xcf, 0x03, 0xff, 0x01, 0xfe, 0x01, 0x92, 0x0c, 0x00,
+ 0x01, 0x04, 0x01, 0xef, 0x06, 0xff, 0x01, 0x90, 0x0b, 0x00, 0x01, 0x6f,
+ 0x02, 0xff, 0x01, 0xfd, 0x01, 0xcb, 0x01, 0xcf, 0x02, 0xff, 0x01, 0xfc,
+ 0x0a, 0x00, 0x01, 0x04, 0x02, 0xff, 0x01, 0xd6, 0x01, 0x10, 0x02, 0x00,
+ 0x01, 0x39, 0x02, 0xff, 0x01, 0xa0, 0x09, 0x00, 0x01, 0x0d, 0x01, 0xff,
+ 0x01, 0xf9, 0x05, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xf3, 0x09, 0x00,
+ 0x01, 0x4f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf9, 0x09, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x06, 0x00,
+ 0x01, 0xff, 0x01, 0xfe, 0x09, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x07, 0x00,
+ 0x01, 0xdf, 0x01, 0xff, 0x09, 0x00, 0x01, 0xac, 0x01, 0xcb, 0x07, 0x00,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x10, 0x10, 0x00, 0x01, 0x04, 0x02, 0xff,
+ 0x11, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xfc, 0x10, 0x00, 0x01, 0x01,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0xf5, 0x10, 0x00, 0x01, 0x5d, 0x02, 0xff,
+ 0x01, 0xa0, 0x0d, 0x00, 0x02, 0x99, 0x01, 0xbe, 0x02, 0xff, 0x01, 0xf8,
+ 0x0e, 0x00, 0x05, 0xff, 0x01, 0x40, 0x0e, 0x00, 0x05, 0xff, 0x01, 0xf9,
+ 0x0e, 0x00, 0x02, 0xbb, 0x01, 0xcd, 0x03, 0xff, 0x01, 0xd1, 0x10, 0x00,
+ 0x01, 0x16, 0x01, 0xef, 0x01, 0xff, 0x01, 0xfc, 0x11, 0x00, 0x01, 0x0a,
+ 0x02, 0xff, 0x01, 0x60, 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x07, 0x01, 0x99, 0x01, 0x80, 0x07, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xf0, 0x07, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf0,
+ 0x07, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf1, 0x07, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xf2, 0x07, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf1,
+ 0x07, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8, 0x07, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xe0, 0x07, 0x00, 0x01, 0x01, 0x02, 0xff, 0x01, 0x20,
+ 0x06, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xa0, 0x08, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0xd2, 0x05, 0x00, 0x01, 0x03, 0x02, 0xff, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x1e, 0x02, 0xff, 0x01, 0x81, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0x8f, 0x01, 0xff, 0x01, 0xfa, 0x09, 0x00, 0x01, 0x03, 0x01, 0xef,
+ 0x02, 0xff, 0x01, 0xda, 0x01, 0x98, 0x01, 0x9a, 0x01, 0xdf, 0x02, 0xff,
+ 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x2d, 0x07, 0xff, 0x01, 0xfa, 0x0c, 0x00,
+ 0x01, 0x6d, 0x05, 0xff, 0x01, 0xfb, 0x01, 0x30, 0x0d, 0x00, 0x01, 0x27,
+ 0x01, 0x9b, 0x01, 0xcd, 0x01, 0xba, 0x01, 0x95, 0x01, 0x10, 0xbe, 0x00,
+
+ /* 8 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x07, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x06, 0x00, 0x01, 0x07, 0x02, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x06, 0x00, 0x01, 0x2f, 0x02, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x06, 0x00, 0x01, 0xcf,
+ 0x02, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0x06, 0x03, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xfa, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0x1e, 0x01, 0xff,
+ 0x01, 0xe1, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x60,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xfb, 0x01, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf2, 0x01, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x70, 0x01, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xfd, 0x02, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf3, 0x02, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x80, 0x02, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfd, 0x03, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0x01, 0x01, 0xef, 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf5, 0x04, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0x5f, 0x01, 0xff, 0x01, 0xb0, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x10, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x99, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x03, 0xff, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f,
+ 0x02, 0xff, 0x01, 0xf7, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x02, 0xff, 0x01, 0xd0, 0x06, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x02, 0xff, 0x01, 0x30,
+ 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1e,
+ 0x01, 0xee, 0x01, 0xe8, 0x07, 0x00, 0x01, 0x0e, 0x01, 0xee, 0x01, 0xa0,
+ 0xce, 0x00,
+
+ /* 9 */
+ 0x2c, 0x00, 0x01, 0x7f, 0x01, 0xf1, 0x03, 0x00, 0x01, 0x9f, 0x01, 0xe0,
+ 0x0d, 0x00, 0x01, 0x5f, 0x01, 0xf8, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xb0, 0x0d, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xb6, 0x01, 0x45,
+ 0x01, 0x9f, 0x01, 0xff, 0x01, 0x50, 0x0d, 0x00, 0x01, 0x05, 0x04, 0xff,
+ 0x01, 0xfb, 0x0f, 0x00, 0x01, 0x5e, 0x03, 0xff, 0x01, 0x90, 0x10, 0x00,
+ 0x01, 0x46, 0x01, 0x87, 0x01, 0x51, 0x20, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x07, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x06, 0x00, 0x01, 0x07, 0x02, 0xff,
+ 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x06, 0x00,
+ 0x01, 0x2f, 0x02, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x06, 0x00, 0x01, 0xbf, 0x02, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x05, 0x00, 0x01, 0x06, 0x03, 0xff,
+ 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x05, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xef, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x05, 0x00, 0x01, 0xaf, 0x01, 0xff,
+ 0x01, 0x4f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x04, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xfa, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xe1, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x04, 0x00,
+ 0x01, 0x9f, 0x01, 0xff, 0x01, 0x60, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00, 0x01, 0x04,
+ 0x01, 0xff, 0x01, 0xfb, 0x01, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00, 0x01, 0x0d,
+ 0x01, 0xff, 0x01, 0xf2, 0x01, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x70, 0x01, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xfd, 0x02, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf3, 0x02, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0x80, 0x02, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xfd, 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0x90, 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x01, 0x01, 0xef,
+ 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x0a, 0x01, 0xff,
+ 0x01, 0xf5, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xb0,
+ 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x01, 0xef, 0x01, 0xff, 0x01, 0x10, 0x04, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x99, 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xc0, 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x1f, 0x03, 0xff, 0x01, 0x20, 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x02, 0xff, 0x01, 0xf7, 0x06, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x02, 0xff,
+ 0x01, 0xd0, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x1f, 0x02, 0xff, 0x01, 0x30, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xe8, 0x07, 0x00,
+ 0x01, 0x0e, 0x01, 0xee, 0x01, 0xa0, 0xce, 0x00,
+
+ /* 10 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x1d,
+ 0x01, 0xff, 0x01, 0xfa, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x04, 0x00, 0x01, 0x01, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xa0, 0x09, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x04, 0x00, 0x01, 0x1d, 0x01, 0xff,
+ 0x01, 0xf9, 0x0a, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x03, 0x00,
+ 0x01, 0x01, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x90, 0x0a, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x2d, 0x01, 0xff, 0x01, 0xf9,
+ 0x0b, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x90, 0x0b, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x02, 0x00, 0x01, 0x2e, 0x01, 0xff, 0x01, 0xf8, 0x0c, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x01, 0x00, 0x01, 0x02, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x80, 0x0c, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x01, 0x00, 0x01, 0x2e, 0x01, 0xff, 0x01, 0xf8, 0x0d, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x01, 0x02, 0x01, 0xef, 0x01, 0xff, 0x01, 0x80,
+ 0x0d, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x01, 0x2e, 0x01, 0xff,
+ 0x01, 0xf7, 0x0e, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc3, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x70, 0x0e, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xee,
+ 0x01, 0xff, 0x01, 0xf7, 0x0f, 0x00, 0x01, 0x1f, 0x03, 0xff, 0x01, 0x70,
+ 0x0f, 0x00, 0x01, 0x1f, 0x03, 0xff, 0x01, 0x20, 0x0f, 0x00, 0x01, 0x1f,
+ 0x03, 0xff, 0x01, 0xe2, 0x0f, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xdd,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x0e, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc1, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xe2, 0x0e, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x01, 0x1d, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20,
+ 0x0d, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x01, 0x01, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0xe2, 0x0d, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x01, 0x00, 0x01, 0x1d, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x0c, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x01, 0x00, 0x01, 0x01, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0xe2, 0x0c, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x02, 0x00, 0x01, 0x1d, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x0b, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0x01, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0xe2, 0x0b, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x03, 0x00, 0x01, 0x1d, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x30, 0x0a, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x02, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xe3, 0x0a, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x04, 0x00, 0x01, 0x2e, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x30, 0x09, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x04, 0x00, 0x01, 0x02, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xe3, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x05, 0x00, 0x01, 0x2e, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x30, 0x08, 0x00,
+ 0x01, 0x1e, 0x01, 0xee, 0x01, 0xb0, 0x05, 0x00, 0x01, 0x02, 0x01, 0xde,
+ 0x01, 0xee, 0x01, 0xd2, 0xcf, 0x00,
+
+ /* 11 */
+ 0xb6, 0x00, 0x01, 0x08, 0x09, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x09, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x09, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xfa, 0x05, 0x66, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf5, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf4,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0a,
+ 0x01, 0xff, 0x01, 0xf4, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf3, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf1,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xf0, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xe0, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xc0,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0x90, 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x60, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x08, 0x00, 0x01, 0x01,
+ 0x01, 0xff, 0x01, 0xfe, 0x06, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf9, 0x06, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x30, 0x08, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xf2,
+ 0x06, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x07, 0x00, 0x01, 0x1a,
+ 0x02, 0xff, 0x01, 0xa0, 0x06, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30,
+ 0x07, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10, 0x06, 0x00,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x07, 0x00, 0x01, 0x2f, 0x01, 0xff,
+ 0x01, 0xf4, 0x07, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x07, 0x00,
+ 0x01, 0x2f, 0x01, 0xfb, 0x01, 0x20, 0x07, 0x00, 0x01, 0xae, 0x01, 0xee,
+ 0x01, 0x30, 0x07, 0x00, 0x01, 0x03, 0x01, 0x10, 0xc6, 0x00,
+
+ /* 12 */
+ 0xb5, 0x00, 0x01, 0x1e, 0x02, 0xee, 0x01, 0x70, 0x08, 0x00, 0x02, 0xee,
+ 0x01, 0xe7, 0x05, 0x00, 0x01, 0x1f, 0x02, 0xff, 0x01, 0xc0, 0x07, 0x00,
+ 0x01, 0x05, 0x02, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x02, 0xff,
+ 0x01, 0xf2, 0x07, 0x00, 0x01, 0x0b, 0x02, 0xff, 0x01, 0xf8, 0x05, 0x00,
+ 0x01, 0x1f, 0x02, 0xff, 0x01, 0xf7, 0x07, 0x00, 0x01, 0x1f, 0x02, 0xff,
+ 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x02, 0xff, 0x01, 0xfd, 0x07, 0x00,
+ 0x01, 0x6f, 0x02, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xcf, 0x01, 0xff, 0x01, 0x30, 0x06, 0x00, 0x01, 0xbf, 0x01, 0xfc,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x9d,
+ 0x01, 0xff, 0x01, 0x80, 0x05, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xf7,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x98,
+ 0x01, 0xff, 0x01, 0xe0, 0x05, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xe2,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x92,
+ 0x01, 0xff, 0x01, 0xf3, 0x05, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0x92,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0xdf, 0x01, 0xf9, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x42,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0x7f, 0x01, 0xfe, 0x05, 0x00, 0x01, 0x6f, 0x01, 0xfe, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0x2f, 0x01, 0xff, 0x01, 0x40, 0x04, 0x00, 0x01, 0xcf, 0x01, 0xf9,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0x0c, 0x01, 0xff, 0x01, 0x90, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0xff, 0x01, 0xf3, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x07, 0x01, 0xff, 0x01, 0xe0,
+ 0x03, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xe0, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x01,
+ 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0x80,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0xcf, 0x01, 0xfa, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x30, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x6f, 0x01, 0xff,
+ 0x03, 0x00, 0x01, 0x7f, 0x01, 0xfd, 0x01, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0x50, 0x02, 0x00, 0x01, 0xcf, 0x01, 0xf8,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xa0,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf3, 0x01, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x01, 0x00, 0x01, 0x07,
+ 0x01, 0xff, 0x01, 0xd0, 0x01, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0xff,
+ 0x01, 0xf6, 0x01, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0x80, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0xaf, 0x01, 0xfb, 0x01, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x20, 0x01, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x5f,
+ 0x01, 0xff, 0x01, 0x10, 0x01, 0x7f, 0x01, 0xfd, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x02, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x60, 0x01, 0xdf, 0x01, 0xf7,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xc2,
+ 0x01, 0xff, 0x01, 0xf2, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00, 0x01, 0x04,
+ 0x01, 0xff, 0x01, 0xfa, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0x70, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0x9f, 0x02, 0xff, 0x01, 0x20, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xfc, 0x03, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x05, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0x80,
+ 0x03, 0x00, 0x01, 0x0d, 0x01, 0xee, 0x01, 0xe6, 0x03, 0x00, 0x01, 0x02,
+ 0x01, 0xee, 0x01, 0xe7, 0xcc, 0x00,
+
+ /* 13 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x0b, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x0b, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x0b, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd4,
+ 0x07, 0x44, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1e,
+ 0x01, 0xee, 0x01, 0xb0, 0x07, 0x00, 0x01, 0x8e, 0x01, 0xee, 0x01, 0x40,
+ 0xce, 0x00,
+
+ /* 14 */
+ 0xa6, 0x00, 0x01, 0x13, 0x01, 0x56, 0x01, 0x64, 0x01, 0x31, 0x0e, 0x00,
+ 0x01, 0x02, 0x01, 0x8d, 0x04, 0xff, 0x01, 0xc7, 0x01, 0x10, 0x0b, 0x00,
+ 0x01, 0x01, 0x01, 0x9f, 0x06, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x3e,
+ 0x08, 0xff, 0x01, 0xd2, 0x09, 0x00, 0x01, 0x04, 0x02, 0xff, 0x01, 0xfc,
+ 0x01, 0x72, 0x01, 0x00, 0x01, 0x01, 0x01, 0x38, 0x01, 0xdf, 0x02, 0xff,
+ 0x01, 0x30, 0x08, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x50,
+ 0x04, 0x00, 0x01, 0x07, 0x02, 0xff, 0x01, 0xe2, 0x07, 0x00, 0x01, 0x01,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0xd1, 0x06, 0x00, 0x01, 0x2e, 0x01, 0xff,
+ 0x01, 0xfd, 0x07, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0x60, 0x06, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xf4, 0x08, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xe0,
+ 0x06, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xa0, 0x08, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf5, 0x06, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xfb, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xfd, 0x0a, 0x00, 0x02, 0xff, 0x05, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf9, 0x0a, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x30,
+ 0x04, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf5, 0x0a, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x50, 0x04, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf4,
+ 0x0a, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x70, 0x04, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xf2, 0x0a, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x80,
+ 0x04, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf2, 0x0a, 0x00, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf3,
+ 0x0a, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x80, 0x04, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf4, 0x0a, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x60,
+ 0x04, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf7, 0x0a, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x50, 0x04, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xfb,
+ 0x0a, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x10, 0x05, 0x00, 0x02, 0xff,
+ 0x01, 0x10, 0x08, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfd, 0x06, 0x00,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0x70, 0x08, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf8, 0x06, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xe1, 0x08, 0x00,
+ 0x01, 0x2f, 0x01, 0xff, 0x01, 0xf1, 0x06, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xfa, 0x08, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xa0, 0x06, 0x00,
+ 0x01, 0x04, 0x02, 0xff, 0x01, 0x80, 0x06, 0x00, 0x01, 0x0a, 0x01, 0xff,
+ 0x01, 0xfe, 0x01, 0x10, 0x07, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0x01, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xf5, 0x08, 0x00,
+ 0x01, 0x0b, 0x02, 0xff, 0x01, 0xe6, 0x01, 0x10, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0x8f, 0x02, 0xff, 0x01, 0x80, 0x09, 0x00, 0x01, 0xaf, 0x02, 0xff,
+ 0x01, 0xfc, 0x01, 0xa8, 0x01, 0x8a, 0x01, 0xdf, 0x02, 0xff, 0x01, 0xf6,
+ 0x0a, 0x00, 0x01, 0x06, 0x01, 0xef, 0x06, 0xff, 0x01, 0xfd, 0x01, 0x40,
+ 0x0b, 0x00, 0x01, 0x18, 0x01, 0xef, 0x04, 0xff, 0x01, 0xfd, 0x01, 0x60,
+ 0x0d, 0x00, 0x01, 0x03, 0x01, 0x7a, 0x01, 0xcd, 0x01, 0xdc, 0x01, 0xa7,
+ 0x01, 0x30, 0xbd, 0x00,
+
+ /* 15 */
+ 0xb5, 0x00, 0x01, 0x1f, 0x0b, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x0b, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x0b, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe6, 0x07, 0x66, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1e,
+ 0x01, 0xee, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9e, 0x01, 0xee, 0x01, 0x40,
+ 0xce, 0x00,
+
+ /* 16 */
+ 0xb5, 0x00, 0x01, 0x1e, 0x06, 0xee, 0x01, 0xec, 0x01, 0x95, 0x0b, 0x00,
+ 0x01, 0x1f, 0x08, 0xff, 0x01, 0xe5, 0x0a, 0x00, 0x01, 0x1f, 0x09, 0xff,
+ 0x01, 0x80, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd6, 0x03, 0x66,
+ 0x01, 0x67, 0x01, 0x9d, 0x02, 0xff, 0x01, 0xf5, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x4e, 0x01, 0xff, 0x01, 0xfe,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x03,
+ 0x02, 0xff, 0x01, 0x50, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x90, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xb0,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xc0, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xa0,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x70, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x05, 0x00, 0x01, 0x1b, 0x02, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc1, 0x03, 0x11, 0x01, 0x12, 0x01, 0x48, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xf9, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xc0,
+ 0x09, 0x00, 0x01, 0x1f, 0x08, 0xff, 0x01, 0xfb, 0x01, 0x10, 0x09, 0x00,
+ 0x01, 0x1f, 0x07, 0xff, 0x01, 0xfb, 0x01, 0x40, 0x0a, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd4, 0x04, 0x44, 0x01, 0x32, 0x0c, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xb0, 0xd8, 0x00,
+
+ /* 17 */
+ 0xa6, 0x00, 0x01, 0x35, 0x01, 0x66, 0x01, 0x54, 0x01, 0x10, 0x0e, 0x00,
+ 0x01, 0x06, 0x01, 0xcf, 0x03, 0xff, 0x01, 0xfd, 0x01, 0x71, 0x0c, 0x00,
+ 0x01, 0x05, 0x01, 0xef, 0x06, 0xff, 0x01, 0x60, 0x0b, 0x00, 0x01, 0xaf,
+ 0x07, 0xff, 0x01, 0xf8, 0x0a, 0x00, 0x01, 0x0a, 0x02, 0xff, 0x01, 0xd7,
+ 0x01, 0x20, 0x01, 0x00, 0x01, 0x03, 0x01, 0x9f, 0x02, 0xff, 0x01, 0x70,
+ 0x09, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x01,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0xf2, 0x08, 0x00, 0x01, 0x02, 0x02, 0xff,
+ 0x01, 0x60, 0x05, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfa, 0x08, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0x02, 0x02, 0xff,
+ 0x01, 0x10, 0x07, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00,
+ 0x01, 0xaf, 0x01, 0xff, 0x01, 0x60, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff,
+ 0x01, 0x60, 0x07, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x10, 0x07, 0x00, 0x01, 0x05, 0x01, 0x55,
+ 0x01, 0x40, 0x06, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xfb, 0x11, 0x00,
+ 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8, 0x11, 0x00, 0x01, 0x08, 0x01, 0xff,
+ 0x01, 0xf5, 0x11, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf3, 0x11, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf2, 0x11, 0x00, 0x01, 0x0b, 0x01, 0xff,
+ 0x01, 0xf2, 0x11, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf3, 0x11, 0x00,
+ 0x01, 0x09, 0x01, 0xff, 0x01, 0xf4, 0x11, 0x00, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xf6, 0x11, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xfa, 0x08, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf6, 0x06, 0x00, 0x01, 0x01, 0x01, 0xff,
+ 0x01, 0xfe, 0x08, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf3, 0x07, 0x00,
+ 0x01, 0xcf, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xf0, 0x07, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xb0, 0x07, 0x00,
+ 0x01, 0x7f, 0x01, 0xff, 0x01, 0xb0, 0x07, 0x00, 0x01, 0x1e, 0x01, 0xff,
+ 0x01, 0xf5, 0x07, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0x60, 0x07, 0x00,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x05, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10, 0x08, 0x00, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xe3, 0x05, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xf7, 0x09, 0x00,
+ 0x01, 0x3f, 0x02, 0xff, 0x01, 0x92, 0x03, 0x00, 0x01, 0x29, 0x02, 0xff,
+ 0x01, 0xc0, 0x09, 0x00, 0x01, 0x04, 0x03, 0xff, 0x01, 0xda, 0x01, 0x88,
+ 0x01, 0x9c, 0x02, 0xff, 0x01, 0xfe, 0x01, 0x10, 0x0a, 0x00, 0x01, 0x3d,
+ 0x07, 0xff, 0x01, 0xc1, 0x0c, 0x00, 0x01, 0x7e, 0x05, 0xff, 0x01, 0xd6,
+ 0x0e, 0x00, 0x01, 0x37, 0x01, 0xac, 0x01, 0xdd, 0x01, 0xca, 0x01, 0x73,
+ 0xbe, 0x00,
+
+ /* 18 */
+ 0xb4, 0x00, 0x01, 0x2f, 0x0b, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x2f,
+ 0x0b, 0xff, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x2f, 0x0b, 0xff, 0x01, 0xa0,
+ 0x07, 0x00, 0x01, 0x16, 0x04, 0x66, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xd6,
+ 0x04, 0x66, 0x01, 0x40, 0x0c, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x2e, 0x01, 0xee, 0x01, 0xa0, 0xd4, 0x00,
+
+ /* 19 */
+ 0xb4, 0x00, 0x01, 0x8e, 0x01, 0xee, 0x01, 0xe2, 0x07, 0x00, 0x01, 0xde,
+ 0x01, 0xee, 0x01, 0xa0, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xfa,
+ 0x06, 0x00, 0x01, 0x06, 0x02, 0xff, 0x01, 0x30, 0x07, 0x00, 0x01, 0x08,
+ 0x02, 0xff, 0x01, 0x20, 0x05, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xfa,
+ 0x08, 0x00, 0x01, 0x01, 0x02, 0xff, 0x01, 0x90, 0x05, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0xf2, 0x09, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xf2,
+ 0x05, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xa0, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x06, 0x02, 0xff, 0x01, 0x20,
+ 0x09, 0x00, 0x01, 0x08, 0x02, 0xff, 0x01, 0x20, 0x03, 0x00, 0x01, 0x0d,
+ 0x01, 0xff, 0x01, 0xfa, 0x0a, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xff,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00,
+ 0x01, 0x8f, 0x01, 0xff, 0x01, 0xf2, 0x03, 0x00, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0x90, 0x0b, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x05, 0x02, 0xff, 0x01, 0x20, 0x0b, 0x00, 0x01, 0x07, 0x02, 0xff,
+ 0x01, 0x20, 0x01, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf9, 0x0d, 0x00,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x90, 0x01, 0x00, 0x01, 0x5f, 0x01, 0xff,
+ 0x01, 0xf1, 0x0d, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xf2, 0x01, 0x00,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0x80, 0x0d, 0x00, 0x01, 0x0e, 0x01, 0xff,
+ 0x01, 0xf9, 0x01, 0x05, 0x02, 0xff, 0x01, 0x10, 0x0d, 0x00, 0x01, 0x07,
+ 0x02, 0xff, 0x01, 0x2d, 0x01, 0xff, 0x01, 0xf8, 0x0f, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xf1, 0x0f, 0x00, 0x01, 0x7f,
+ 0x03, 0xff, 0x01, 0x80, 0x0f, 0x00, 0x01, 0x0e, 0x02, 0xff, 0x01, 0xfe,
+ 0x01, 0x10, 0x0f, 0x00, 0x01, 0x06, 0x02, 0xff, 0x01, 0xf7, 0x11, 0x00,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0xe0, 0x10, 0x00, 0x01, 0x01, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x70, 0x10, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xfe,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xf6, 0x11, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0xe0, 0x10, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0x60,
+ 0x10, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xfe, 0x11, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0xf6, 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xd0,
+ 0x10, 0x00, 0x01, 0x05, 0x02, 0xff, 0x01, 0x50, 0x10, 0x00, 0x01, 0x0c,
+ 0x01, 0xee, 0x01, 0xec, 0xd7, 0x00,
+
+ /* 20 */
+ 0xbb, 0x00, 0x01, 0x0b, 0x01, 0xee, 0x01, 0xe2, 0x11, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf2, 0x11, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf2,
+ 0x10, 0x00, 0x01, 0x01, 0x01, 0x2d, 0x01, 0xff, 0x01, 0xf4, 0x01, 0x10,
+ 0x0d, 0x00, 0x01, 0x48, 0x01, 0xce, 0x05, 0xff, 0x01, 0xfd, 0x01, 0x96,
+ 0x01, 0x10, 0x09, 0x00, 0x01, 0x7d, 0x09, 0xff, 0x01, 0xfa, 0x01, 0x20,
+ 0x07, 0x00, 0x01, 0x2d, 0x0b, 0xff, 0x01, 0xf6, 0x06, 0x00, 0x01, 0x03,
+ 0x01, 0xef, 0x02, 0xff, 0x01, 0xfb, 0x01, 0x75, 0x01, 0x4d, 0x01, 0xff,
+ 0x01, 0xf6, 0x01, 0x56, 0x01, 0x9d, 0x03, 0xff, 0x01, 0x80, 0x05, 0x00,
+ 0x01, 0x1e, 0x02, 0xff, 0x01, 0xe6, 0x02, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x02, 0x00, 0x01, 0x3b, 0x02, 0xff, 0x01, 0xf5, 0x05, 0x00,
+ 0x01, 0x8f, 0x01, 0xff, 0x01, 0xfb, 0x01, 0x10, 0x02, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf2, 0x03, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xfe,
+ 0x05, 0x00, 0x02, 0xff, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x03, 0x00, 0x01, 0x07, 0x02, 0xff, 0x01, 0x50, 0x03, 0x00,
+ 0x01, 0x05, 0x02, 0xff, 0x01, 0x20, 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xb0, 0x03, 0x00,
+ 0x01, 0x08, 0x01, 0xff, 0x01, 0xfc, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xe0, 0x03, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xf0, 0x03, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf7, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xf1, 0x03, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf7, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xf1, 0x03, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xf0, 0x03, 0x00,
+ 0x01, 0x08, 0x01, 0xff, 0x01, 0xfc, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xe0, 0x03, 0x00,
+ 0x01, 0x05, 0x02, 0xff, 0x01, 0x30, 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xb0, 0x04, 0x00,
+ 0x02, 0xff, 0x01, 0xd1, 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf2,
+ 0x03, 0x00, 0x01, 0x08, 0x02, 0xff, 0x01, 0x60, 0x04, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0xfc, 0x01, 0x10, 0x02, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf2, 0x03, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xfe, 0x05, 0x00,
+ 0x01, 0x1e, 0x02, 0xff, 0x01, 0xf7, 0x01, 0x10, 0x01, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf2, 0x02, 0x00, 0x01, 0x4c, 0x02, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0x04, 0x03, 0xff, 0x01, 0xfb, 0x01, 0x86, 0x01, 0x5d,
+ 0x01, 0xff, 0x01, 0xf6, 0x01, 0x67, 0x01, 0xae, 0x03, 0xff, 0x01, 0xa0,
+ 0x06, 0x00, 0x01, 0x4e, 0x0b, 0xff, 0x01, 0xf8, 0x07, 0x00, 0x01, 0x01,
+ 0x01, 0x8e, 0x09, 0xff, 0x01, 0xfb, 0x01, 0x30, 0x09, 0x00, 0x01, 0x48,
+ 0x01, 0xbe, 0x05, 0xff, 0x01, 0xed, 0x01, 0xa6, 0x01, 0x10, 0x0d, 0x00,
+ 0x01, 0x1c, 0x01, 0xff, 0x01, 0xf3, 0x01, 0x10, 0x10, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf2, 0x11, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf2,
+ 0x11, 0x00, 0x01, 0x0b, 0x01, 0xee, 0x01, 0xe2, 0xd2, 0x00,
+
+ /* 21 */
+ 0xb4, 0x00, 0x01, 0x0b, 0x01, 0xee, 0x01, 0xec, 0x07, 0x00, 0x01, 0x2e,
+ 0x01, 0xee, 0x01, 0xe7, 0x07, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0x80,
+ 0x06, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xc0, 0x08, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0xf3, 0x05, 0x00, 0x01, 0x06, 0x02, 0xff, 0x01, 0x20,
+ 0x08, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xfd, 0x05, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xf6, 0x09, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xff,
+ 0x01, 0x80, 0x04, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xb0, 0x0a, 0x00,
+ 0x01, 0x5f, 0x01, 0xff, 0x01, 0xf3, 0x03, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xfe, 0x01, 0x10, 0x0a, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xfd,
+ 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xf5, 0x0b, 0x00, 0x01, 0x01,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x80, 0x02, 0x00, 0x01, 0xbf, 0x01, 0xff,
+ 0x01, 0x90, 0x0c, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xf3, 0x01, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xfd, 0x0d, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xfd, 0x01, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xf3, 0x0e, 0x00,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0x80, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x70,
+ 0x0e, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xf9, 0x01, 0xff, 0x01, 0xfc,
+ 0x0f, 0x00, 0x01, 0x08, 0x03, 0xff, 0x01, 0xf2, 0x10, 0x00, 0x01, 0xcf,
+ 0x02, 0xff, 0x01, 0x50, 0x10, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xfc,
+ 0x11, 0x00, 0x01, 0xaf, 0x02, 0xff, 0x01, 0x30, 0x0f, 0x00, 0x01, 0x05,
+ 0x03, 0xff, 0x01, 0xd0, 0x0f, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xfd,
+ 0x01, 0xff, 0x01, 0xf9, 0x0f, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x91,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x50, 0x0d, 0x00, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xfd, 0x01, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xe1, 0x0d, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0xf3, 0x01, 0x00, 0x01, 0x0b, 0x01, 0xff,
+ 0x01, 0xfb, 0x0d, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x80, 0x01, 0x00,
+ 0x01, 0x01, 0x02, 0xff, 0x01, 0x60, 0x0b, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xfd, 0x03, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00,
+ 0x01, 0x4f, 0x01, 0xff, 0x01, 0xf3, 0x03, 0x00, 0x01, 0x0b, 0x01, 0xff,
+ 0x01, 0xfc, 0x0a, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xff, 0x01, 0x80,
+ 0x03, 0x00, 0x01, 0x01, 0x02, 0xff, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0a,
+ 0x01, 0xff, 0x01, 0xfd, 0x05, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xf4,
+ 0x09, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xf3, 0x05, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10, 0x07, 0x00, 0x01, 0x02, 0x02, 0xff,
+ 0x01, 0x80, 0x05, 0x00, 0x01, 0x01, 0x02, 0xff, 0x01, 0xa0, 0x07, 0x00,
+ 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfd, 0x07, 0x00, 0x01, 0x6f, 0x01, 0xff,
+ 0x01, 0xf5, 0x07, 0x00, 0x01, 0x6e, 0x01, 0xee, 0x01, 0xe3, 0x07, 0x00,
+ 0x01, 0x0b, 0x01, 0xee, 0x01, 0xed, 0x01, 0x10, 0xce, 0x00,
+
+ /* 22 */
+ 0xb5, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xc0, 0x07, 0x00, 0x01, 0x9e,
+ 0x01, 0xee, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x07, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xe6, 0x07, 0x66, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x51,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0x1f, 0x0c, 0xff, 0x01, 0xf1, 0x06, 0x00,
+ 0x01, 0x1f, 0x0c, 0xff, 0x01, 0xf1, 0x06, 0x00, 0x01, 0x1f, 0x0c, 0xff,
+ 0x01, 0xf1, 0x11, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf1, 0x11, 0x00,
+ 0x01, 0x03, 0x01, 0xff, 0x01, 0xf1, 0x11, 0x00, 0x01, 0x03, 0x01, 0xff,
+ 0x01, 0xf1, 0x11, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf1, 0x11, 0x00,
+ 0x01, 0x03, 0x01, 0xff, 0x01, 0xf1, 0x11, 0x00, 0x01, 0x01, 0x01, 0x77,
+ 0x01, 0x70, 0x55, 0x00,
+
+ /* 23 */
+ 0xb4, 0x00, 0x01, 0x04, 0x01, 0xee, 0x01, 0xe8, 0x06, 0x00, 0x01, 0xbe,
+ 0x01, 0xee, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8,
+ 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8,
+ 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8,
+ 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf8,
+ 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x10, 0x08, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xfa,
+ 0x06, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x09, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x40, 0x05, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x09, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xfd, 0x01, 0xba, 0x04, 0xaa,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0x10, 0x09, 0x00, 0x01, 0x0b, 0x09, 0xff,
+ 0x01, 0x10, 0x0a, 0x00, 0x01, 0x8f, 0x08, 0xff, 0x01, 0x10, 0x0a, 0x00,
+ 0x01, 0x01, 0x01, 0x69, 0x05, 0xaa, 0x01, 0xef, 0x01, 0xff, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x11, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x10, 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x11, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x10, 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x11, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x10, 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x10, 0x11, 0x00, 0x01, 0xbe,
+ 0x01, 0xee, 0x01, 0x10, 0xd0, 0x00,
+
+ /* 24 */
+ 0xb5, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x1e,
+ 0x01, 0xee, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xc0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe6, 0x03, 0x66, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0xe6, 0x03, 0x66, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x0d, 0xff, 0x01, 0xd0, 0x05, 0x00, 0x01, 0x1f,
+ 0x0d, 0xff, 0x01, 0xd0, 0x05, 0x00, 0x01, 0x1f, 0x0d, 0xff, 0x01, 0xc0,
+ 0xcc, 0x00,
+
+ /* 25 */
+ 0xb5, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x1e,
+ 0x01, 0xee, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xc0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe6, 0x03, 0x66, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0xe6, 0x03, 0x66, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xd1,
+ 0x01, 0x10, 0x04, 0x00, 0x01, 0x1f, 0x0e, 0xff, 0x01, 0xfa, 0x04, 0x00,
+ 0x01, 0x1f, 0x0e, 0xff, 0x01, 0xfa, 0x04, 0x00, 0x01, 0x1f, 0x0e, 0xff,
+ 0x01, 0xfa, 0x12, 0x00, 0x01, 0xbf, 0x01, 0xfa, 0x12, 0x00, 0x01, 0xbf,
+ 0x01, 0xfa, 0x12, 0x00, 0x01, 0xbf, 0x01, 0xfa, 0x12, 0x00, 0x01, 0xbf,
+ 0x01, 0xfa, 0x12, 0x00, 0x01, 0xbf, 0x01, 0xfa, 0x12, 0x00, 0x01, 0x57,
+ 0x01, 0x74, 0x53, 0x00,
+
+ /* 26 */
+ 0xb5, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe8,
+ 0x03, 0x88, 0x01, 0x76, 0x01, 0x53, 0x0c, 0x00, 0x01, 0x1f, 0x07, 0xff,
+ 0x01, 0xfb, 0x01, 0x50, 0x0a, 0x00, 0x01, 0x1f, 0x08, 0xff, 0x01, 0xfd,
+ 0x01, 0x30, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xfc, 0x03, 0xcc,
+ 0x01, 0xcd, 0x01, 0xef, 0x02, 0xff, 0x01, 0xf5, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x04, 0x00, 0x01, 0x01, 0x01, 0x7e, 0x02, 0xff,
+ 0x01, 0x20, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xb0, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xf6, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf8, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xf9,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf8, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x06, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf6, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf2,
+ 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0xaf,
+ 0x01, 0xff, 0x01, 0xc0, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x05, 0x00, 0x01, 0x1a, 0x02, 0xff, 0x01, 0x40, 0x08, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd6, 0x04, 0x66, 0x01, 0x7b, 0x02, 0xff, 0x01, 0xf9,
+ 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xa0, 0x09, 0x00, 0x01, 0x1f,
+ 0x08, 0xff, 0x01, 0xe6, 0x0a, 0x00, 0x01, 0x1e, 0x06, 0xee, 0x01, 0xed,
+ 0x01, 0xa5, 0xd2, 0x00,
+
+ /* 27 */
+ 0xb5, 0x00, 0x01, 0x1e, 0x01, 0xee, 0x01, 0xb0, 0x0a, 0x00, 0x01, 0x3e,
+ 0x01, 0xee, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0,
+ 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0,
+ 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0,
+ 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xe8, 0x03, 0x88, 0x01, 0x76, 0x01, 0x52, 0x05, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x07, 0xff,
+ 0x01, 0xfb, 0x01, 0x50, 0x03, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0,
+ 0x04, 0x00, 0x01, 0x1f, 0x08, 0xff, 0x01, 0xfd, 0x01, 0x30, 0x02, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xfd, 0x04, 0xdd, 0x01, 0xef, 0x02, 0xff, 0x01, 0xf5, 0x02, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x04, 0x00, 0x01, 0x01, 0x01, 0x7e, 0x02, 0xff, 0x01, 0x20,
+ 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x02, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xb0, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x3f, 0x01, 0xff,
+ 0x01, 0xf1, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x0b, 0x01, 0xff,
+ 0x01, 0xf6, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf8, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x04, 0x01, 0xff,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x05, 0x01, 0xff,
+ 0x01, 0xf8, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf6, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0x0e, 0x01, 0xff,
+ 0x01, 0xf2, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x06, 0x00, 0x01, 0xaf, 0x01, 0xff,
+ 0x01, 0xc0, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x1a, 0x02, 0xff,
+ 0x01, 0x40, 0x01, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd6, 0x04, 0x66, 0x01, 0x7a, 0x02, 0xff,
+ 0x01, 0xf9, 0x02, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00,
+ 0x01, 0x1f, 0x09, 0xff, 0x01, 0xa0, 0x02, 0x00, 0x01, 0x3f, 0x01, 0xff,
+ 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1f, 0x08, 0xff, 0x01, 0xe6, 0x03, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x1e, 0x06, 0xee,
+ 0x01, 0xed, 0x01, 0xa5, 0x04, 0x00, 0x01, 0x3e, 0x01, 0xee, 0x01, 0xa0,
+ 0xcb, 0x00,
+
+ /* 28 */
+ 0xb4, 0x00, 0x01, 0x2e, 0x06, 0xee, 0x01, 0x50, 0x0c, 0x00, 0x01, 0x2f,
+ 0x06, 0xff, 0x01, 0x50, 0x0c, 0x00, 0x01, 0x2f, 0x06, 0xff, 0x01, 0x50,
+ 0x0c, 0x00, 0x01, 0x17, 0x04, 0x77, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x50,
+ 0x11, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50,
+ 0x11, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50,
+ 0x11, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0xb8, 0x03, 0x88, 0x01, 0x76, 0x01, 0x41, 0x0c, 0x00,
+ 0x01, 0x8f, 0x07, 0xff, 0x01, 0xe8, 0x01, 0x20, 0x0a, 0x00, 0x01, 0x8f,
+ 0x08, 0xff, 0x01, 0xf9, 0x0a, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xed,
+ 0x04, 0xdd, 0x03, 0xff, 0x01, 0xc0, 0x09, 0x00, 0x01, 0x8f, 0x01, 0xff,
+ 0x01, 0x50, 0x04, 0x00, 0x01, 0x03, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xfb,
+ 0x09, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x05, 0x00, 0x01, 0x07,
+ 0x02, 0xff, 0x01, 0x40, 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xa0, 0x08, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x50, 0x06, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xe0,
+ 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xb0, 0x08, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x50, 0x05, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0x50,
+ 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x05, 0x00, 0x01, 0x4e,
+ 0x01, 0xff, 0x01, 0xfd, 0x09, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x96,
+ 0x04, 0x66, 0x01, 0x8d, 0x02, 0xff, 0x01, 0xf3, 0x09, 0x00, 0x01, 0x8f,
+ 0x08, 0xff, 0x01, 0xfe, 0x01, 0x40, 0x09, 0x00, 0x01, 0x8f, 0x08, 0xff,
+ 0x01, 0xb2, 0x0a, 0x00, 0x01, 0x7e, 0x06, 0xee, 0x01, 0xec, 0x01, 0x83,
+ 0xce, 0x00,
+
+ /* 29 */
+ 0xa5, 0x00, 0x01, 0x14, 0x01, 0x56, 0x01, 0x54, 0x01, 0x20, 0x0e, 0x00,
+ 0x01, 0x02, 0x01, 0x8e, 0x03, 0xff, 0x01, 0xfe, 0x01, 0xa4, 0x0d, 0x00,
+ 0x01, 0x8f, 0x06, 0xff, 0x01, 0xc2, 0x0b, 0x00, 0x01, 0x0c, 0x08, 0xff,
+ 0x01, 0x50, 0x0a, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xfd, 0x01, 0x73,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0x49, 0x02, 0xff, 0x01, 0xf6, 0x09, 0x00,
+ 0x01, 0x05, 0x02, 0xff, 0x01, 0x80, 0x04, 0x00, 0x01, 0x2c, 0x02, 0xff,
+ 0x01, 0x30, 0x08, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf8, 0x06, 0x00,
+ 0x01, 0xaf, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00, 0x01, 0x5f, 0x01, 0xff,
+ 0x01, 0xd0, 0x06, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf6, 0x08, 0x00,
+ 0x01, 0xaf, 0x01, 0xff, 0x01, 0x60, 0x06, 0x00, 0x01, 0x03, 0x01, 0xff,
+ 0x01, 0xfe, 0x08, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0x10, 0x07, 0x00,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0x40, 0x07, 0x00, 0x01, 0x55, 0x01, 0x54,
+ 0x08, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x90, 0x11, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf1,
+ 0x11, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf4, 0x0a, 0x00, 0x01, 0xbf,
+ 0x08, 0xff, 0x01, 0xf5, 0x0a, 0x00, 0x01, 0xbf, 0x08, 0xff, 0x01, 0xf6,
+ 0x0a, 0x00, 0x01, 0xbf, 0x08, 0xff, 0x01, 0xf7, 0x0a, 0x00, 0x01, 0x35,
+ 0x06, 0x55, 0x01, 0x5a, 0x01, 0xff, 0x01, 0xf6, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xf5, 0x11, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf3,
+ 0x06, 0x00, 0x01, 0x09, 0x01, 0xee, 0x01, 0xe5, 0x08, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xf0, 0x06, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf8,
+ 0x08, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xd0, 0x06, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xfd, 0x08, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x70,
+ 0x06, 0x00, 0x01, 0x01, 0x02, 0xff, 0x01, 0x20, 0x07, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x20, 0x07, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x90,
+ 0x06, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfb, 0x08, 0x00, 0x01, 0x5f,
+ 0x01, 0xff, 0x01, 0xf3, 0x06, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xf3,
+ 0x08, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x04, 0x00,
+ 0x01, 0x06, 0x02, 0xff, 0x01, 0xa0, 0x08, 0x00, 0x01, 0x03, 0x02, 0xff,
+ 0x01, 0xe6, 0x03, 0x00, 0x01, 0x03, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xfd,
+ 0x0a, 0x00, 0x01, 0x5f, 0x02, 0xff, 0x01, 0xfb, 0x01, 0x87, 0x01, 0x8a,
+ 0x01, 0xef, 0x02, 0xff, 0x01, 0xd1, 0x0a, 0x00, 0x01, 0x04, 0x01, 0xef,
+ 0x06, 0xff, 0x01, 0xfb, 0x01, 0x10, 0x0b, 0x00, 0x01, 0x19, 0x05, 0xff,
+ 0x01, 0xfc, 0x01, 0x50, 0x0d, 0x00, 0x01, 0x15, 0x01, 0x9b, 0x01, 0xde,
+ 0x01, 0xdc, 0x01, 0xa7, 0x01, 0x20, 0xbe, 0x00,
+
+ /* 30 */
+ 0xab, 0x00, 0x01, 0x13, 0x01, 0x56, 0x01, 0x54, 0x01, 0x20, 0x06, 0x00,
+ 0x01, 0x1e, 0x01, 0xee, 0x01, 0xb0, 0x05, 0x00, 0x01, 0x02, 0x01, 0x8d,
+ 0x03, 0xff, 0x01, 0xfe, 0x01, 0x93, 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x04, 0x00, 0x01, 0x01, 0x01, 0x9f, 0x06, 0xff, 0x01, 0xb2,
+ 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x04, 0x00, 0x01, 0x3e,
+ 0x08, 0xff, 0x01, 0x50, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0,
+ 0x03, 0x00, 0x01, 0x03, 0x02, 0xff, 0x01, 0xfc, 0x01, 0x62, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0x6b, 0x02, 0xff, 0x01, 0xf6, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x03, 0x00, 0x01, 0x1e, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0x40, 0x04, 0x00, 0x01, 0x3d, 0x02, 0xff, 0x01, 0x30, 0x02, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xff,
+ 0x01, 0xd1, 0x05, 0x00, 0x01, 0x01, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xd0,
+ 0x02, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0x04,
+ 0x02, 0xff, 0x01, 0x10, 0x06, 0x00, 0x01, 0x1e, 0x01, 0xff, 0x01, 0xf7,
+ 0x02, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf6, 0x07, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xfd,
+ 0x02, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xe0, 0x08, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x40,
+ 0x01, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0x80, 0x08, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x90,
+ 0x01, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x20, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x01, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x02, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x09, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf0, 0x01, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x01, 0x00, 0x01, 0x01, 0x01, 0xff,
+ 0x01, 0xfc, 0x09, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf3, 0x01, 0x00,
+ 0x01, 0x1f, 0x05, 0xff, 0x01, 0xfb, 0x09, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf4, 0x01, 0x00, 0x01, 0x1f, 0x05, 0xff, 0x01, 0xfa, 0x09, 0x00,
+ 0x01, 0x08, 0x01, 0xff, 0x01, 0xf5, 0x01, 0x00, 0x01, 0x1f, 0x05, 0xff,
+ 0x01, 0xf9, 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf5, 0x01, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe5, 0x01, 0x55, 0x01, 0x57, 0x01, 0xff,
+ 0x01, 0xfa, 0x09, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf4, 0x01, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x01, 0x00, 0x01, 0x01, 0x01, 0xff,
+ 0x01, 0xfb, 0x09, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf3, 0x01, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0xff, 0x01, 0xfd,
+ 0x09, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf1, 0x01, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xe0, 0x01, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x50,
+ 0x08, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xa0, 0x01, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xb0,
+ 0x08, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x50, 0x01, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf2,
+ 0x07, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xfe, 0x02, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xfb,
+ 0x07, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf6, 0x02, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0x01, 0x02, 0xff, 0x01, 0x70,
+ 0x06, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xd0, 0x02, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xf7,
+ 0x05, 0x00, 0x01, 0x06, 0x02, 0xff, 0x01, 0x30, 0x02, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x09, 0x02, 0xff, 0x01, 0xc4,
+ 0x03, 0x00, 0x01, 0x03, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xf6, 0x03, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x04, 0x00, 0x01, 0x9f, 0x02, 0xff,
+ 0x01, 0xea, 0x01, 0x87, 0x01, 0x8a, 0x01, 0xef, 0x02, 0xff, 0x01, 0x50,
+ 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x04, 0x00, 0x01, 0x06,
+ 0x07, 0xff, 0x01, 0xd4, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0,
+ 0x05, 0x00, 0x01, 0x19, 0x05, 0xff, 0x01, 0xe7, 0x0e, 0x00, 0x01, 0x04,
+ 0x01, 0x9b, 0x01, 0xce, 0x01, 0xdc, 0x01, 0x95, 0xb9, 0x00,
+
+ /* 31 */
+ 0xb7, 0x00, 0x01, 0x04, 0x01, 0x9c, 0x01, 0xde, 0x06, 0xee, 0x01, 0xc0,
+ 0x09, 0x00, 0x01, 0x04, 0x01, 0xdf, 0x08, 0xff, 0x01, 0xd0, 0x09, 0x00,
+ 0x01, 0x6f, 0x09, 0xff, 0x01, 0xd0, 0x08, 0x00, 0x01, 0x04, 0x02, 0xff,
+ 0x01, 0xfb, 0x01, 0x87, 0x04, 0x77, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xd0,
+ 0x08, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xfc, 0x01, 0x20, 0x05, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00, 0x01, 0x4f, 0x01, 0xff,
+ 0x01, 0xe1, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00,
+ 0x01, 0x9f, 0x01, 0xff, 0x01, 0x60, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xd0, 0x08, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x30, 0x06, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00, 0x01, 0xcf, 0x01, 0xff,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00,
+ 0x01, 0xaf, 0x01, 0xff, 0x01, 0x20, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xd0, 0x08, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xfa, 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xd0, 0x08, 0x00, 0x01, 0x02, 0x01, 0xef, 0x01, 0xff, 0x01, 0xe8,
+ 0x01, 0x54, 0x04, 0x44, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xd0, 0x09, 0x00,
+ 0x01, 0x4f, 0x09, 0xff, 0x01, 0xd0, 0x09, 0x00, 0x01, 0x03, 0x01, 0xdf,
+ 0x08, 0xff, 0x01, 0xd0, 0x0a, 0x00, 0x01, 0x05, 0x01, 0xae, 0x07, 0xff,
+ 0x01, 0xd0, 0x0c, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x32,
+ 0x01, 0x22, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xd0, 0x0c, 0x00, 0x01, 0xaf,
+ 0x01, 0xff, 0x01, 0xe2, 0x02, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0,
+ 0x0b, 0x00, 0x01, 0x08, 0x02, 0xff, 0x01, 0x30, 0x02, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xd0, 0x0b, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xf5,
+ 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x0a, 0x00, 0x01, 0x04,
+ 0x02, 0xff, 0x01, 0x60, 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0,
+ 0x0a, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xf7, 0x04, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xd0, 0x09, 0x00, 0x01, 0x02, 0x01, 0xef, 0x01, 0xff,
+ 0x01, 0x90, 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x09, 0x00,
+ 0x01, 0x1d, 0x01, 0xff, 0x01, 0xfb, 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xd0, 0x09, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x08, 0x00, 0x01, 0x0b, 0x01, 0xff,
+ 0x01, 0xfd, 0x01, 0x10, 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0,
+ 0x08, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xe1, 0x06, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x07, 0x02, 0xff, 0x01, 0x20,
+ 0x06, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0, 0x07, 0x00, 0x01, 0x5f,
+ 0x01, 0xff, 0x01, 0xf4, 0x07, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xd0,
+ 0xcf, 0x00,
+
+ /* 32 */
+ 0xff, 0x00, 0x45, 0x00, 0x01, 0x01, 0x01, 0x11, 0x10, 0x00, 0x01, 0x02,
+ 0x01, 0x8d, 0x02, 0xff, 0x01, 0xfd, 0x01, 0x93, 0x0e, 0x00, 0x01, 0x9f,
+ 0x05, 0xff, 0x01, 0xb0, 0x0c, 0x00, 0x01, 0x0b, 0x06, 0xff, 0x01, 0xfb,
+ 0x0c, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xf8, 0x01, 0x42, 0x01, 0x12,
+ 0x01, 0x4a, 0x02, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0xcf, 0x01, 0xff,
+ 0x01, 0x30, 0x03, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x90, 0x0b, 0x00,
+ 0x01, 0xff, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xb0,
+ 0x0a, 0x00, 0x01, 0x02, 0x01, 0xdd, 0x01, 0xd5, 0x04, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xc0,
+ 0x11, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xc0, 0x0e, 0x00, 0x01, 0x02,
+ 0x01, 0x57, 0x01, 0xad, 0x02, 0xff, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x16,
+ 0x01, 0xad, 0x05, 0xff, 0x01, 0xc0, 0x0b, 0x00, 0x01, 0x09, 0x04, 0xff,
+ 0x01, 0xfe, 0x01, 0x9d, 0x01, 0xff, 0x01, 0xc0, 0x0b, 0x00, 0x01, 0xcf,
+ 0x02, 0xff, 0x01, 0xc9, 0x01, 0x64, 0x01, 0x10, 0x01, 0x0b, 0x01, 0xff,
+ 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x71,
+ 0x03, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xf2, 0x04, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xc0,
+ 0x0a, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x70,
+ 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xc0,
+ 0x0a, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf2, 0x03, 0x00, 0x01, 0x0a,
+ 0x02, 0xff, 0x01, 0xc0, 0x0a, 0x00, 0x01, 0x07, 0x02, 0xff, 0x01, 0x83,
+ 0x01, 0x12, 0x01, 0x48, 0x01, 0xef, 0x02, 0xff, 0x01, 0xf4, 0x0b, 0x00,
+ 0x01, 0xcf, 0x05, 0xff, 0x01, 0x76, 0x02, 0xff, 0x01, 0xf6, 0x0a, 0x00,
+ 0x01, 0x1b, 0x04, 0xff, 0x01, 0xc3, 0x01, 0x01, 0x01, 0xef, 0x01, 0xff,
+ 0x01, 0xf6, 0x0b, 0x00, 0x01, 0x39, 0x01, 0xce, 0x01, 0xdc, 0x01, 0x94,
+ 0x02, 0x00, 0x01, 0x2a, 0x01, 0xde, 0x01, 0xb3, 0xbd, 0x00,
+
+ /* 33 */
+ 0x93, 0x00, 0x01, 0x03, 0x01, 0xcc, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xd0, 0x10, 0x00, 0x01, 0x26, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xa0, 0x0d, 0x00, 0x01, 0x02, 0x01, 0x69, 0x01, 0xbe, 0x03, 0xff,
+ 0x01, 0x40, 0x0c, 0x00, 0x01, 0x02, 0x01, 0xcf, 0x04, 0xff, 0x01, 0xf6,
+ 0x0d, 0x00, 0x01, 0x3f, 0x03, 0xff, 0x01, 0xfe, 0x01, 0xa6, 0x01, 0x10,
+ 0x0d, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xfc, 0x01, 0x85, 0x01, 0x10,
+ 0x0e, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf6, 0x11, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x40, 0x11, 0x00, 0x01, 0x7f, 0x01, 0xf7, 0x02, 0x00,
+ 0x01, 0x10, 0x0f, 0x00, 0x01, 0xdf, 0x01, 0xe0, 0x01, 0x3a, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xfb, 0x01, 0x71, 0x0c, 0x00, 0x01, 0x01, 0x01, 0xff,
+ 0x01, 0x99, 0x04, 0xff, 0x01, 0xfe, 0x01, 0x60, 0x0b, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xdf, 0x05, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x08,
+ 0x02, 0xff, 0x01, 0xfe, 0x01, 0x72, 0x01, 0x11, 0x01, 0x5b, 0x02, 0xff,
+ 0x01, 0x50, 0x0a, 0x00, 0x01, 0x0b, 0x02, 0xff, 0x01, 0xc1, 0x03, 0x00,
+ 0x01, 0x7f, 0x01, 0xff, 0x01, 0xe1, 0x0a, 0x00, 0x01, 0x0d, 0x01, 0xff,
+ 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf7,
+ 0x0a, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xf6, 0x04, 0x00, 0x01, 0x01,
+ 0x01, 0xff, 0x01, 0xfd, 0x0a, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xf1,
+ 0x05, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x10, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x90, 0x05, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x80,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80, 0x09, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x70, 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80, 0x05, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf1, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x10, 0x09, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf8,
+ 0x04, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfd, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x20, 0x03, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf6,
+ 0x0b, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xe3, 0x03, 0x00, 0x01, 0xaf,
+ 0x01, 0xff, 0x01, 0xd0, 0x0b, 0x00, 0x01, 0x0c, 0x02, 0xff, 0x01, 0xa6,
+ 0x01, 0x45, 0x01, 0x8e, 0x02, 0xff, 0x01, 0x30, 0x0b, 0x00, 0x01, 0x01,
+ 0x01, 0xcf, 0x05, 0xff, 0x01, 0xf5, 0x0d, 0x00, 0x01, 0x08, 0x04, 0xff,
+ 0x01, 0xfc, 0x01, 0x30, 0x0e, 0x00, 0x01, 0x16, 0x01, 0xac, 0x01, 0xed,
+ 0x01, 0xc8, 0x01, 0x30, 0xc0, 0x00,
+
+ /* 34 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x04, 0x77, 0x01, 0x63, 0x0e, 0x00,
+ 0x01, 0xef, 0x05, 0xff, 0x01, 0xd5, 0x0d, 0x00, 0x01, 0xef, 0x06, 0xff,
+ 0x01, 0x60, 0x0c, 0x00, 0x01, 0xef, 0x01, 0xfd, 0x02, 0x99, 0x01, 0xac,
+ 0x02, 0xff, 0x01, 0xf1, 0x0c, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00,
+ 0x01, 0x2d, 0x01, 0xff, 0x01, 0xf5, 0x0c, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x03, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf8, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x04, 0x00, 0x01, 0xff, 0x01, 0xf7, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x03, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x0c, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x2d, 0x01, 0xff, 0x01, 0xe0,
+ 0x0c, 0x00, 0x01, 0xef, 0x01, 0xfd, 0x02, 0x99, 0x01, 0xac, 0x02, 0xff,
+ 0x01, 0x40, 0x0c, 0x00, 0x01, 0xef, 0x05, 0xff, 0x01, 0xf3, 0x0d, 0x00,
+ 0x01, 0xef, 0x05, 0xff, 0x01, 0xfe, 0x01, 0x60, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xfc, 0x03, 0x88, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xf8, 0x0c, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x02, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0x30, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x5f,
+ 0x01, 0xff, 0x01, 0x70, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00,
+ 0x01, 0x2f, 0x01, 0xff, 0x01, 0x90, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x04, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0x90, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x04, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x70, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xfa, 0x03, 0x22, 0x01, 0x4b, 0x02, 0xff, 0x01, 0x10,
+ 0x0b, 0x00, 0x01, 0xef, 0x06, 0xff, 0x01, 0xf8, 0x0c, 0x00, 0x01, 0xef,
+ 0x06, 0xff, 0x01, 0x80, 0x0c, 0x00, 0x01, 0xef, 0x04, 0xff, 0x01, 0xfd,
+ 0x01, 0x93, 0xd4, 0x00,
+
+ /* 35 */
+ 0xff, 0x00, 0x56, 0x00, 0x06, 0x77, 0x01, 0x70, 0x0d, 0x00, 0x01, 0xef,
+ 0x05, 0xff, 0x01, 0xf0, 0x0d, 0x00, 0x01, 0xef, 0x05, 0xff, 0x01, 0xf0,
+ 0x0d, 0x00, 0x01, 0xef, 0x01, 0xfd, 0x04, 0x99, 0x01, 0x90, 0x0d, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0xd9, 0x00,
+
+ /* 36 */
+ 0xff, 0x00, 0x58, 0x00, 0x01, 0x57, 0x06, 0x77, 0x01, 0x20, 0x0c, 0x00,
+ 0x01, 0xcf, 0x06, 0xff, 0x01, 0x50, 0x0c, 0x00, 0x01, 0xdf, 0x06, 0xff,
+ 0x01, 0x50, 0x0c, 0x00, 0x01, 0xdf, 0x01, 0xfd, 0x03, 0x99, 0x01, 0xaf,
+ 0x01, 0xff, 0x01, 0x50, 0x0c, 0x00, 0x01, 0xdf, 0x01, 0xfa, 0x03, 0x00,
+ 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50, 0x0c, 0x00, 0x01, 0xef, 0x01, 0xfa,
+ 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xfa, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50, 0x0c, 0x00,
+ 0x01, 0xef, 0x01, 0xfa, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50,
+ 0x0c, 0x00, 0x01, 0xff, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff,
+ 0x01, 0x50, 0x0c, 0x00, 0x01, 0xff, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xf8,
+ 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf6, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50,
+ 0x0b, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xf5, 0x03, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf3,
+ 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf0, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50,
+ 0x0b, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0x30, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x50,
+ 0x0a, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xfd, 0x04, 0x22, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0x50, 0x09, 0x00, 0x01, 0x6a, 0x01, 0xae, 0x08, 0xff,
+ 0x01, 0xca, 0x01, 0xa0, 0x08, 0x00, 0x01, 0x9f, 0x0a, 0xff, 0x01, 0xf0,
+ 0x08, 0x00, 0x01, 0x9f, 0x0a, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x9f,
+ 0x01, 0xf5, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x9f,
+ 0x01, 0xf5, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x9f,
+ 0x01, 0xf5, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x9f,
+ 0x01, 0xf5, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf0, 0x08, 0x00, 0x01, 0x8e,
+ 0x01, 0xe5, 0x08, 0x00, 0x01, 0xde, 0x01, 0xe0, 0x6c, 0x00,
+
+ /* 37 */
+ 0xff, 0x00, 0x58, 0x00, 0x01, 0x28, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xfc,
+ 0x01, 0x71, 0x0e, 0x00, 0x01, 0x09, 0x05, 0xff, 0x01, 0x60, 0x0c, 0x00,
+ 0x01, 0x01, 0x01, 0xcf, 0x05, 0xff, 0x01, 0xf8, 0x0c, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0x73, 0x01, 0x11, 0x01, 0x5b, 0x02, 0xff,
+ 0x01, 0x50, 0x0b, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xc1, 0x03, 0x00,
+ 0x01, 0x5f, 0x01, 0xff, 0x01, 0xe0, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xfe,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf6, 0x0a, 0x00,
+ 0x01, 0x05, 0x01, 0xff, 0x01, 0xf5, 0x05, 0x00, 0x01, 0xdf, 0x01, 0xfc,
+ 0x0a, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xe0, 0x05, 0x00, 0x01, 0x7f,
+ 0x01, 0xff, 0x0a, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xb0, 0x05, 0x00,
+ 0x01, 0x4f, 0x01, 0xff, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xc6, 0x05, 0x66, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x60, 0x09, 0x00,
+ 0x01, 0x1f, 0x09, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x2f, 0x09, 0xff,
+ 0x01, 0x80, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xb6, 0x07, 0x66,
+ 0x01, 0x30, 0x09, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x80, 0x11, 0x00,
+ 0x01, 0x0e, 0x01, 0xff, 0x01, 0xb0, 0x11, 0x00, 0x01, 0x0a, 0x01, 0xff,
+ 0x01, 0xf0, 0x05, 0x00, 0x01, 0x48, 0x01, 0x88, 0x0a, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xef, 0x01, 0xfc, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xd2, 0x03, 0x00,
+ 0x01, 0x6f, 0x01, 0xff, 0x01, 0xe1, 0x0b, 0x00, 0x01, 0x0c, 0x02, 0xff,
+ 0x01, 0xa6, 0x01, 0x45, 0x01, 0x7c, 0x02, 0xff, 0x01, 0x50, 0x0b, 0x00,
+ 0x01, 0x01, 0x01, 0xcf, 0x05, 0xff, 0x01, 0xf6, 0x0d, 0x00, 0x01, 0x08,
+ 0x04, 0xff, 0x01, 0xfd, 0x01, 0x40, 0x0e, 0x00, 0x01, 0x16, 0x01, 0xad,
+ 0x01, 0xee, 0x01, 0xc9, 0x01, 0x40, 0xc0, 0x00,
+
+ /* 38 */
+ 0xff, 0x00, 0x55, 0x00, 0x01, 0x03, 0x02, 0x77, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0x77, 0x01, 0x71, 0x03, 0x00, 0x01, 0x06, 0x01, 0x77, 0x01, 0x73,
+ 0x06, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xb0, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xb0,
+ 0x06, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xfb, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf4, 0x02, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xfb,
+ 0x08, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xa0, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf4, 0x02, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xc0,
+ 0x08, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xfa, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf4, 0x01, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfc,
+ 0x0a, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0xa0, 0x01, 0x03, 0x01, 0xff,
+ 0x01, 0xf4, 0x01, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xc0, 0x0a, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf9, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf4,
+ 0x01, 0x08, 0x01, 0xff, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0xbf, 0x01, 0xff,
+ 0x01, 0x93, 0x01, 0xff, 0x01, 0xf4, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xc1,
+ 0x0c, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfb, 0x01, 0xff, 0x01, 0xfb,
+ 0x01, 0xff, 0x01, 0xfc, 0x01, 0x10, 0x0d, 0x00, 0x01, 0xcf, 0x04, 0xff,
+ 0x01, 0xd1, 0x0e, 0x00, 0x01, 0x0d, 0x03, 0xff, 0x01, 0xfd, 0x01, 0x10,
+ 0x0e, 0x00, 0x01, 0x5f, 0x04, 0xff, 0x01, 0x60, 0x0d, 0x00, 0x01, 0x05,
+ 0x05, 0xff, 0x01, 0xf6, 0x0d, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xe5,
+ 0x01, 0xff, 0x01, 0xf5, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x60, 0x0b, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x23, 0x01, 0xff, 0x01, 0xf4,
+ 0x01, 0x1d, 0x01, 0xff, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0x6f, 0x01, 0xff,
+ 0x01, 0xe2, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf4, 0x01, 0x01, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xfd,
+ 0x01, 0x20, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf4, 0x01, 0x00, 0x01, 0x1d,
+ 0x01, 0xff, 0x01, 0xf7, 0x09, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xd1,
+ 0x01, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf4, 0x01, 0x00, 0x01, 0x01,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0x70, 0x07, 0x00, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xfd, 0x01, 0x10, 0x01, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf4,
+ 0x02, 0x00, 0x01, 0x1c, 0x01, 0xff, 0x01, 0xf8, 0x07, 0x00, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0xd1, 0x02, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf4,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x80, 0x05, 0x00,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xfd, 0x01, 0x10, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00, 0x01, 0x1c, 0x01, 0xff, 0x01, 0xf8,
+ 0x05, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xd1, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00, 0x01, 0x01, 0x01, 0xcf, 0x01, 0xff,
+ 0x01, 0x80, 0xcc, 0x00,
+
+ /* 39 */
+ 0xff, 0x00, 0x45, 0x00, 0x01, 0x01, 0x11, 0x00, 0x01, 0x17, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0xa5, 0x0e, 0x00, 0x01, 0x06, 0x05, 0xff,
+ 0x01, 0xd3, 0x0d, 0x00, 0x01, 0x5f, 0x06, 0xff, 0x01, 0x30, 0x0c, 0x00,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0xc5, 0x01, 0x21, 0x01, 0x26, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0xd0, 0x0b, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xfb,
+ 0x03, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf5, 0x0b, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xf3, 0x03, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xf9,
+ 0x0b, 0x00, 0x01, 0x05, 0x01, 0x88, 0x01, 0x80, 0x04, 0x00, 0x01, 0xff,
+ 0x01, 0xfa, 0x11, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf9, 0x11, 0x00,
+ 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf4, 0x0e, 0x00, 0x01, 0x01, 0x01, 0x33,
+ 0x01, 0x36, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xb0, 0x0e, 0x00, 0x01, 0x09,
+ 0x03, 0xff, 0x01, 0xfa, 0x01, 0x10, 0x0e, 0x00, 0x01, 0x09, 0x03, 0xff,
+ 0x01, 0xfa, 0x01, 0x10, 0x0e, 0x00, 0x01, 0x08, 0x01, 0xee, 0x03, 0xff,
+ 0x01, 0xe3, 0x10, 0x00, 0x01, 0x01, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xfd,
+ 0x11, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0x40, 0x0a, 0x00, 0x01, 0x06,
+ 0x01, 0x66, 0x01, 0x30, 0x04, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x70,
+ 0x0a, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xb0, 0x04, 0x00, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0x80, 0x0a, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xf1,
+ 0x04, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x60, 0x0a, 0x00, 0x01, 0x0a,
+ 0x01, 0xff, 0x01, 0xfb, 0x03, 0x00, 0x01, 0x04, 0x02, 0xff, 0x01, 0x10,
+ 0x0a, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0xe8, 0x01, 0x53, 0x01, 0x46,
+ 0x01, 0xbf, 0x01, 0xff, 0x01, 0xf8, 0x0c, 0x00, 0x01, 0x7f, 0x06, 0xff,
+ 0x01, 0xb0, 0x0c, 0x00, 0x01, 0x06, 0x01, 0xef, 0x04, 0xff, 0x01, 0xf7,
+ 0x0e, 0x00, 0x01, 0x05, 0x01, 0x9c, 0x01, 0xde, 0x01, 0xdc, 0x01, 0x95,
+ 0xc1, 0x00,
+
+ /* 40 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x04, 0x00, 0x01, 0x05,
+ 0x01, 0x77, 0x01, 0x76, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x04, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x03, 0x00, 0x01, 0x05, 0x02, 0xff, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x0e, 0x02, 0xff, 0x01, 0xfe,
+ 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x7f, 0x01, 0xff,
+ 0x01, 0xcf, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x01, 0x01, 0xff, 0x01, 0xf9, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xe1,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0x70, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0xcf, 0x01, 0xfd, 0x01, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xf4, 0x01, 0x00, 0x01, 0x9f, 0x01, 0xfe,
+ 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00, 0x01, 0x0e, 0x01, 0xff,
+ 0x01, 0xb0, 0x01, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf8, 0x02, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xe0, 0x02, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0x60, 0x02, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0xdf, 0x01, 0xfc, 0x03, 0x00, 0x01, 0x9f,
+ 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0xf3, 0x03, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0xa0,
+ 0x03, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x02, 0xff,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xf7, 0x04, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xff, 0x01, 0xe0, 0x04, 0x00, 0x01, 0x9f, 0x01, 0xfe,
+ 0xd2, 0x00,
+
+ /* 41 */
+ 0xca, 0x00, 0x01, 0x2a, 0x01, 0xa2, 0x03, 0x00, 0x01, 0x3a, 0x01, 0xa2,
+ 0x0d, 0x00, 0x01, 0x2f, 0x01, 0xf9, 0x03, 0x00, 0x01, 0xaf, 0x01, 0xf1,
+ 0x0d, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0x82, 0x01, 0x00, 0x01, 0x29,
+ 0x01, 0xff, 0x01, 0xc0, 0x0d, 0x00, 0x01, 0x05, 0x05, 0xff, 0x01, 0x30,
+ 0x0e, 0x00, 0x01, 0x7f, 0x03, 0xff, 0x01, 0xf6, 0x0f, 0x00, 0x01, 0x02,
+ 0x01, 0x8b, 0x01, 0xdd, 0x01, 0xb8, 0x01, 0x10, 0x21, 0x00, 0x01, 0x67,
+ 0x01, 0x74, 0x04, 0x00, 0x01, 0x05, 0x01, 0x77, 0x01, 0x76, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0xfe,
+ 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0xcf, 0x01, 0xff,
+ 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x05,
+ 0x02, 0xff, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00,
+ 0x01, 0x0e, 0x02, 0xff, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x03, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xcf, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xf9,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf1, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0x70,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0xcf, 0x01, 0xfd, 0x01, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf4,
+ 0x01, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x01, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xb0, 0x01, 0x00, 0x01, 0x9f,
+ 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x20, 0x01, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x02, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xe0, 0x02, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x60, 0x02, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0xdf,
+ 0x01, 0xfc, 0x03, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef,
+ 0x02, 0xff, 0x01, 0xf3, 0x03, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00,
+ 0x01, 0xef, 0x02, 0xff, 0x01, 0xa0, 0x03, 0x00, 0x01, 0x9f, 0x01, 0xfe,
+ 0x0b, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0x10, 0x03, 0x00, 0x01, 0x9f,
+ 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xf7, 0x04, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xe0,
+ 0x04, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0xd2, 0x00,
+
+ /* 42 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x04, 0x00, 0x01, 0x67,
+ 0x01, 0x77, 0x01, 0x10, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xff, 0x01, 0xf6, 0x0c, 0x00, 0x01, 0xef, 0x01, 0xf8,
+ 0x03, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x60, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf8, 0x02, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf5, 0x0d, 0x00,
+ 0x01, 0xef, 0x01, 0xf8, 0x02, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x50,
+ 0x0d, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x01, 0x00, 0x01, 0x0a, 0x01, 0xff,
+ 0x01, 0xf5, 0x0e, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x01, 0x00, 0x01, 0xaf,
+ 0x01, 0xff, 0x01, 0x50, 0x0e, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x01, 0x0a,
+ 0x01, 0xff, 0x01, 0xf4, 0x0f, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x40, 0x0f, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0xf4,
+ 0x10, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0x40, 0x10, 0x00, 0x01, 0xef,
+ 0x02, 0xff, 0x01, 0xa0, 0x10, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0xfa,
+ 0x10, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xb0,
+ 0x0f, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xfb,
+ 0x0f, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x01, 0x00, 0x01, 0xaf, 0x01, 0xff,
+ 0x01, 0xb0, 0x0e, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x01, 0x00, 0x01, 0x0a,
+ 0x01, 0xff, 0x01, 0xfb, 0x0e, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x02, 0x00,
+ 0x01, 0x9f, 0x01, 0xff, 0x01, 0xc0, 0x0d, 0x00, 0x01, 0xef, 0x01, 0xf8,
+ 0x02, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfc, 0x0d, 0x00, 0x01, 0xef,
+ 0x01, 0xf8, 0x03, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xc0, 0x0c, 0x00,
+ 0x01, 0xef, 0x01, 0xf8, 0x03, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfc,
+ 0x0c, 0x00, 0x01, 0xef, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x9f, 0x01, 0xff,
+ 0x01, 0xc1, 0xd2, 0x00,
+
+ /* 43 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x02, 0x06, 0x77, 0x01, 0x75, 0x0c, 0x00,
+ 0x01, 0x05, 0x06, 0xff, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x05, 0x06, 0xff,
+ 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xfb, 0x03, 0xaa,
+ 0x01, 0xef, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x05, 0x01, 0xff,
+ 0x01, 0xf2, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf2, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00,
+ 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc,
+ 0x0c, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x03, 0x00, 0x01, 0xbf,
+ 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x03, 0x00,
+ 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0,
+ 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x08, 0x01, 0xff,
+ 0x01, 0xf0, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf0, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xd0, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc,
+ 0x0c, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xb0, 0x03, 0x00, 0x01, 0xbf,
+ 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x80, 0x03, 0x00,
+ 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x3f, 0x01, 0xff, 0x01, 0x40,
+ 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x9f, 0x01, 0xff,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0b, 0x00, 0x01, 0x04,
+ 0x01, 0xff, 0x01, 0xf9, 0x04, 0x00, 0x01, 0xbf, 0x01, 0xfc, 0x0b, 0x00,
+ 0x01, 0x8f, 0x01, 0xff, 0x01, 0xf2, 0x04, 0x00, 0x01, 0xbf, 0x01, 0xfc,
+ 0x0b, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x70, 0x04, 0x00, 0x01, 0xbf,
+ 0x01, 0xfc, 0x0b, 0x00, 0x01, 0x9f, 0x01, 0xf6, 0x05, 0x00, 0x01, 0xbf,
+ 0x01, 0xfc, 0x0b, 0x00, 0x01, 0x34, 0xc7, 0x00,
+
+ /* 44 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x77, 0x01, 0x30, 0x04, 0x00,
+ 0x01, 0x03, 0x02, 0x77, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xd0,
+ 0x04, 0x00, 0x01, 0x0b, 0x02, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff,
+ 0x01, 0xf3, 0x04, 0x00, 0x01, 0x2f, 0x02, 0xff, 0x0a, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0xfa, 0x04, 0x00, 0x01, 0x9f, 0x02, 0xff, 0x0a, 0x00,
+ 0x01, 0xef, 0x02, 0xff, 0x01, 0x10, 0x03, 0x00, 0x03, 0xff, 0x0a, 0x00,
+ 0x01, 0xef, 0x02, 0xff, 0x01, 0x80, 0x02, 0x00, 0x01, 0x06, 0x03, 0xff,
+ 0x0a, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0xe0, 0x02, 0x00, 0x01, 0x0d,
+ 0x03, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfd, 0x01, 0xff, 0x01, 0xf5,
+ 0x02, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0xdf, 0x01, 0xff, 0x0a, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0xdf, 0x01, 0xfc, 0x02, 0x00, 0x01, 0xaf,
+ 0x01, 0xfe, 0x01, 0x8f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x01, 0x7f, 0x01, 0xff, 0x01, 0x30, 0x01, 0x01, 0x01, 0xff, 0x01, 0xf8,
+ 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf2, 0x01, 0x7f,
+ 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x0a, 0x01, 0xff,
+ 0x01, 0xf1, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xb0, 0x01, 0x7f, 0x01, 0xff,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x03, 0x01, 0xff, 0x01, 0xf7,
+ 0x01, 0x5f, 0x01, 0xff, 0x01, 0x40, 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00, 0x01, 0xcf, 0x01, 0xfd, 0x01, 0xcf,
+ 0x01, 0xfe, 0x01, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x6f, 0x02, 0xff, 0x01, 0xf7, 0x01, 0x00,
+ 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00,
+ 0x01, 0x0f, 0x02, 0xff, 0x01, 0xf1, 0x01, 0x00, 0x01, 0x7f, 0x01, 0xff,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00, 0x01, 0x09, 0x02, 0xff,
+ 0x01, 0xa0, 0x01, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x02, 0x02, 0xff, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0xcf, 0x01, 0xfd, 0x02, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x5f, 0x01, 0xf7, 0x02, 0x00,
+ 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0x61, 0x02, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x0a, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x06, 0x00, 0x01, 0x7f, 0x01, 0xff, 0xd1, 0x00,
+
+ /* 45 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x05, 0x00, 0x01, 0x77,
+ 0x01, 0x73, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xfd, 0x05, 0xaa, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x07, 0xff, 0x01, 0xf8, 0x0b, 0x00,
+ 0x01, 0xef, 0x07, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xfc,
+ 0x05, 0x77, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf8, 0xd2, 0x00,
+
+ /* 46 */
+ 0xff, 0x00, 0x58, 0x00, 0x01, 0x39, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xeb,
+ 0x01, 0x60, 0x0e, 0x00, 0x01, 0x1b, 0x04, 0xff, 0x01, 0xfe, 0x01, 0x50,
+ 0x0c, 0x00, 0x01, 0x02, 0x01, 0xef, 0x05, 0xff, 0x01, 0xf8, 0x0c, 0x00,
+ 0x01, 0x0d, 0x02, 0xff, 0x01, 0x83, 0x01, 0x12, 0x01, 0x5c, 0x02, 0xff,
+ 0x01, 0x50, 0x0b, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xd1, 0x03, 0x00,
+ 0x01, 0x7f, 0x01, 0xff, 0x01, 0xe1, 0x0a, 0x00, 0x01, 0x01, 0x01, 0xff,
+ 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf7,
+ 0x0a, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf7, 0x04, 0x00, 0x01, 0x01,
+ 0x01, 0xff, 0x01, 0xfd, 0x0a, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf1,
+ 0x05, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x10, 0x09, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90, 0x05, 0x00, 0x01, 0x3f,
+ 0x01, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80,
+ 0x05, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80, 0x09, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x70, 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90,
+ 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80, 0x05, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf1, 0x05, 0x00, 0x01, 0xaf,
+ 0x01, 0xff, 0x01, 0x10, 0x09, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf8,
+ 0x04, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xfd, 0x0b, 0x00, 0x02, 0xff,
+ 0x01, 0x20, 0x03, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf6, 0x0b, 0x00,
+ 0x01, 0x8f, 0x01, 0xff, 0x01, 0xe3, 0x03, 0x00, 0x01, 0xaf, 0x01, 0xff,
+ 0x01, 0xd0, 0x0b, 0x00, 0x01, 0x0c, 0x02, 0xff, 0x01, 0xa5, 0x01, 0x34,
+ 0x01, 0x7e, 0x02, 0xff, 0x01, 0x30, 0x0b, 0x00, 0x01, 0x01, 0x01, 0xcf,
+ 0x05, 0xff, 0x01, 0xf5, 0x0d, 0x00, 0x01, 0x19, 0x04, 0xff, 0x01, 0xfc,
+ 0x01, 0x30, 0x0e, 0x00, 0x01, 0x27, 0x01, 0xbd, 0x01, 0xee, 0x01, 0xc9,
+ 0x01, 0x40, 0xc0, 0x00,
+
+ /* 47 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x07, 0x77, 0x01, 0x73, 0x0b, 0x00,
+ 0x01, 0xef, 0x07, 0xff, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x07, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xfd, 0x05, 0xaa, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0xd2, 0x00,
+
+ /* 48 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x72, 0x01, 0x00, 0x01, 0x29,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0xc7, 0x01, 0x10, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf4, 0x01, 0x08, 0x04, 0xff, 0x01, 0xf6, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf4, 0x01, 0xaf, 0x05, 0xff, 0x01, 0x80, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xfc, 0x01, 0xff, 0x01, 0xf9, 0x01, 0x42, 0x01, 0x37, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0xf6, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0x30, 0x02, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xf3, 0x04, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x70, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x0a, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf2,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfe, 0x05, 0x00, 0x01, 0x05, 0x01, 0xff,
+ 0x01, 0xf5, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf7, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfa, 0x06, 0x00,
+ 0x01, 0xff, 0x01, 0xf8, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x06, 0x00,
+ 0x01, 0xff, 0x01, 0xf9, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfa, 0x06, 0x00,
+ 0x01, 0xff, 0x01, 0xf9, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfe,
+ 0x05, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf5, 0x0a, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf2,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xd0, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xf4,
+ 0x04, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x70, 0x0a, 0x00, 0x01, 0xef,
+ 0x02, 0xff, 0x01, 0x40, 0x02, 0x00, 0x01, 0x1b, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0x10, 0x0a, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0xfb, 0x01, 0x64,
+ 0x01, 0x58, 0x01, 0xef, 0x01, 0xff, 0x01, 0xf5, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0xaf, 0x05, 0xff, 0x01, 0x70, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x08, 0x04, 0xff, 0x01, 0xe4, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x28, 0x01, 0xce, 0x01, 0xed, 0x01, 0xa5,
+ 0x0d, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xde, 0x01, 0xe8,
+ 0x25, 0x00,
+
+ /* 49 */
+ 0xff, 0x00, 0x58, 0x00, 0x01, 0x38, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xea,
+ 0x01, 0x50, 0x0e, 0x00, 0x01, 0x19, 0x04, 0xff, 0x01, 0xfd, 0x01, 0x20,
+ 0x0c, 0x00, 0x01, 0x01, 0x01, 0xcf, 0x05, 0xff, 0x01, 0xf2, 0x0c, 0x00,
+ 0x01, 0x0c, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x73, 0x01, 0x12, 0x01, 0x6d,
+ 0x01, 0xff, 0x01, 0xfd, 0x0c, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xc1,
+ 0x03, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x60, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xb0,
+ 0x0a, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf6, 0x04, 0x00, 0x01, 0x0a,
+ 0x01, 0xff, 0x01, 0xf0, 0x0a, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf1,
+ 0x04, 0x00, 0x01, 0x04, 0x01, 0xbb, 0x01, 0xb1, 0x0a, 0x00, 0x01, 0x0d,
+ 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90,
+ 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80, 0x11, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x70, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80,
+ 0x11, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90, 0x11, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xc0, 0x05, 0x00, 0x01, 0x55, 0x01, 0x52, 0x0a, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf1, 0x04, 0x00, 0x01, 0x04, 0x01, 0xff,
+ 0x01, 0xf4, 0x0a, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf6, 0x04, 0x00,
+ 0x01, 0x09, 0x01, 0xff, 0x01, 0xf1, 0x0b, 0x00, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xc0, 0x0b, 0x00,
+ 0x01, 0x8f, 0x01, 0xff, 0x01, 0xd2, 0x02, 0x00, 0x01, 0x01, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x60, 0x0b, 0x00, 0x01, 0x0c, 0x02, 0xff, 0x01, 0x94,
+ 0x01, 0x34, 0x01, 0x8e, 0x01, 0xff, 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x01,
+ 0x01, 0xdf, 0x05, 0xff, 0x01, 0xe1, 0x0d, 0x00, 0x01, 0x19, 0x04, 0xff,
+ 0x01, 0xfa, 0x01, 0x10, 0x0e, 0x00, 0x01, 0x27, 0x01, 0xcd, 0x01, 0xee,
+ 0x01, 0xc8, 0x01, 0x20, 0xc0, 0x00,
+
+ /* 50 */
+ 0xff, 0x00, 0x55, 0x00, 0x01, 0x47, 0x06, 0x77, 0x01, 0x76, 0x0c, 0x00,
+ 0x01, 0x9f, 0x06, 0xff, 0x01, 0xfe, 0x0c, 0x00, 0x01, 0x9f, 0x06, 0xff,
+ 0x01, 0xfe, 0x0c, 0x00, 0x01, 0x6a, 0x02, 0xaa, 0x01, 0xdf, 0x01, 0xff,
+ 0x02, 0xaa, 0x01, 0xa9, 0x0f, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00, 0x01, 0x9f, 0x01, 0xfe, 0x12, 0x00,
+ 0x01, 0x9f, 0x01, 0xfe, 0xd7, 0x00,
+
+ /* 51 */
+ 0xff, 0x00, 0x55, 0x00, 0x01, 0x67, 0x01, 0x75, 0x05, 0x00, 0x01, 0x05,
+ 0x01, 0x77, 0x01, 0x70, 0x0a, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x05, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xb0, 0x0a, 0x00, 0x01, 0x5f, 0x01, 0xff,
+ 0x01, 0x50, 0x04, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x50, 0x0a, 0x00,
+ 0x01, 0x0f, 0x01, 0xff, 0x01, 0xb0, 0x04, 0x00, 0x01, 0xbf, 0x01, 0xff,
+ 0x0b, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf0, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0xff, 0x01, 0xf9, 0x0b, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xf5,
+ 0x03, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf3, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xfb, 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xd0, 0x0c, 0x00,
+ 0x01, 0x9f, 0x01, 0xff, 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x70,
+ 0x0c, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x50, 0x02, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x20, 0x0c, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xb0,
+ 0x02, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x0d, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf1, 0x01, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xf5, 0x0d, 0x00,
+ 0x01, 0x04, 0x01, 0xff, 0x01, 0xf5, 0x01, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf0, 0x0e, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x01, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0x90, 0x0e, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0x10,
+ 0x01, 0x5f, 0x01, 0xff, 0x01, 0x40, 0x0e, 0x00, 0x01, 0x3f, 0x01, 0xff,
+ 0x01, 0x50, 0x01, 0xbf, 0x01, 0xfd, 0x0f, 0x00, 0x01, 0x0d, 0x01, 0xff,
+ 0x01, 0xb1, 0x01, 0xff, 0x01, 0xf8, 0x0f, 0x00, 0x01, 0x08, 0x01, 0xff,
+ 0x01, 0xf7, 0x01, 0xff, 0x01, 0xf2, 0x0f, 0x00, 0x01, 0x03, 0x03, 0xff,
+ 0x01, 0xc0, 0x10, 0x00, 0x01, 0xdf, 0x02, 0xff, 0x01, 0x60, 0x10, 0x00,
+ 0x01, 0x8f, 0x02, 0xff, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xfa,
+ 0x11, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf4, 0x11, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x80,
+ 0x11, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x20, 0x11, 0x00, 0x01, 0xef,
+ 0x01, 0xfc, 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf6, 0x0f, 0x00,
+ 0x01, 0x05, 0x01, 0x76, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xd0, 0x0f, 0x00,
+ 0x01, 0x09, 0x03, 0xff, 0x01, 0x50, 0x0f, 0x00, 0x01, 0x09, 0x02, 0xff,
+ 0x01, 0xf7, 0x10, 0x00, 0x01, 0x05, 0x01, 0xce, 0x01, 0xda, 0x01, 0x30,
+ 0x24, 0x00,
+
+ /* 52 */
+ 0xe3, 0x00, 0x01, 0x05, 0x01, 0x99, 0x01, 0x80, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0,
+ 0x0c, 0x00, 0x01, 0x01, 0x01, 0x8d, 0x01, 0xff, 0x01, 0xeb, 0x01, 0x40,
+ 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0, 0x01, 0x02, 0x01, 0x9e, 0x01, 0xff,
+ 0x01, 0xea, 0x01, 0x50, 0x07, 0x00, 0x01, 0x6f, 0x03, 0xff, 0x01, 0xfa,
+ 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0, 0x01, 0x5f, 0x03, 0xff, 0x01, 0xfc,
+ 0x01, 0x20, 0x05, 0x00, 0x01, 0x06, 0x05, 0xff, 0x01, 0x98, 0x01, 0xff,
+ 0x01, 0xe4, 0x05, 0xff, 0x01, 0xd1, 0x05, 0x00, 0x01, 0x3f, 0x01, 0xff,
+ 0x01, 0xfc, 0x01, 0x53, 0x01, 0x36, 0x01, 0xcf, 0x01, 0xfc, 0x01, 0xff,
+ 0x01, 0xfd, 0x01, 0xff, 0x01, 0x83, 0x01, 0x24, 0x01, 0x9f, 0x01, 0xff,
+ 0x01, 0xfb, 0x05, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x90, 0x02, 0x00,
+ 0x01, 0x0a, 0x03, 0xff, 0x01, 0xe2, 0x02, 0x00, 0x01, 0x03, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x40, 0x03, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfc,
+ 0x04, 0x00, 0x01, 0xdf, 0x02, 0xff, 0x01, 0x40, 0x03, 0x00, 0x01, 0x5f,
+ 0x01, 0xff, 0x01, 0xb0, 0x03, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf4,
+ 0x04, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xfb, 0x04, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf1, 0x03, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xe0,
+ 0x04, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xf6, 0x04, 0x00, 0x01, 0x07,
+ 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xb0,
+ 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf2, 0x04, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf7, 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf0, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf9, 0x03, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0x80, 0x04, 0x00,
+ 0x01, 0x09, 0x01, 0xff, 0x01, 0xf0, 0x05, 0x00, 0x01, 0xff, 0x01, 0xfa,
+ 0x03, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0x70, 0x04, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xe0, 0x05, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x03, 0x00,
+ 0x01, 0x2f, 0x01, 0xff, 0x01, 0x80, 0x04, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf0, 0x05, 0x00, 0x01, 0xff, 0x01, 0xfa, 0x03, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0x90, 0x04, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf0,
+ 0x05, 0x00, 0x01, 0xff, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x0f, 0x01, 0xff,
+ 0x01, 0xb0, 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf3, 0x04, 0x00,
+ 0x01, 0x03, 0x01, 0xff, 0x01, 0xf7, 0x03, 0x00, 0x01, 0x0c, 0x01, 0xff,
+ 0x01, 0xf0, 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xf7, 0x04, 0x00,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xf4, 0x03, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf5, 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xfc, 0x04, 0x00,
+ 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf1, 0x03, 0x00, 0x01, 0x04, 0x01, 0xff,
+ 0x01, 0xfc, 0x04, 0x00, 0x01, 0xdf, 0x02, 0xff, 0x01, 0x40, 0x03, 0x00,
+ 0x01, 0x5f, 0x01, 0xff, 0x01, 0xb0, 0x04, 0x00, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xa0, 0x02, 0x00, 0x01, 0x0b, 0x03, 0xff, 0x01, 0xe3, 0x02, 0x00,
+ 0x01, 0x04, 0x02, 0xff, 0x01, 0x40, 0x04, 0x00, 0x01, 0x5f, 0x01, 0xff,
+ 0x01, 0xfd, 0x01, 0x74, 0x01, 0x47, 0x01, 0xdf, 0x01, 0xfe, 0x03, 0xff,
+ 0x01, 0x95, 0x01, 0x45, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xfb, 0x05, 0x00,
+ 0x01, 0x08, 0x05, 0xff, 0x01, 0xb8, 0x01, 0xff, 0x01, 0xe6, 0x05, 0xff,
+ 0x01, 0xd1, 0x06, 0x00, 0x01, 0x7f, 0x03, 0xff, 0x01, 0xfa, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xe0, 0x01, 0x6f, 0x03, 0xff, 0x01, 0xfa, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0x02, 0x01, 0x8c, 0x01, 0xef, 0x01, 0xdb, 0x01, 0x50,
+ 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0, 0x01, 0x02, 0x01, 0x8d, 0x01, 0xee,
+ 0x01, 0xd9, 0x01, 0x30, 0x0c, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xe0, 0x1e, 0x00,
+
+ /* 53 */
+ 0xff, 0x00, 0x55, 0x00, 0x01, 0x37, 0x01, 0x77, 0x01, 0x30, 0x04, 0x00,
+ 0x01, 0x17, 0x01, 0x77, 0x01, 0x40, 0x0a, 0x00, 0x01, 0x0d, 0x01, 0xff,
+ 0x01, 0xe1, 0x04, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x20, 0x0a, 0x00,
+ 0x01, 0x03, 0x01, 0xff, 0x01, 0xfb, 0x03, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf6, 0x0c, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x50, 0x02, 0x00,
+ 0x01, 0x2f, 0x01, 0xff, 0x01, 0xb0, 0x0c, 0x00, 0x01, 0x0d, 0x01, 0xff,
+ 0x01, 0xe1, 0x02, 0x00, 0x01, 0xcf, 0x01, 0xfe, 0x01, 0x10, 0x0c, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xfb, 0x01, 0x00, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xf5, 0x0e, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0x60, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x90, 0x0e, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf2,
+ 0x01, 0xcf, 0x01, 0xfd, 0x0f, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0xff, 0x01, 0xf3, 0x10, 0x00, 0x01, 0x6f, 0x02, 0xff, 0x01, 0x70,
+ 0x10, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xfc, 0x11, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xfd, 0x11, 0x00, 0x01, 0x4f, 0x02, 0xff, 0x01, 0x80,
+ 0x0f, 0x00, 0x01, 0x01, 0x01, 0xef, 0x02, 0xff, 0x01, 0xf3, 0x0f, 0x00,
+ 0x01, 0x0a, 0x01, 0xff, 0x01, 0xe3, 0x01, 0xef, 0x01, 0xfd, 0x0f, 0x00,
+ 0x01, 0x6f, 0x01, 0xff, 0x01, 0x50, 0x01, 0x5f, 0x01, 0xff, 0x01, 0x90,
+ 0x0d, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfb, 0x01, 0x00, 0x01, 0x0a,
+ 0x01, 0xff, 0x01, 0xf4, 0x0d, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xe1,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xfd, 0x0d, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0x50, 0x02, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x90,
+ 0x0b, 0x00, 0x01, 0x03, 0x01, 0xff, 0x01, 0xfa, 0x03, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xf4, 0x0b, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xe1,
+ 0x03, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xfe, 0x01, 0x10, 0x0a, 0x00,
+ 0x01, 0x9f, 0x01, 0xff, 0x01, 0x50, 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff,
+ 0x01, 0xa0, 0x0a, 0x00, 0x02, 0x11, 0x05, 0x00, 0x01, 0x01, 0x01, 0x11,
+ 0x01, 0x10, 0xbe, 0x00,
+
+ /* 54 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x05, 0x00, 0x01, 0x77,
+ 0x01, 0x73, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x00, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x05, 0x11, 0x01, 0xff,
+ 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xef, 0x07, 0xff, 0x01, 0xfc, 0x01, 0x99,
+ 0x0a, 0x00, 0x01, 0xef, 0x09, 0xff, 0x0a, 0x00, 0x01, 0xef, 0x09, 0xff,
+ 0x12, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x12, 0x00, 0x01, 0x0e, 0x01, 0xff,
+ 0x12, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x12, 0x00, 0x01, 0x0e, 0x01, 0xff,
+ 0x12, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x6d, 0x00,
+
+ /* 55 */
+ 0xff, 0x00, 0x55, 0x00, 0x01, 0x02, 0x01, 0x77, 0x01, 0x71, 0x04, 0x00,
+ 0x01, 0x77, 0x01, 0x73, 0x0b, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x04, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x05, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf2, 0x04, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00,
+ 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x04, 0x00, 0x01, 0xff, 0x01, 0xf8,
+ 0x0b, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x04, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x04, 0x00,
+ 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x04, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x05, 0x01, 0xff,
+ 0x01, 0xf2, 0x04, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x03,
+ 0x01, 0xff, 0x01, 0xf6, 0x04, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x0c, 0x00,
+ 0x02, 0xff, 0x01, 0x85, 0x03, 0x55, 0x01, 0xff, 0x01, 0xf8, 0x0c, 0x00,
+ 0x01, 0x6f, 0x06, 0xff, 0x01, 0xf8, 0x0c, 0x00, 0x01, 0x07, 0x06, 0xff,
+ 0x01, 0xf8, 0x0d, 0x00, 0x01, 0x17, 0x01, 0xbc, 0x03, 0xcc, 0x01, 0xff,
+ 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x12, 0x00, 0x01, 0x11, 0x01, 0x10, 0xbf, 0x00,
+
+ /* 56 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x66, 0x01, 0x64, 0x02, 0x00, 0x01, 0x01,
+ 0x01, 0x66, 0x01, 0x62, 0x02, 0x00, 0x01, 0x02, 0x01, 0x66, 0x01, 0x60,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x11, 0x01, 0x13,
+ 0x01, 0xff, 0x01, 0xf6, 0x02, 0x11, 0x01, 0x17, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0xef, 0x0a, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef,
+ 0x0a, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x0a, 0xff, 0x01, 0xf1,
+ 0xcf, 0x00,
+
+ /* 57 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x66, 0x01, 0x63, 0x02, 0x00, 0x01, 0x01,
+ 0x01, 0x66, 0x01, 0x62, 0x02, 0x00, 0x01, 0x02, 0x01, 0x66, 0x01, 0x60,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff,
+ 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xff,
+ 0x01, 0xf1, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x11, 0x01, 0x13,
+ 0x01, 0xff, 0x01, 0xf6, 0x02, 0x11, 0x01, 0x17, 0x01, 0xff, 0x01, 0xf1,
+ 0x08, 0x00, 0x01, 0xef, 0x0a, 0xff, 0x01, 0xf9, 0x01, 0x95, 0x07, 0x00,
+ 0x01, 0xef, 0x0b, 0xff, 0x01, 0xf9, 0x07, 0x00, 0x01, 0xef, 0x0b, 0xff,
+ 0x01, 0xf9, 0x12, 0x00, 0x01, 0x5f, 0x01, 0xf9, 0x12, 0x00, 0x01, 0x5f,
+ 0x01, 0xf9, 0x12, 0x00, 0x01, 0x5f, 0x01, 0xf9, 0x12, 0x00, 0x01, 0x5f,
+ 0x01, 0xf9, 0x12, 0x00, 0x01, 0x5f, 0x01, 0xf9, 0x6a, 0x00,
+
+ /* 58 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x56, 0x01, 0x63, 0x12, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xff, 0x02, 0xee, 0x01, 0xed,
+ 0x01, 0xc9, 0x01, 0x60, 0x0d, 0x00, 0x01, 0xef, 0x06, 0xff, 0x01, 0x70,
+ 0x0c, 0x00, 0x01, 0xef, 0x06, 0xff, 0x01, 0xfa, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xfa, 0x02, 0x33, 0x01, 0x34, 0x01, 0x6a, 0x02, 0xff, 0x01, 0x50,
+ 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff,
+ 0x01, 0xd0, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x0c,
+ 0x01, 0xff, 0x01, 0xf1, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00,
+ 0x01, 0x09, 0x01, 0xff, 0x01, 0xf3, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x04, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf4, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x04, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x2f, 0x01, 0xff, 0x01, 0xe0,
+ 0x0b, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x03, 0x11, 0x01, 0x38, 0x02, 0xff,
+ 0x01, 0x70, 0x0b, 0x00, 0x01, 0xef, 0x06, 0xff, 0x01, 0xfc, 0x0c, 0x00,
+ 0x01, 0xef, 0x06, 0xff, 0x01, 0xc1, 0x0c, 0x00, 0x01, 0xef, 0x05, 0xff,
+ 0x01, 0xb5, 0x0d, 0x00, 0x05, 0x11, 0xc2, 0x00,
+
+ /* 59 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x56, 0x01, 0x63, 0x07, 0x00, 0x01, 0x02,
+ 0x01, 0x66, 0x01, 0x60, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x07, 0x00,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x07, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x07, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x07, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x07, 0x00, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x07, 0x00, 0x01, 0x07,
+ 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x07, 0x00,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xff,
+ 0x02, 0xee, 0x01, 0xed, 0x01, 0xc9, 0x01, 0x60, 0x02, 0x00, 0x01, 0x07,
+ 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x06, 0xff, 0x01, 0x70,
+ 0x01, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef,
+ 0x06, 0xff, 0x01, 0xfa, 0x01, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xfa, 0x02, 0x33, 0x01, 0x34, 0x01, 0x6b,
+ 0x02, 0xff, 0x01, 0x50, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xd0,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf1, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf3, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf4,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x04, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf2, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x04, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xe0, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x03, 0x11, 0x01, 0x37, 0x02, 0xff, 0x01, 0x70,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x06, 0xff,
+ 0x01, 0xfc, 0x01, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00,
+ 0x01, 0xef, 0x06, 0xff, 0x01, 0xc1, 0x01, 0x00, 0x01, 0x07, 0x01, 0xff,
+ 0x01, 0xf0, 0x08, 0x00, 0x01, 0xef, 0x05, 0xff, 0x01, 0xb5, 0x02, 0x00,
+ 0x01, 0x07, 0x01, 0xff, 0x01, 0xf0, 0x08, 0x00, 0x05, 0x11, 0x05, 0x00,
+ 0x01, 0x11, 0x01, 0x10, 0xbb, 0x00,
+
+ /* 60 */
+ 0xff, 0x00, 0x55, 0x00, 0x01, 0x36, 0x04, 0x66, 0x01, 0x63, 0x0e, 0x00,
+ 0x01, 0x9f, 0x04, 0xff, 0x01, 0xf8, 0x0e, 0x00, 0x01, 0x9f, 0x04, 0xff,
+ 0x01, 0xf8, 0x0e, 0x00, 0x01, 0x6a, 0x03, 0xaa, 0x01, 0xff, 0x01, 0xf8,
+ 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8,
+ 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x12, 0x00, 0x01, 0xff, 0x01, 0xf8,
+ 0x12, 0x00, 0x02, 0xff, 0x02, 0xee, 0x01, 0xed, 0x01, 0xc9, 0x01, 0x50,
+ 0x0d, 0x00, 0x06, 0xff, 0x01, 0xfe, 0x01, 0x60, 0x0c, 0x00, 0x07, 0xff,
+ 0x01, 0xf9, 0x0c, 0x00, 0x01, 0xff, 0x01, 0xfa, 0x02, 0x33, 0x01, 0x34,
+ 0x01, 0x6b, 0x02, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0xff, 0x01, 0xf8,
+ 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0xc0, 0x0b, 0x00, 0x01, 0xff,
+ 0x01, 0xf8, 0x04, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf1, 0x0b, 0x00,
+ 0x01, 0xff, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf3,
+ 0x0b, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf3, 0x0b, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x04, 0x00, 0x01, 0x0b,
+ 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0xff, 0x01, 0xf8, 0x04, 0x00,
+ 0x01, 0x3f, 0x01, 0xff, 0x01, 0xe0, 0x0b, 0x00, 0x01, 0xff, 0x01, 0xf9,
+ 0x03, 0x11, 0x01, 0x38, 0x02, 0xff, 0x01, 0x70, 0x0b, 0x00, 0x07, 0xff,
+ 0x01, 0xfc, 0x0c, 0x00, 0x07, 0xff, 0x01, 0xb1, 0x0c, 0x00, 0x06, 0xff,
+ 0x01, 0xb5, 0x0d, 0x00, 0x05, 0x11, 0xbf, 0x00,
+
+ /* 61 */
+ 0xff, 0x00, 0x57, 0x00, 0x01, 0x02, 0x01, 0x8c, 0x01, 0xff, 0x01, 0xfd,
+ 0x01, 0x94, 0x0f, 0x00, 0x01, 0x9f, 0x04, 0xff, 0x01, 0xb2, 0x0d, 0x00,
+ 0x01, 0x0c, 0x05, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x0c, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0xf8, 0x01, 0x42, 0x01, 0x36, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0xe1, 0x0b, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20,
+ 0x02, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfa, 0x0b, 0x00, 0x01, 0x07,
+ 0x01, 0xff, 0x01, 0xf5, 0x04, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x20,
+ 0x0a, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xe0, 0x04, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0x90, 0x0a, 0x00, 0x01, 0x0a, 0x01, 0xcc, 0x01, 0x80,
+ 0x04, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xe0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xff, 0x01, 0xf1, 0x0d, 0x00, 0x01, 0x69, 0x03, 0x99, 0x01, 0x9b,
+ 0x01, 0xff, 0x01, 0xf4, 0x0d, 0x00, 0x01, 0xaf, 0x05, 0xff, 0x01, 0xf5,
+ 0x0d, 0x00, 0x01, 0xaf, 0x05, 0xff, 0x01, 0xf6, 0x0d, 0x00, 0x01, 0x58,
+ 0x03, 0x88, 0x01, 0x8a, 0x01, 0xff, 0x01, 0xf5, 0x11, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf4, 0x0a, 0x00, 0x01, 0x05, 0x01, 0x55, 0x01, 0x10,
+ 0x04, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf2, 0x0a, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0x80, 0x04, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xe0,
+ 0x0a, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xd0, 0x04, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xa0, 0x0a, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xf5,
+ 0x04, 0x00, 0x01, 0xbf, 0x01, 0xff, 0x01, 0x40, 0x0a, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xfe, 0x01, 0x20, 0x02, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xfc, 0x0c, 0x00, 0x01, 0x9f, 0x01, 0xff, 0x01, 0xf9, 0x01, 0x42,
+ 0x01, 0x37, 0x01, 0xdf, 0x01, 0xff, 0x01, 0xf2, 0x0c, 0x00, 0x01, 0x0b,
+ 0x06, 0xff, 0x01, 0x40, 0x0d, 0x00, 0x01, 0x8f, 0x04, 0xff, 0x01, 0xc2,
+ 0x0e, 0x00, 0x01, 0x01, 0x01, 0x8c, 0x01, 0xef, 0x01, 0xed, 0x01, 0x94,
+ 0xc1, 0x00,
+
+ /* 62 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x56, 0x01, 0x63, 0x04, 0x00, 0x01, 0x05,
+ 0x01, 0xae, 0x01, 0xff, 0x01, 0xed, 0x01, 0x83, 0x09, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x03, 0x00, 0x01, 0x03, 0x01, 0xdf, 0x04, 0xff, 0x01, 0xa1,
+ 0x08, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x6f, 0x05, 0xff,
+ 0x01, 0xfe, 0x01, 0x20, 0x07, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0x04, 0x02, 0xff, 0x01, 0xd6, 0x01, 0x32, 0x01, 0x48, 0x02, 0xff,
+ 0x01, 0xe0, 0x07, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x1c, 0x01, 0xff, 0x01, 0xf9,
+ 0x07, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x7f, 0x01, 0xff,
+ 0x01, 0xb0, 0x03, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xff, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x70, 0x06, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0xfb,
+ 0x05, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xb0, 0x06, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xe0, 0x06, 0x00, 0x01, 0xef, 0x01, 0xfd,
+ 0x01, 0x99, 0x01, 0x9c, 0x01, 0xff, 0x01, 0xf3, 0x05, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xf1, 0x06, 0x00, 0x01, 0xef, 0x04, 0xff, 0x01, 0xf2,
+ 0x05, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf2, 0x06, 0x00, 0x01, 0xef,
+ 0x04, 0xff, 0x01, 0xf1, 0x05, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf3,
+ 0x06, 0x00, 0x01, 0xef, 0x01, 0xfc, 0x01, 0x88, 0x01, 0x8c, 0x01, 0xff,
+ 0x01, 0xf2, 0x05, 0x00, 0x01, 0x07, 0x01, 0xff, 0x01, 0xf2, 0x06, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x01, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf3,
+ 0x05, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xf1, 0x06, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x04, 0x01, 0xff, 0x01, 0xf6, 0x05, 0x00,
+ 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf0, 0x06, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0xff, 0x01, 0xfb, 0x05, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xb0, 0x06, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00,
+ 0x01, 0xcf, 0x01, 0xff, 0x01, 0x20, 0x04, 0x00, 0x01, 0x7f, 0x01, 0xff,
+ 0x01, 0x70, 0x06, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0xb0, 0x03, 0x00, 0x01, 0x01, 0x01, 0xef, 0x01, 0xff,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x0e,
+ 0x01, 0xff, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x2d, 0x01, 0xff, 0x01, 0xf9,
+ 0x07, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x04, 0x02, 0xff,
+ 0x01, 0xd7, 0x01, 0x32, 0x01, 0x49, 0x02, 0xff, 0x01, 0xd0, 0x07, 0x00,
+ 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x6f, 0x05, 0xff, 0x01, 0xfd,
+ 0x01, 0x20, 0x07, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0xdf, 0x04, 0xff, 0x01, 0xa1, 0x08, 0x00, 0x01, 0x11, 0x01, 0x10,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xad, 0x01, 0xff, 0x01, 0xec, 0x01, 0x82,
+ 0xbc, 0x00,
+
+ /* 63 */
+ 0xff, 0x00, 0x58, 0x00, 0x01, 0x14, 0x05, 0x66, 0x01, 0x60, 0x0c, 0x00,
+ 0x01, 0x2b, 0x06, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0x02, 0x01, 0xef,
+ 0x06, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0x0c, 0x02, 0xff, 0x01, 0xeb,
+ 0x02, 0xaa, 0x01, 0xac, 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0x4f,
+ 0x01, 0xff, 0x01, 0xf5, 0x03, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x0b, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0x70, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0x30,
+ 0x03, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0x9f,
+ 0x01, 0xff, 0x01, 0x20, 0x03, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x0b, 0x00, 0x01, 0x6f, 0x01, 0xff, 0x01, 0x70, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xf8,
+ 0x01, 0x20, 0x02, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00,
+ 0x01, 0x08, 0x07, 0xff, 0x01, 0xf2, 0x0c, 0x00, 0x01, 0x8f, 0x06, 0xff,
+ 0x01, 0xf2, 0x0c, 0x00, 0x01, 0x02, 0x01, 0x9d, 0x05, 0xff, 0x01, 0xf2,
+ 0x0d, 0x00, 0x01, 0x01, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x62, 0x01, 0x27,
+ 0x01, 0xff, 0x01, 0xf2, 0x0d, 0x00, 0x01, 0x0c, 0x01, 0xff, 0x01, 0xf7,
+ 0x01, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x0d, 0x00, 0x01, 0xcf,
+ 0x01, 0xff, 0x01, 0x80, 0x01, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x0c, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf9, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf2, 0x0c, 0x00, 0x01, 0xaf, 0x01, 0xff, 0x01, 0xa0,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x0b, 0x00, 0x01, 0x09,
+ 0x01, 0xff, 0x01, 0xfa, 0x03, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x0b, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x01, 0xb0, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xff, 0x01, 0xf2, 0x0a, 0x00, 0x01, 0x08, 0x01, 0xff, 0x01, 0xfb,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2, 0x0a, 0x00, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0xc0, 0x04, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf2,
+ 0x0a, 0x00, 0x02, 0x11, 0x06, 0x00, 0x01, 0x11, 0x01, 0x10, 0xbe, 0x00,
+
+ /* 64 */
+ 0x2c, 0x00, 0x01, 0xbd, 0x01, 0xdd, 0x01, 0x60, 0x01, 0x05, 0x01, 0xdd,
+ 0x01, 0xdc, 0x0e, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x70, 0x01, 0x06,
+ 0x01, 0xff, 0x01, 0xfe, 0x0e, 0x00, 0x01, 0xdf, 0x01, 0xff, 0x01, 0x70,
+ 0x01, 0x06, 0x01, 0xff, 0x01, 0xfe, 0x0e, 0x00, 0x01, 0xdf, 0x01, 0xff,
+ 0x01, 0x70, 0x01, 0x06, 0x01, 0xff, 0x01, 0xfe, 0x0e, 0x00, 0x01, 0x67,
+ 0x01, 0x77, 0x01, 0x30, 0x01, 0x02, 0x01, 0x77, 0x01, 0x76, 0x33, 0x00,
+ 0x01, 0x1c, 0x0a, 0xcc, 0x09, 0x00, 0x01, 0x1f, 0x0a, 0xff, 0x09, 0x00,
+ 0x01, 0x1f, 0x0a, 0xff, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xe8,
+ 0x08, 0x88, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xfe, 0x07, 0xee,
+ 0x01, 0xe4, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf5, 0x09, 0x00,
+ 0x01, 0x1f, 0x09, 0xff, 0x01, 0xf5, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xe7, 0x07, 0x77, 0x01, 0x72, 0x09, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00,
+ 0x01, 0x1f, 0x01, 0xff, 0x01, 0xc0, 0x11, 0x00, 0x01, 0x1f, 0x01, 0xff,
+ 0x01, 0xd4, 0x08, 0x44, 0x01, 0x30, 0x08, 0x00, 0x01, 0x1f, 0x0a, 0xff,
+ 0x01, 0xb0, 0x08, 0x00, 0x01, 0x1f, 0x0a, 0xff, 0x01, 0xb0, 0x08, 0x00,
+ 0x01, 0x1f, 0x0a, 0xff, 0x01, 0xb0, 0x08, 0x00, 0x01, 0x01, 0x0a, 0x11,
+ 0xbc, 0x00,
+
+ /* 65 */
+ 0xb6, 0x00, 0x01, 0x01, 0x02, 0x55, 0x01, 0x00, 0x01, 0x04, 0x01, 0x55,
+ 0x01, 0x52, 0x0d, 0x00, 0x01, 0x05, 0x02, 0xff, 0x01, 0x00, 0x01, 0x0d,
+ 0x01, 0xff, 0x01, 0xf7, 0x0d, 0x00, 0x01, 0x05, 0x02, 0xff, 0x01, 0x00,
+ 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf7, 0x0d, 0x00, 0x01, 0x05, 0x02, 0xff,
+ 0x01, 0x00, 0x01, 0x0d, 0x01, 0xff, 0x01, 0xf7, 0x0d, 0x00, 0x01, 0x04,
+ 0x02, 0xee, 0x01, 0x00, 0x01, 0x0c, 0x01, 0xee, 0x01, 0xe6, 0x4a, 0x00,
+ 0x01, 0x17, 0x01, 0xbe, 0x01, 0xff, 0x01, 0xdb, 0x01, 0x60, 0x0e, 0x00,
+ 0x01, 0x07, 0x04, 0xff, 0x01, 0xfe, 0x01, 0x50, 0x0d, 0x00, 0x01, 0xbf,
+ 0x05, 0xff, 0x01, 0xf7, 0x0c, 0x00, 0x01, 0x0a, 0x02, 0xff, 0x01, 0x94,
+ 0x01, 0x23, 0x01, 0x6c, 0x02, 0xff, 0x01, 0x50, 0x0b, 0x00, 0x01, 0x6f,
+ 0x01, 0xff, 0x01, 0xd2, 0x03, 0x00, 0x01, 0x7f, 0x01, 0xff, 0x01, 0xd0,
+ 0x0b, 0x00, 0x01, 0xef, 0x01, 0xfe, 0x01, 0x10, 0x03, 0x00, 0x01, 0x07,
+ 0x01, 0xff, 0x01, 0xf6, 0x0a, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf6,
+ 0x05, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x0a, 0x00, 0x01, 0x09, 0x01, 0xff,
+ 0x01, 0xf0, 0x05, 0x00, 0x01, 0x8f, 0x01, 0xff, 0x0a, 0x00, 0x01, 0x0d,
+ 0x01, 0xff, 0x01, 0xb0, 0x05, 0x00, 0x01, 0x4f, 0x01, 0xff, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0f, 0x01, 0xff, 0x01, 0xb5, 0x05, 0x55, 0x01, 0x7f,
+ 0x01, 0xff, 0x01, 0x50, 0x09, 0x00, 0x01, 0x1f, 0x09, 0xff, 0x01, 0x70,
+ 0x09, 0x00, 0x01, 0x2f, 0x09, 0xff, 0x01, 0x70, 0x09, 0x00, 0x01, 0x1f,
+ 0x01, 0xff, 0x01, 0xb7, 0x07, 0x77, 0x01, 0x40, 0x09, 0x00, 0x01, 0x0f,
+ 0x01, 0xff, 0x01, 0x80, 0x11, 0x00, 0x01, 0x0e, 0x01, 0xff, 0x01, 0xb0,
+ 0x11, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xe0, 0x05, 0x00, 0x01, 0x37,
+ 0x01, 0x77, 0x0a, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf5, 0x05, 0x00,
+ 0x01, 0xdf, 0x01, 0xfd, 0x0b, 0x00, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10,
+ 0x03, 0x00, 0x01, 0x06, 0x01, 0xff, 0x01, 0xf8, 0x0b, 0x00, 0x01, 0x8f,
+ 0x01, 0xff, 0x01, 0xc1, 0x03, 0x00, 0x01, 0x5f, 0x01, 0xff, 0x01, 0xf1,
+ 0x0b, 0x00, 0x01, 0x0c, 0x02, 0xff, 0x01, 0x94, 0x01, 0x23, 0x01, 0x6b,
+ 0x02, 0xff, 0x01, 0x60, 0x0b, 0x00, 0x01, 0x01, 0x01, 0xcf, 0x05, 0xff,
+ 0x01, 0xf8, 0x0d, 0x00, 0x01, 0x19, 0x04, 0xff, 0x01, 0xfe, 0x01, 0x50,
+ 0x0e, 0x00, 0x01, 0x27, 0x01, 0xce, 0x01, 0xff, 0x01, 0xda, 0x01, 0x50,
+ 0xc0, 0x00,
+
+ /* 48 */
+ 0xff, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x72, 0x01, 0x00, 0x01, 0x29,
+ 0x01, 0xdf, 0x01, 0xff, 0x01, 0xc7, 0x01, 0x10, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf4, 0x01, 0x08, 0x04, 0xff, 0x01, 0xf6, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf4, 0x01, 0xaf, 0x05, 0xff, 0x01, 0x80, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xfc, 0x01, 0xff, 0x01, 0xf9, 0x01, 0x42, 0x01, 0x37, 0x01, 0xdf,
+ 0x01, 0xff, 0x01, 0xf6, 0x0b, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0x30, 0x02, 0x00, 0x01, 0x09, 0x01, 0xff, 0x01, 0xfe, 0x01, 0x10,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xf3, 0x04, 0x00, 0x01, 0xbf,
+ 0x01, 0xff, 0x01, 0x70, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x1f, 0x01, 0xff, 0x01, 0xd0, 0x0a, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0a, 0x01, 0xff, 0x01, 0xf2,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfe, 0x05, 0x00, 0x01, 0x05, 0x01, 0xff,
+ 0x01, 0xf5, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xff, 0x01, 0xf7, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfa, 0x06, 0x00,
+ 0x01, 0xff, 0x01, 0xf8, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x06, 0x00,
+ 0x01, 0xff, 0x01, 0xf9, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfa, 0x06, 0x00,
+ 0x01, 0xff, 0x01, 0xf9, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfb, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xff, 0x01, 0xf8, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xfe,
+ 0x05, 0x00, 0x01, 0x05, 0x01, 0xff, 0x01, 0xf5, 0x0a, 0x00, 0x01, 0xef,
+ 0x01, 0xff, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0b, 0x01, 0xff, 0x01, 0xf2,
+ 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xa0, 0x04, 0x00, 0x01, 0x2f,
+ 0x01, 0xff, 0x01, 0xd0, 0x0a, 0x00, 0x01, 0xef, 0x01, 0xff, 0x01, 0xf4,
+ 0x04, 0x00, 0x01, 0xcf, 0x01, 0xff, 0x01, 0x70, 0x0a, 0x00, 0x01, 0xef,
+ 0x02, 0xff, 0x01, 0x40, 0x02, 0x00, 0x01, 0x1b, 0x01, 0xff, 0x01, 0xfe,
+ 0x01, 0x10, 0x0a, 0x00, 0x01, 0xef, 0x02, 0xff, 0x01, 0xfb, 0x01, 0x64,
+ 0x01, 0x58, 0x01, 0xef, 0x01, 0xff, 0x01, 0xf5, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0xaf, 0x05, 0xff, 0x01, 0x70, 0x0b, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x08, 0x04, 0xff, 0x01, 0xe4, 0x0c, 0x00, 0x01, 0xef,
+ 0x01, 0xf9, 0x01, 0x00, 0x01, 0x28, 0x01, 0xce, 0x01, 0xed, 0x01, 0xa5,
+ 0x0d, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9,
+ 0x12, 0x00, 0x01, 0xef, 0x01, 0xf9, 0x12, 0x00, 0x01, 0xde, 0x01, 0xe8,
+ 0x25, 0x00,
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp
new file mode 100644
index 0000000..d9acb4f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp
@@ -0,0 +1,58 @@
+/*******************
+ * font_bitmap.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+namespace FTDI {
+
+ uint32_t write_rle_data(uint32_t addr, const uint8_t *data, size_t n) {
+ for (; n >= 2; n -= 2) {
+ uint8_t count = pgm_read_byte(data++);
+ uint8_t value = pgm_read_byte(data++);
+ CLCD::mem_write_fill(addr, value, count);
+ addr += count;
+ }
+ return addr;
+ }
+
+ void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle) {
+ cmd.cmd(BITMAP_HANDLE(handle));
+ cmd.cmd(BITMAP_SOURCE(fm.ptr));
+ cmd.bitmap_layout(fm.format, fm.stride, fm.height);
+ cmd.bitmap_size(BILINEAR, BORDER, BORDER, fm.width, fm.height);
+ }
+
+ void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell) {
+ if (x < 0 || y < 0 || x > 511 || y > 511) {
+ cmd.cmd(BITMAP_HANDLE(handle));
+ cmd.cmd(CELL(cell));
+ cmd.cmd(VERTEX2F(x * 16, y * 16));
+ }
+ else {
+ cmd.cmd(VERTEX2II(x, y, handle, cell));
+ }
+ }
+
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h
new file mode 100644
index 0000000..2b0a533
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h
@@ -0,0 +1,30 @@
+/******************
+ * font_bitmaps.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+class CommandProcessor;
+
+namespace FTDI {
+ uint32_t write_rle_data(uint32_t addr, const uint8_t *data, size_t n);
+ void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle);
+ void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell);
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png
new file mode 100644
index 0000000..bc46ebe
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png
Binary files differ
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg
new file mode 100644
index 0000000..25893f5
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg
@@ -0,0 +1,535 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="40"
+ height="3234"
+ viewBox="0 0 10.583333 855.66248"
+ version="1.1"
+ id="svg8"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ sodipodi:docname="cyrillic_char_set_bitmap_31.svg"
+ inkscape:export-filename="C:\Users\kiril\Documents\PlatformIO\Marlin\Marlin\src\lcd\extui\lib\ftdi_eve_touch_ui\ftdi_eve_lib\extended\unicode\font_bitmaps\cyrillic_char_set_bitmap_31.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4142136"
+ inkscape:cx="376.00796"
+ inkscape:cy="-222.93717"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="px"
+ inkscape:window-width="1920"
+ inkscape:window-height="1021"
+ inkscape:window-x="-7"
+ inkscape:window-y="-7"
+ inkscape:window-maximized="1"
+ inkscape:document-rotation="0"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:snap-nodes="false"
+ inkscape:snap-others="false"
+ showguides="false">
+ <inkscape:grid
+ type="xygrid"
+ id="grid94"
+ spacingx="11.1125"
+ spacingy="12.964583"
+ originx="3.0055911e-10"
+ originy="0" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid110"
+ snapvisiblegridlinesonly="false"
+ spacingx="52.916666"
+ spacingy="12.964583"
+ color="#ff6400"
+ opacity="1"
+ originx="3.0055911e-10"
+ originy="-2.6458333"
+ empcolor="#ff6400"
+ empopacity="1" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid112"
+ snapvisiblegridlinesonly="true"
+ enabled="true"
+ originx="3.0055911e-10"
+ spacingx="52.916665"
+ spacingy="12.964583"
+ color="#ff6400"
+ opacity="1"
+ empcolor="#ff6400"
+ empopacity="1"
+ originy="2.3812499" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,264.81684)">
+ <image
+ y="-947.59998"
+ x="-1.7763568e-15"
+ id="image4606"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAABJgCAYAAACFiF0FAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnetu6zrSKJnBev9X9vlxPgWOI6l4aZKt7CpgMNgriVUmdSOb3fx6vV6vkoj/7Rb4RCFCIUIh QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHi3/t/fH19 /fjhjkUP6VpIIUIhQiFCIUIhQiFCIUIhQiHixzt1hoXD6VpIIUIhwpEroRDhnZpQiFCIUIhQiFCI UIhQiFCISCdUNQxaOTxK10IKEQoRzxG6urRnj26f00K7OBXa1V2llPJlVQtAIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHiH//K/+c9iHc2cUs/ryVdCz1TaFV3VQutRCEindCPaNDn goEIWk/ydC2UTgiXL6+8B5WSsIWqhejbR0VKb4XoqptxVT63y1aRTujr9Xq9MtyhD9K1UDqhf6Xk uEMfpGuhZwjt6q5LoZ0oRChEuAaNUIhQiFCIUIhQiEgnVB1aOJj5+lpKwhZSiEgnVHVSX82OzDjB cUqvdqomakrnUqjnABFSp1129sE0pH7/t+khzpWpOb+EWpu9tuW6hWoO2PM7taS7D6UTan7aX7Hk xljKnHjGHb+Eoq+aVqrPoVVSTTmKLc+2Xm7nh2oOvnQWtuZg0a1WdaeuFYuga0rv7uBbVsfctdpo Sw09OlKOy5a/ftQQ2VJWGyRyC3120eox2S+hqINNHwbdDaWjn/6nj46Rg0x5dPR+aMRt4vIl/6rU zywRFDo72Oz5xVKy34cykE6oaeS64mGbroUUIhQiFCIUIhQiFCLSCQ2Fp2ZQHQ1aMQP7S6jmgLOl cBh0JjIaNbzju4VoiNMiMNK94VfZ1knPTyLOr2n3oe1pFOGZwFdj+OgDEpeXfcv5MC3xtickPj0D 724Vw4rn2WmX1R54+XKd1TKlPOV9iLhrndF3qbB1jHe3ieNnNWIhXRYZgmhqoZoTeTSg17Wyobar 6HOGhGqIWBoWUkQikqbwlLOwn7S2zvRX2EPiToZEP0cg9PtN0aAaUow6aqVrfi98ld7yhythMZvZ KEQoRChEKEQoRChEKEQoRAylBM4YyQ7NU88IUw13WXSksSvmOjOqWBVz/eyWmflD3Rl4LqzcRUho oZSJsY6amfmlVxkxexnG0KMjWqaUgRXnswJ6l102Mq84Qmh6ewS/zqFdIgdd6e0UG3v/XyvfLdR6 Oc9aslN9Uq/KEP5fywe3SvW0YPN9aHZLdWdxfhL1Ktv9tJ9VazhnWmlv5t3Z3179W5PQGbXjsuhL /3SF1d0Bj/+uWcnQw9Qq8D1dF5ISeDeIbJW6XdDUeheOaGFLaBIKEQoRChEKEQoRChEKEQoR6YSs rkMoRChEdM3kz+Q5LbSL0PpDEaRrIdwDbzXpWkghQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhIp1QeDGbUbqK2cykuXZMKZvW5F9hMZsrmVVUd9m2qqcHu9IpToV2RqfT3am7cxRnUZXFuZLn ddlqqmpYreSH0O7zp5SnddkOFCIUIhQiFCJ+CKVfjJJ61LEKhQgsIrGaprH9CvJ3WSljibijPKOF StnXSrmHQcTyTWjOWN114WU2Rkk3pefGjoRChEJEU+2YFXyVUr6v5d1vi6VknNLb+TJ2xnCplmhu K6PsIHd4KkPX5bwxvrO7lfK3UCkPyC9z5JqJ56SVXhXTms1zWmgXChEKEQoRChHPEdq1Du05LbSL ZwptX8eYYrIhC7iOcfvCynfSh6dWcDnHuP0lf/fc4sHpPHWqyYbdc435Js5rNpFdyek89U5y34cy oBChEKEQoRChEKEQkU4IV1ilynPdgULEZfVl2pmr5veGha4Oevdv0QwPpaMlv1uodXvUWbeA5l1x thUAuGqlLauFU2eTr9r77qA6eXvVMp7LnZWutiWctV0hCu0i3bNMIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiEinVB1AYBVE6HpWkghQiFCISKd0PeNsTV2Qb/fe+NM10LphE5jrmf4LMuCQoRC hEJEOqHqUYdJk1lQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiLhc +7G9UlwWFCIUIk6FUlUb3E1+od3Z7tVLvlaRv8t2oxChEKEQoRChEKEQoRChEKEQoRChEKEQoRCR TuiyLmwNM2ZM0rVQOqEfXZZh0ipdCylEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQo RChEKEQoRChEKEQoRChEKEQoRNwutdgRx0/XQgoRrv0gFCIUIhQiFCIUIhQiFCIUItIJVRfuf+d9 uBT92tvcQq3L5FsZ6rLta/Jnt04pAy3kNj2frOiuUjpbaOYI95ldtqq7SuloodkTEii0snVKaWyh FdM1zzqpV3dXKQ0t5L5Bn+zorlIqW2jlZOip0K7WKaWihVZPFec/qXd2VynQQkaDyofQ7u4q5aaF ttf0zNA6pVy0kPUY3/hfKXm6q5STFtodVUzXZf9K2d8q76RrIYUIhQiFCIUIhQiFCIWIqgDe1Svu jPeoS6Ga9+zjdyLFQuaHIgcJ1bMfr9fr+38zpaomrD4lrsQipG4nG+jc2B5zXcHlZEPtt//8vdFu y9tCWVCIUIhQiFCIUIhQiMgr1PteE50ClreFSmlvpRkxEhy5ng0GZ45kv14nn9LzzaNGICEBvMjh 0GWXHQdZOdFwKzT7wFfkvuwzoBChEKEQoRChEKEQoRDxbKHjdXbmErFfr7A7xmLv5O6yDKv1fg2l j1HG5/9vETrYKZX7HMqAQoRChEKEQoRChEKEQoRChEKEQoRCRDqh6vpDFgDIgkKEQoRChEKEQoRC hEKEQsRQBl4p8a+2t0I7svDCalhFBf9OW+jsw2vWyX59fcWvFq6ROf5tS8Jb60FD88t6FmtvL1Q7 m3RCf297jP9WkkAGhoRmbOvTLTRrj6EuoZmraJqFap91vXQt+ZolU8rgSb01vX3VRllVQqmqL684 b965FVotU0rjS/626su7ZEqpPKlXvifd7oG3g+Gh9BW9rfq33odm8Pde8qNRiFCIUIhQiFCIUIhQ iFCISCf0nBKadyJnP586x/j19bUtgFcVLztYUUazuxDJVeWU0ajicNLk0knP7Vus7MrcfOdXC+2W Snen/lsBvC1FtWoPvDU89cm2aNAVPc++y886KzvWIvLJ1pN6Rkno4S5LFcA7iKzA/Pfu1NFcvjGm 2Edxt0wpHRHF2dxWrKwl8onfFQRu+XkrTRUrV5TRPH39eL1elwsnZ3PZZT1lNCMeI7cvaKsqnVYL zTzwFfkfHbtRiFCIUIhQiFCIUIhQiFCIqH6FfWfmStB0LRSyJj+SZ7fQ1pHrJ6umZp7ZZasyFkrp mB/atiZ/F01zjNuSBM7YPvuRYp76YEdXHeQ/qXe2TinZl1pkSDT5FtrdVQfpTuqv1+v1mtFVpuLM 4l8pfc2bKjV5JgoRChHphLpmP0rZnLy9EoUIhQiFCIUIhQiFCIUIhYh0QtX1GGuxMNtsqkYdTgtn Iv889e76MU1ppStIdw5VTzasKrSFQnddGF3ouJSE+WXdC7xnnfwYDbpaaz8jt+yX0OdB6NxYclKP HiQ0m7yHlBl4kShEmIFHhKe3jxKeEhg6Lmt9HMzo2q41aFdP94ibZFNK4B1Tg8Ct2XSRj4+qDLw0 5X5mHviK/I+O3ShEKEQoRChEKEQoRChEKEQ0rUG7GvpEbKT2fQwqqtUyJJq+b9D26jrv3I1MqZTm CNUj1+2pOO9sHZelC+Dt5ja0sD3zJQPDd+pSNsTLKB4WeQMd3j7183enFNU6Y0sAr1bm+LflBSJr nlePCE9tLxCZLkweiUJEbqFVN787wtZ+vLO1YmU0w0u+lpTQvDvQ7AhRczrX7K3lb0to7gjiVe+1 kGYN2syDn5H7Tp0BhQiFCIUIhQiFCIUIhQiFiO9X2OjxleV+ZvHdZSOjisjuntJCW7MWUm8XNj0q vYNuoVQ1rGZGHp/fZbPjskMtNGOKpkkodW1hS0btoivRZGux49UoRDRHg6xPvRuFCIUIhYju3dtn ka6FFCIUIhQiFCIUIhQiFCIUItIJVa1Bm71U8J1LodoJzujibKdd1jPbOq0wW+2S0qvN1KcvPb06 AK2J7QUrxbUyPdGESBXrmMGzhLYnCWTYrqc78XZpDaurA94xPQi8q4ZVU/J2xO8S1Q9XyiCPkvp1 DrVcNTNO7KHU5KlR6d4mj864CrnKInnWs2wHzxFqHXVE8S0UdRJPXYNG3356Cc2r7PCrIc8MnlNC c4dMKTcDxZqB4JYMPAN4uwU+UYhQiFCIUIhQiFCIUIhQiOjeyGjWq213AO/959MnPVvHZVMnPe+6 aPmkZ+sk5vRJz9YPTznpGc3wpOeyWdhdKEQ8R2j7Vk+7QgmfDM/CTl1q0VKjc1aXDi9oiua0dN2u APCpUO2BZlXwrtpZaSXPuTHu4m+VSJhBaM2GCMJKJJQSc1XermOcUe65Wajn4KlqNkxfnPt+gNXB u1OhFQe942/dh2agEKEQoRChEKEQoRChEKEQoRChEKEQkU7ox8jVLedOUIj4cQ5lCFGlayGFCIUI hQiFCIUIhYh0Qr7CEgoRvsISChEKEQoRChEKEQoRChEKEQoRChEKEQoRzn4QChHOfhAKEQoRChEK EQoRChG+MRIKEQoRw5VRonlOC+3iVGjncMhxGaEQoRChEKEQoRChEKEQoRChEKEQ8feEplYbbOG9 9GGkVFW1wU+RT7aUjLorBrm0hehgaTaYXVbDapfIwb8MEu+kq/J1KpRmwupgVkH1Gv5HB51RjPaO rt25Zrba5W6lpewRu3100AFndOdtC50JXDF9P9erg54deHuByE+xre9D7yw/qXegEKEQoRChEKEQ oRChEKEQoRChEKEQoRChEKEQkU7odsV5D27TMxuXnhIKEc8Q+rwf0X9HgjvetuKNcTbeGAmFCIUI hQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWI3EIr0yWu+NVCq/M4Prnssl1ieA6tFvshlCEl 5zKvo+bgM2b+MdFktVhY5kspMWJNQj/+8EJuW7zsKi1n9MTvznyZ1UIhqcmRVAmtvNJuhXZk4DVn As8SOWhaP7QiJlt1DpmavFvinerXj1XkfsnPgEKEQoRChEKEQoRChEKEQoRCRHNRrSU1rGpEzn4+ vRBJ61TLjKmZb6G7LrqaLZshdXkO3VXRmTlp9b+zA9C58fnzSMGcl32GMf1Buhb6G0IzN6t5fgvN njhvEppdYLSUxiKjs2VKqRRaJVNKZRB4lUwpHSf17Lv6rVDKuP07K555z78xziZd8CVdCylENAWB vewzkE7I+xChEKEQoRChEKEQoRChEKEQMVQn/+vrq7xer9A5pOYF3r1TNLWHqW6h0bmi4+9JbGj5 cs32GWf/dpuu0Zq10H1uVH5O05TeyLCoNsZ2mxsUJdMiVVUHLXLASJ+FN8YZo9e7zUdO88t2Mjy2 770lvN/h328F0xYS9KZ/XZ5DPTe9kd876Hq41jxMa9Mx8KRu5W4ZRguH2OnaD0oNnMlQC23fN2jF PSrdK+xQBt4MprTQSNdOERppvaG4fc3vtspVC82eRD99uN4x45LvfmMsZV2Y4Vvo/YAj70G1ZX+v zrPqFho5eMvnN71+nL0uXHXv+7+3bHcYfh86DlDT7ae51p8j197XkNqlqSFj+zNqr7rhG+OsDRtr 6VrQNJNToZ1LUauGQStrf9x2WcQy5fBx2d1NbsYq9KZs8hXl6ZsfHbUyvRfG9BtjK39nGDQLhQiF CIWIdEJNd+oV6xqHWmhqwlsWtk42nDHcQtGiz+yylauGQ1poa47i1kSTUtanKIed1FHd9qzMl9ah TkQrPec+tCNjoZSgEOc7o932jC7b1V2lBLVQZLeFFYiMIt1ilGknde8Xq5rSmy3xzu3qmMen4kRc bZd1P3ZNnj/jTj3CaLedFiLZSbrgS3d96ln8/ZN6FIUIhQiFCIUIhQiFCIUIhYimvRauSFeYLXLB U2iXRYgN5QbdrXPt7cbhNIptleLuiNyuJ+wcimqpdPchhYhpAbwtl/0MhtPbzxi54oa2eooUOUj3 LEuXPRVWVOts4W5PF059dIQm3vaQ7qQuJWjiPBMKEX9faPSpH/7oGGXoaX8QGd4Kfdp/0nOjDGmh T6a9D62SeOeHUIZY3t+/D42iEKEQoRChEKEQoRChEKEQMVyx8kh/j3r9bS4QeUeEVPMugXfU1u1s FmoprdJTt/OO28ooVxKnHxRUIiisQOSUeFmGNbFNZTaI0AXeWUi34jx8Omb0i+TtsiwoRChEKESk Ewq/U4cFX2akGfeQrsuGkrfp94dfYR8RWqhppciFlacDxdplOC3DpSEhOtgd017QehZNTh1Kfx5k Rvd0Cc046B3PujHuQCFCIUIhQiFCIUIhQiFCIWI4Ay/61XZ49mNkb44znrX0tGdDo9H4a3cLHQPJ yGS3IaF3HpOBtz1elu4qi8C8DkIhQiFCIUIhQiHib6dzRZDuJX9avn0pkxbFrZQp5a/n24/KlJLw JX94bD91suERYfLVKEQoRChEKEQoRChEKEQoRKQTCimheUaqwmxbwlN3pKjyFUW6k1ohQiFCIUIh wik9It3EuQ9XQiFCIUIhQiEindC0EpoOpe8IG0obwDtBIUIhQiFCIUIhQiFCIUIhIp2QATwi96jj E+cYi0KMQoRChEKEATzCAB6R7qRWiFCIUIhQiFCIUIgwgEcoRChEKEQoRChEKEQoRChEpBMa3gOv lMVl6Wv3WjiYNunZu6HD6Dyje+AReJX9qT3wwkto7tge41vILecuSPfoUIhIJ9R1Us/cdLarhWbe ErqEZm4l1tVlPYW0a0l3UitEfAu5B94Ft0I7WumH0CNCCy3DoSlFRq9a6TjY50EP4ahRR/geeCMy pdw8Omq2mosUOagal9EGfcfPIi6Kyy7bxbNujDtQiFCIUIhQiFCIUIhQiFCIuM3AG3m77f2sdC2k EKEQoRChEKEQkU5oWlGtXtK1UDqhaRl427dPjUIhQiFCIUIhQiFCIcIAHqEQoRChEKEQoRChEKEQ oRCRTujXhNXuDJh0LaQQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRDxa/ZjdzwvXQspRChEKEQo RChEKEQoRChEpBMarhQXHfBL10IKEQoRChEKEQoRChEKEQoRChF5hd6rCe4qn/lDqJR9dTzfydtl PVVPZyzC7G6hWd1bnd7+/u2jymWi0Ov1uvzmq074X13WUxt/+vYY1D2fvxMJzn64fHm3wCcKEQoR ChEKEQoRChEKEQoR4SU0R4dIoS0UMV4LE1q2w1svvaOVEKHISYdhoVRR6Rnj/dDpmG3zQzOnY0JO 6sjxf7PQ7FzqJqEVid3VQquyzP9GCc3/1JZzt0J3W/TMkqpuoVVSTV22Qqr5HJotle4lP+yyj2ql 7haaJTXUZTOkhs+hrU/7WkZaadoL2vZix1FSoV0WIRV+Do2e5JbQJBQiFCIUIhQiFCIUIhQiFCLS CU3bA6+XdC2kEKEQoRChEKEQoRChEKEQoRChEKEQoRCRTmjacp2tCys/2bqw8oyRlv2VNLmbdCe1 QoRChEKEQoRChEKEQoRCRDqh2wBeKbGvtTWfjy0UtQq49nPSdVmV0Mr8jiUt1PKFntllpWysrhNN 6OLcnjJSLZ/XLDTKlPXU6cv99HZb7Reb1mVT1+Sv7LYpCW8jy36G8stmML1S3LYCAAdLc4N6ira1 8vz09rtvvT2/7E5ie2hha0pgutTkT1JUtZjVSunSuZ476jhja4mEGiIEzcAjFCIUIhQiFCIUIhQi FCIUItIJTcvA6/2s2xZKWXZstVS6c+i5EcU/Ey9rpUloRSs1BfBKmS/1zHhZdKjzjuee1Kta6dmh hRUn+HCsY3s9xjO212NMGVqY1XWh96Ht8bL0E+elJC0QmbIeYy/PfbgSqWqcH2zdJXAW/40Q59Ak hQE8QCFCIUIhQiFCIUIhQiFCISKdEG7jfHA3PJ6+0XWtyNnvTBt1fH19dU0ajM5+VHfZQc3M2fFv Pa11KtQSwD1+Nm1KLzL3Zzh7ajTPdfpuFD3nQMqx/QjfQpGrGkbmsPO2UBYUIhQiFCIUIvIKRcZQ lyTeriJ82WBoiHNGlKH1M09jHT2vssu3Aj8bpx3/HbnU4jYaNLv6wBnpXvJx5Pp+gOis3y6hWQe+ 4lk3xh0oRChEKEQoRChEKEQoRChEYAnNWtItrOyNr32Sbvny7aijphuuAnjbCiK9Xq/nbCffw9TV wtv3t49AIeJvC6W8U7+zvLjfO1HzjM1rPz6JnlWbsm9Qum16RhjuslIWTnq6a3JRiFGIUIhQiFCI cA88QiFCIUIhQiFCIUIhQiFCISKdkBl4hBl4XUJm4F0JmYF3Qroboxl4hEKEQoRChEKEQoQZeIQZ eMR/KwOvq8tnZOB9EnaVRb3kt3yxpoqVLWuFes+paRl4r9cr38LK9y9Q+2VC1g/dsX1P4FEUIhQi FCIUIhQiFCIUItIJmYFHTMnAGxGbkoE3wn8rA2/7uMz9OlagEDE1A+9PJLwNCd3NMW5LeIuUKWXC SZ1uIcH2p/0hEUVIC5098bc/7c/waT8DhQiFCIWI6UKhywZ7GL05ugceoRChEKEQoRChEKEQoRCh EJFOyAw84r+TgdfbUlWLc3sjiyEz+TuKsb2Dl/3QTuzOMU4gfOnp9NBCdFye+CUUGYPv4bSFrqRW iA2tyZ8xtYQTVrWtEiVXPYO2SqxrSm9mVw7PMUZXPXW5DpHu4Xq7Ss+qp2VCBt4ooRl4S1bH1LbS tNUxd0/6lgy80GHQ1UFaCF+u01vxJMUeeBEi1UIzDnrHs26MO1CIUIhQiFCIUIhQiFCIUIj4V8r8 Eerfra6zg3+l9K+9nzEKSddCChEKEQoRChEKEQoRChEKEQoRChEKEQoR6YQM4BEKEQoRChEKEQoR ChEKEQoR6YSmLM7972yPsQOFCIUIhQiFCIUIhQiFCIUIhYhnCbnlXAnOt5+yk0Bvvuoj9sDrYcoe eNPqU+/Y6NoMPOJZd+odKEQoRChEKEQoRChEKEQoRJxm4EW8qvZ+5pQWCo8o7qiqc/C/UmJHE6Gz HzPonv2I2mZnlNAWSrmx4zvD0zEZui2shVJsqHZHWC293d0W0kKRz8JToZ2tlO71Y1go+tXlUmhX t/2tLpvxptk0T72i28K6bPu+0rNaC4VWd1tIl0W+k1cJrWylv3UfKiU+IFMttKpo7d/qshmtZgCP UIhQiFCIUIhQiFCIUIhQiEgnNBzAi/7bdC00FMC72m6u92+/hTJtvp2my45GWRIEbuFSiD50+gza yvPo7sukmPR8/9tpJ/XSrZ5mVtD9uzHXUvr27Pz8m2ahlu7avjtXBH8rCHzWXXdfqKa7m4QeFZ6K oipM3sq0zJeD0USklr9f1mW1519T9lQLny0wvGzw7gN6zpHhFpp5id99oa4WmknuNWizDtJCeAYe QZ+ZbqXn8Aaz0Tzj4boThQiFCIUIhQiFCIUIhQiFiO81aFGVTUY/JzS0EPGlwsv9jBJW7mdZMZvV 9WNCyv1Edu3wHGNUV90K1R74jGWZL2fMuApD8zqmJ5qccVUmalleR2+RrV66shZaf95Cuqf9cJLA tqyFVQzfGKNP8O5o0Cy6umxmXDbs9WNJrvTdk3zWbHJTl5HE1AIANR8+47HyjBvj6LcMXYPW80q6 9OFae7Coe9MPoeg78tBynYjRw5ZX2FZaW8kAHqEQoRChEKEQoRChEKEQoRCRTug0A6+U2MhQcwDv EQUio8ZoYQUie5hej3H0AOH1GFtYVv4wZYiTmF5tkA44k/CY67QQJx346t9GCV2Tv3x+aHuyUkt2 3baY69n+QZGEvA9tL103k+EWSlUpbkbLpXunVohQiFCIUIhQiLCEJqEQoRChEKEQoRChEKEQoRCR Tug2A2+UJYVIZpNO6LvLRkcUqXbnigwiT+myJQlvV2zJ67giOt5fSnCXbV0tvC34UiMTyTODL+/M LDBaytMiisTW4Mvsrjp4xkKCd2bcje9oPoe2VorbXiLhndVddTCcXxbNlPyyEULyyyIJyy+L4ja/ bEce021+2Y5zCaNBI1IOpWcQNpSOIl0LKUQoRChEKEQoRChEpBP68ca4oooXka6F0gndvuRvHQZl QSFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiEindDtlN6OlQ7pWiid0I8uyxC7T9dCChEK EQoRChEKEaclNHc+09K10P9KmbuHSys5W6iUHO9CpTQugV9B3i4rJUe3PSeNYhe/hHbfk/K3UCkP eJalSudazaXQrm7rTgmcxXO6rJQ996RntVApm7Onapjdbc/rslKSZeCdkT7fPpLutNJZrfTcFirl AaGF5Rtd72A4vT1VqZYZNFU9PUhVkWA2ChEKEQoRChEKEZf7l72TftQxk3RC/0rZP/P6TroWUohQ iFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhIJ1Q1C7uSdC2UTuh0FnYn6VpIIUIhQiFCIUIh oroAwNbtMc7YvgT+EelcLoE/SB0mXx3T/yWUfs+XM7atON9e7Pjum2+/U5PA9CXwNQdwxfnBzpHs 1yvTOLo85Vm2E4UIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiF CIUIhQiFCIUIhQiFiHRC4dlTo8uR0rVQOiGzpwiFCIUIhQiFCIUIhYjTrIUUqTifMtvTuV6vV4ra nrnPoVL2V0CtSqNYKXWZxZl+I6NVKEQoRChEKEQoRChEKEQoRChEKEQxETWvAAAOpUlEQVQoRChE KEQoRChEKEQoRChEKEQoRChEKEQoRChEKERUbQV+FQSeEZe9FKqJRB+/Eyl22mWtYfHIMPqvFqqp enr2O19fXyEtdbo65k7m+LdZcf3bq4wOOmMFxI8uy7BqON19KJ1QdUnxVZwKpViDdrB7/5cfLdRT Wzj6C3wL7a5LfZDuKrsUcsnX/zEktKz6cs3BphfMPjtn3g/6vkZ2W9H1T4FPkRkn/g+hlgMse0Gj t0H6+Wh3WsGbUIhQiFCIUIhQiFCIUIi4HUo7ci0KMQoRChEKEVUBvFLWBfGqWuhuvB49PXMr1HKw KKmmc+iY+Zg5Z111Dl0F8aIk3sEWaj1pRwWHIoq1v9PClPvQSCuFCH220kir/c0WikQhQiHibwpF jnjx9WM1VeGpkZ+30rQG7b0rZr3S3hYi+TwotUb4CquzA9QeJOo1pOoqGwnotWIAj1CIUIhQiFCI UIhQiFCIUIhQiFCIUIhQiDADj0iXgVed+bIieFdKxTm0MnhXCqQErg7e/RJqZeqa/N1ZUwfD1Zcf EeIcQSFCISKv0Ejec+TuA8MtFL0VQu4MvNF09Yi7Nr5+tATvIjiNBvUccGq8rDUTL/IBW/W0TzHq mH3gK/LeqbOgEKEQoRChEKEQoRCRTqg6r+OOZesYd6AQoRChEKEQUT378c7MkWxXAO/9Z0tm8nvm F6OoCuAdrUBBvClCdzKf/z69ZFSGEFXeDLwMrVPKzUz+9lp66VooCwoRChHd9RhncVuPcQdhEcUo 0qUE/qpPfZXktiqAd1og8oyjfsPsd+yQAF4kGMBbPeowA49QiFCIUIhQiFCIUIhQiFCIUIhQiFCI UIhIl4E3VLFyxrTM8N5T0WmB1atjtq04b1l6M6PAdmgGXgShGXihiSYZWqeUhDP56fbAS/foSCc0 nMUZTboWyis04ybXQ94WykJIBt6yGufHwa72AD77/1HCMvBKmVhCs2f11JJX2JraDMsiijMPekfu yz4DChEKEQoRChEKEQoR6YTSTQs/ZzpmRU38M5qSJle8ylZnvqx6r666ynzJz4RCxL9S2nct2ZrO tZp0Qv9K4Zkz70OZUIhQiFCIUIhQiFCIUIhQiEgndDr7sTMpL10LKUQoRChEKEQoRChEKEQoRChE KEQoRChEdJXQLOU+gjSl2HFL9t30Bd47Vpof/Oqymi6a1TqnQncin/+2fA88YkZdz+ESmtE8p0Ck 2VP/h0KEQsRzhLZn4GUpqWcJTSJdCc1f70NnUrMl3hkqobn0fYgOtm358urbwXPu1LsIvzGOdnH+ geLZwc6+9az70lBexztTNwfdye1CgpUpybdCsw96R7ouU4hQiEgn9OOyz1ClKV0LKUQoRChEKEQ0 Jd6uyH8dfsmPrlhZVaGphqhhUdMMGu2BFyHVPfsxK4gXfpWNCg4H8JZGFHegEKEQoRChEKEQoRCh EJFOyD3wCIUIhQiFCIUIhQiFCIUIA3iEQsSvhZW7SddCChEKEd6pCYUIhQiFCIUIhQiFCIUIhQiF CIWIdEJONhAKEQoRChEKEQoRChEKEadr8t2m5w2FCMvSEwoRChHeqQmFCIUIhQiFCIUIhQiFCIUI hQiFCIUIhYj8QrvL0/8QWlE9h/i3u0U+Ga6MEk26Sc9/GVYzvJP/st+NQoRChHkdhEKEQoRChEJE UwnNT2YMCkJbKOJR0y00a7TSJTRz/BbSZZFvBc1CsweWTUIrhtpDXTbjBa5aaNXb5O2NccdERFeX zXzXDrsPRVG9X8fWvadq2P7oWLUzTlMLrRg4Dj/LtpeDnt11f+M+dMaSGud3zOq65z7taxltJUto EgoRChEKEQoRChEKEQoRBvAIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWIdEKW0CQUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCKallq05gZdrYu9+5uqFvr6+rr88Kuf3S3SvftZeCpO7d98fX2d tlRTGsXxv1qRnr/BLM6zDzv+7fMD3//78++u/uaTKZVRWv7uUzB8CTzJ0M/T3YcUIhQiFCIUIhQi FCIUItIJmYFHKEQoRChEKEQoRChEKEQoRChEKEQoRChETA3gDQtdUROMW1YgsiUgF8Gt0FkXtgbk WukK4L3/+/ayY8So4HBEMVUJzRkoRChEKEQoRChEKEQoRKQTMoBHKEQoRChEKEQoRChEKEQoRChE KEQoRChEDMXLZgx6hxLeooN3l0KtEZ1IseptC1dt+/Rr9qO1aHZ0ke0fV1nEN/+7Abws28pftlDL N69ZcDAstAuFCIWIvEIjl27k4yNvC51R00pTV8dEPJdGPwPfh85evpa+D/UecOoatLtlXTNlLoXe D0RLvqLfhwzgEQoRChEKEQoRChEKEQoRChEKEQoRChEKEZcZeLUzaltygygDL3J65nJ+qCeIty2A dwjMkDIDj8gbwItke7zsquRqD3+zhSJRiFCICBGKfHxMaaF096ER0kUUqwN4pdQF8aa/D71DrRHx 5O+Ol82QQaGag7VGH4nud+pZPOuy34FChEKEQoSbgxIKEQoRChEKEQoRChEKEemEmmY/3rmLDo28 6HXHy2Zk310KjSQIjPJLqKeLpgqRyOe/Tw3g7Vz6fjAcwIsm3X3oMiVw16AxbwtlQSFCIeJSaFdm 8GVK4C6e02Wl1L2kLU8JPDvoDJGDX+9Dr9ereVvmSC4z8GqIjpVdCtUcbNZV2f0KO4tnXfY7UIhQ iFCIaFqMcsWy5O0dKEQoRChEKEQoRChEKESkE6reA2/VxPpwBl40KLR6rnF4CXw0VS/5K2dAsMtS TccYwCsKMQoRChEKEQoRChEKEemETDQhFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiwjLwokiXgXfa ZTsz8H4JnR3gWMp81RrTyo5dyZzJzZLqjpdtjUqvZGhh5YxWSheV7srrmEn3zkqzTurbfYNqWyZS rnojoxVl65qEfvzRxAdu131o5t266ll2xdT70PvlvXOj0L+VozhDGh8dZ9l3VzIR5xTuCVzLtIqV PVl1SypW1tRkWL7z9qyD3pHujVEhQiFCIUIhQiFCIUIhQiFCIeJ24nz7lN47u6Se0WU7UYj4V0p9 bOxg5mg2XQulE/pXCpfHTJXwthqFCIUIhQiFCIUIhQiFiOqaDSkrVq4Qe06XXUUWZ7/OGsAjFCIU IhQiFCIUIhQiFCIUIhQiFCIUIhQiqkto3hEZPUrXQgoRChEKEQoRChEKEQoRuYV6drWdXgCghRmh quoiEncV4SM5TXg74wjezV591RRR7P29FpoDeGc/25K8vYrc96EMKEQoRChEKEQoRChEKEQoRChE KEQoRKQTOs3AaxnMRk8+/O/sQ1LWsNpF6AxaaGG2LN0W1mXTaljVMqsFh6eFownpsu2bpaeYFl4F ttCqSpUHzV22JfNlZ7dVJyudsXwm/5MV96XnPu1TbFL8mP1cLSLxTvr8su0ZeCsk3nneObQahQiF CIUIhQiFCIUIhQiFCIUIhQiFiHRC3QG81r+p3XDktIVWTN1dfYHTiCKxdCa/lyVbzs3irkcuI4qR tLTeZQtdfcj7vy/fcq6VKZthtRK9pc9tiPOTnhZo/ZvbFloh8El3l/WkUdT8XnesYxZdMdfac63n SwzHXKNZttSi9jyrirmubKVpsY7eLxH66Ji6sWPkg7Pls5paaEVUKPwFLWSV3kya39fNwAMUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCIu98DrCeLV/t0dl/Gy1o36ImS+hSI+bEk6V01EKJqmWMcVU7On aAZ2Sw2rK7YlmtTOU29NxUmRaLKDrswXE012kvtO3XLQJZnAd6yaX69aP3TIrAjs/RJqPcjyEpqf rTK7634I1X7bmV2XN0ex9eE5q5X+F/lhEZ9jAI9QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIjIWUKT DrKSrgy8gyVTeiNMXQK/i8uYa/p5amJ7Tc9Z3AaBa2Md20toziS/0KPC5CuoCpOvpKqFrlL80mcC R7AknauF7rRSVzaUYk3PUsrTuqyUzUHgMx6bmhzFs9JKU1WBT7+TwKqb5Heh2rsW+U8Xqr0t5bvj WfYtlGWBQ7ouU4hQiFCIUIhQiFCIUIhIJ1T1Tl3L344GZaH7nXrWFF9XC6UqMjore/Ng+Bz6b6YE njG7qw66u2zrxPmqWfxSnjbpueq8eec5k56p5hh3dNVBVZdtnWNceYmf0ZXwNpPL/LJSNk96ntHT YukrVraSTsh5akIhQiFCIUIhQiFCIUIhomsGbeZgoGqT4kNkBSi0emhU3UIHW2c/doxin3OV7Rrj P6eFdqEQoRChEPEMoe1ppcTKyawfrx8ZpoUvawsfbJk431Eq84rbOmg7uvBXHbTdM/qYo7iaqpTA 1Du8zUYhQiFCIUIhYmhB0wyem5q8iqZM4BSL4s6kti+sTJmB93q9LgtnbxE6SLUGbQUKEQoRChEK EemEbmfQHlOIZCYKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRP+YYdy9mKiVhCylE KEQoRChEfC/OzbCWupSTuh+7xXKuyX9faHKQorpOBqmcV9k7u1spfwvtRiFCIUIh4plC2zNf0u/O Vcq6l7fmFedbly/vyMxrKpFA/x7BZRGJXZl4TQu8V1A16ki5BH4VChEKEQoRChG/hFJOWL2ztZRv Bn7NMb6zrZTv7ioE7+Qcdbxn1u2OKn630G6Rg9xXWQYUIhQiFCIUIhQiFCIUIhQiFCIUIhQimmId pcwfUJ4K3U1aHT+rEXv/nNov0j2DNmumDWucv3+zT4m71uoV/lGxsnbCis6vkYmvripfLfHY1ovg dg3aHbOutl9FRrs+JHBKsLlw/xmpdiuNRiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCISKd0P8DU3MdyMKZsxcAAAAASUVORK5CYII= "
+ preserveAspectRatio="none"
+ height="1244.6"
+ width="9.5249996"
+ style="display:none" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#fd0000;fill-opacity:0.635071;stroke:none;stroke-width:0.264583;stroke-opacity:1"
+ x="-2.5308407e-06"
+ y="-873.23492"
+ id="text4630"><tspan
+ sodipodi:role="line"
+ x="-2.5308407e-06"
+ y="-873.23492"
+ id="tspan4634"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.5819px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#fd0000;fill-opacity:0.635071;stroke:none;stroke-width:0.264583;stroke-opacity:1" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;line-height:13.0757px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.221634"
+ x="-0.109361"
+ y="-256.69623"
+ id="text4642"
+ inkscape:export-xdpi="91.400002"
+ inkscape:export-ydpi="91.400002"
+ transform="scale(1.008509,0.9915628)"><tspan
+ sodipodi:role="line"
+ id="tspan94"
+ x="-0.109361"
+ y="-256.69623"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">А</tspan><tspan
+ sodipodi:role="line"
+ id="tspan96"
+ x="-0.109361"
+ y="-243.62054"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Б</tspan><tspan
+ sodipodi:role="line"
+ id="tspan98"
+ x="-0.109361"
+ y="-230.54485"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">В</tspan><tspan
+ sodipodi:role="line"
+ id="tspan100"
+ x="-0.109361"
+ y="-217.46915"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Г</tspan><tspan
+ sodipodi:role="line"
+ id="tspan102"
+ x="-0.109361"
+ y="-204.39345"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Д</tspan><tspan
+ sodipodi:role="line"
+ id="tspan104"
+ x="-0.109361"
+ y="-191.31775"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Е</tspan><tspan
+ sodipodi:role="line"
+ id="tspan106"
+ x="-0.109361"
+ y="-178.24205"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ж</tspan><tspan
+ sodipodi:role="line"
+ id="tspan108"
+ x="-0.109361"
+ y="-165.16635"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">З</tspan><tspan
+ sodipodi:role="line"
+ id="tspan110"
+ x="-0.109361"
+ y="-152.09065"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">И</tspan><tspan
+ sodipodi:role="line"
+ id="tspan112"
+ x="-0.109361"
+ y="-139.01495"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Й</tspan><tspan
+ sodipodi:role="line"
+ id="tspan114"
+ x="-0.109361"
+ y="-125.93924"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">К</tspan><tspan
+ sodipodi:role="line"
+ id="tspan116"
+ x="-0.109361"
+ y="-112.86354"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Л</tspan><tspan
+ sodipodi:role="line"
+ id="tspan118"
+ x="-0.109361"
+ y="-99.787842"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">М</tspan><tspan
+ sodipodi:role="line"
+ id="tspan120"
+ x="-0.109361"
+ y="-86.712143"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Н</tspan><tspan
+ sodipodi:role="line"
+ id="tspan122"
+ x="-0.109361"
+ y="-73.636444"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">О</tspan><tspan
+ sodipodi:role="line"
+ id="tspan124"
+ x="-0.109361"
+ y="-60.560741"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">П</tspan><tspan
+ sodipodi:role="line"
+ id="tspan126"
+ x="-0.109361"
+ y="-47.485043"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Р</tspan><tspan
+ sodipodi:role="line"
+ id="tspan128"
+ x="-0.109361"
+ y="-34.409344"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">С</tspan><tspan
+ sodipodi:role="line"
+ id="tspan130"
+ x="-0.109361"
+ y="-21.333645"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Т</tspan><tspan
+ sodipodi:role="line"
+ id="tspan132"
+ x="-0.109361"
+ y="-8.2579451"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">У</tspan><tspan
+ sodipodi:role="line"
+ id="tspan134"
+ x="-0.109361"
+ y="4.8177543"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ф</tspan><tspan
+ sodipodi:role="line"
+ id="tspan136"
+ x="-0.109361"
+ y="17.893454"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Х</tspan><tspan
+ sodipodi:role="line"
+ id="tspan138"
+ x="-0.109361"
+ y="30.969154"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ц</tspan><tspan
+ sodipodi:role="line"
+ id="tspan140"
+ x="-0.109361"
+ y="44.044853"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ч</tspan><tspan
+ sodipodi:role="line"
+ id="tspan142"
+ x="-0.109361"
+ y="57.120552"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ш</tspan><tspan
+ sodipodi:role="line"
+ id="tspan144"
+ x="-0.109361"
+ y="70.196251"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Щ</tspan><tspan
+ sodipodi:role="line"
+ id="tspan146"
+ x="-0.109361"
+ y="83.27195"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ь</tspan><tspan
+ sodipodi:role="line"
+ id="tspan148"
+ x="-0.109361"
+ y="96.347649"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ы</tspan><tspan
+ sodipodi:role="line"
+ id="tspan150"
+ x="-0.109361"
+ y="109.42335"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ъ</tspan><tspan
+ sodipodi:role="line"
+ id="tspan152"
+ x="-0.109361"
+ y="122.49905"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Э</tspan><tspan
+ sodipodi:role="line"
+ id="tspan154"
+ x="-0.109361"
+ y="135.57474"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ю</tspan><tspan
+ sodipodi:role="line"
+ id="tspan156"
+ x="-0.109361"
+ y="148.65044"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Я</tspan><tspan
+ sodipodi:role="line"
+ id="tspan158"
+ x="-0.109361"
+ y="161.72614"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">а</tspan><tspan
+ sodipodi:role="line"
+ id="tspan160"
+ x="-0.109361"
+ y="174.80183"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">б</tspan><tspan
+ sodipodi:role="line"
+ id="tspan162"
+ x="-0.109361"
+ y="187.87755"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">в</tspan><tspan
+ sodipodi:role="line"
+ id="tspan164"
+ x="-0.109361"
+ y="200.95325"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">г</tspan><tspan
+ sodipodi:role="line"
+ id="tspan166"
+ x="-0.109361"
+ y="214.02895"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">д</tspan><tspan
+ sodipodi:role="line"
+ id="tspan168"
+ x="-0.109361"
+ y="227.10464"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">е</tspan><tspan
+ sodipodi:role="line"
+ id="tspan170"
+ x="-0.109361"
+ y="240.18034"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ж</tspan><tspan
+ sodipodi:role="line"
+ id="tspan172"
+ x="-0.109361"
+ y="253.25604"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">з</tspan><tspan
+ sodipodi:role="line"
+ id="tspan174"
+ x="-0.109361"
+ y="266.33176"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">и</tspan><tspan
+ sodipodi:role="line"
+ id="tspan176"
+ x="-0.109361"
+ y="279.40744"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">й</tspan><tspan
+ sodipodi:role="line"
+ id="tspan178"
+ x="-0.109361"
+ y="292.48315"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">к</tspan><tspan
+ sodipodi:role="line"
+ id="tspan180"
+ x="-0.109361"
+ y="305.55884"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">л</tspan><tspan
+ sodipodi:role="line"
+ id="tspan182"
+ x="-0.109361"
+ y="318.63455"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">м</tspan><tspan
+ sodipodi:role="line"
+ id="tspan184"
+ x="-0.109361"
+ y="331.71027"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">н</tspan><tspan
+ sodipodi:role="line"
+ id="tspan186"
+ x="-0.109361"
+ y="344.78595"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">о</tspan><tspan
+ sodipodi:role="line"
+ id="tspan188"
+ x="-0.109361"
+ y="357.86166"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">п</tspan><tspan
+ sodipodi:role="line"
+ id="tspan190"
+ x="-0.109361"
+ y="370.93735"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">р</tspan><tspan
+ sodipodi:role="line"
+ id="tspan192"
+ x="-0.109361"
+ y="384.01306"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">с</tspan><tspan
+ sodipodi:role="line"
+ id="tspan194"
+ x="-0.109361"
+ y="397.08875"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">т</tspan><tspan
+ sodipodi:role="line"
+ id="tspan196"
+ x="-0.109361"
+ y="410.16446"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">у</tspan><tspan
+ sodipodi:role="line"
+ id="tspan198"
+ x="-0.109361"
+ y="423.24014"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ф</tspan><tspan
+ sodipodi:role="line"
+ id="tspan200"
+ x="-0.109361"
+ y="436.31586"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">х</tspan><tspan
+ sodipodi:role="line"
+ id="tspan202"
+ x="-0.109361"
+ y="449.39154"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ц</tspan><tspan
+ sodipodi:role="line"
+ id="tspan204"
+ x="-0.109361"
+ y="462.46725"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ч</tspan><tspan
+ sodipodi:role="line"
+ id="tspan206"
+ x="-0.109361"
+ y="475.54294"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ш</tspan><tspan
+ sodipodi:role="line"
+ id="tspan208"
+ x="-0.109361"
+ y="488.61865"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">щ</tspan><tspan
+ sodipodi:role="line"
+ id="tspan210"
+ x="-0.109361"
+ y="501.69434"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ь</tspan><tspan
+ sodipodi:role="line"
+ id="tspan212"
+ x="-0.109361"
+ y="514.77002"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ы</tspan><tspan
+ sodipodi:role="line"
+ id="tspan214"
+ x="-0.109361"
+ y="527.8457"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ъ</tspan><tspan
+ sodipodi:role="line"
+ id="tspan216"
+ x="-0.109361"
+ y="540.92139"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">э</tspan><tspan
+ sodipodi:role="line"
+ id="tspan218"
+ x="-0.109361"
+ y="553.99713"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ю</tspan><tspan
+ sodipodi:role="line"
+ id="tspan220"
+ x="-0.109361"
+ y="567.07281"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">я</tspan><tspan
+ sodipodi:role="line"
+ id="tspan222"
+ x="-0.109361"
+ y="580.1485"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ё</tspan><tspan
+ sodipodi:role="line"
+ id="tspan224"
+ x="-0.109361"
+ y="593.22418"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ё</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+ x="0"
+ y="-1286.5312"
+ id="text5550"><tspan
+ sodipodi:role="line"
+ id="tspan5548"
+ x="0"
+ y="-1286.5312"
+ style="stroke-width:0.264583" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+ x="0"
+ y="-1286.5312"
+ id="text8872"><tspan
+ sodipodi:role="line"
+ id="tspan8870"
+ x="0"
+ y="-1286.5312"
+ style="stroke-width:0.264583" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+ x="0"
+ y="-1269.8625"
+ id="text8876"><tspan
+ sodipodi:role="line"
+ id="tspan8874"
+ x="0"
+ y="-1269.8625"
+ style="stroke-width:0.264583" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+ x="0"
+ y="196.98749"
+ id="text4641"><tspan
+ sodipodi:role="line"
+ id="tspan4639"
+ x="0"
+ y="196.98749"
+ style="stroke-width:0.264583" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+ x="0"
+ y="230.325"
+ id="text4649"><tspan
+ sodipodi:role="line"
+ id="tspan4647"
+ x="0"
+ y="230.325"
+ style="stroke-width:0.264583" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
+ x="0"
+ y="10.456248"
+ id="text4532"><tspan
+ sodipodi:role="line"
+ id="tspan4530"
+ x="0"
+ y="10.456248"
+ style="stroke-width:0.264583" /></text>
+ <image
+ sodipodi:absref="C:\Users\kiril\Documents\PlatformIO\Marlin\Marlin\src\lcd\extui\lib\ftdi_eve_touch_ui\ftdi_eve_lib\extended\unicode\font_bitmaps\romfont_31.pbm"
+ xlink:href="romfont_31.pbm"
+ width="9.5249996"
+ height="1244.6"
+ preserveAspectRatio="none"
+ id="image106"
+ x="13.229167"
+ y="-264.81683" />
+ </g>
+</svg>
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm
new file mode 100644
index 0000000..39cb670
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm
Binary files differ
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png
new file mode 100644
index 0000000..baafc82
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png
Binary files differ
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png
new file mode 100644
index 0000000..ef68192
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png
Binary files differ
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg
new file mode 100644
index 0000000..f803126
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="38"
+ height="2107"
+ viewBox="0 0 10.054166 557.47707"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
+ sodipodi:docname="western_char_set_bitmap_31.svg"
+ inkscape:export-filename="/home/aleph/git-repos/marlin-devel/tests/ftdi-eve-lib-examples/unicode_demo/src/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="3.6948106"
+ inkscape:cx="-66.497155"
+ inkscape:cy="512.92836"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="px"
+ inkscape:window-width="1330"
+ inkscape:window-height="965"
+ inkscape:window-x="59"
+ inkscape:window-y="18"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid4838"
+ spacingx="10.583333"
+ spacingy="12.964583"
+ originy="0"
+ empspacing="1"
+ color="#000000"
+ opacity="0"
+ originx="8.1491663"
+ empcolor="#3fff69"
+ empopacity="0.25098039" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid4528"
+ spacingx="10.583333"
+ spacingy="12.964583"
+ originx="0"
+ originy="2.6987499"
+ color="#c93f24"
+ opacity="0.1254902"
+ dotted="false"
+ empspacing="1"
+ visible="true" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid4530"
+ spacingx="10.583333"
+ spacingy="12.964583"
+ color="#3f5fff"
+ opacity="0.69019608"
+ originy="8.8106248"
+ empcolor="#593fff"
+ empopacity="0.25098039"
+ empspacing="1"
+ visible="true"
+ enabled="true" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid4532"
+ spacingx="10.583333"
+ spacingy="12.964583"
+ empspacing="1"
+ color="#ffa03f"
+ opacity="0.1254902"
+ originy="10.689166"
+ visible="true" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid4653"
+ empcolor="#ff663f"
+ empopacity="0.25098039"
+ spacingx="10.583333"
+ spacingy="12.964583"
+ originy="6.6145831"
+ visible="false" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,260.47708)">
+ <image
+ y="-947.59998"
+ x="-1.7763568e-15"
+ id="image4606"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAABJgCAYAAACFiF0FAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnetu6zrSKJnBev9X9vlxPgWOI6l4aZKt7CpgMNgriVUmdSOb3fx6vV6vkoj/7Rb4RCFCIUIh QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHi3/t/fH19 /fjhjkUP6VpIIUIhQiFCIUIhQiFCIUIhQiHixzt1hoXD6VpIIUIhwpEroRDhnZpQiFCIUIhQiFCI UIhQiFCISCdUNQxaOTxK10IKEQoRzxG6urRnj26f00K7OBXa1V2llPJlVQtAIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHiH//K/+c9iHc2cUs/ryVdCz1TaFV3VQutRCEindCPaNDn goEIWk/ydC2UTgiXL6+8B5WSsIWqhejbR0VKb4XoqptxVT63y1aRTujr9Xq9MtyhD9K1UDqhf6Xk uEMfpGuhZwjt6q5LoZ0oRChEuAaNUIhQiFCIUIhQiEgnVB1aOJj5+lpKwhZSiEgnVHVSX82OzDjB cUqvdqomakrnUqjnABFSp1129sE0pH7/t+khzpWpOb+EWpu9tuW6hWoO2PM7taS7D6UTan7aX7Hk xljKnHjGHb+Eoq+aVqrPoVVSTTmKLc+2Xm7nh2oOvnQWtuZg0a1WdaeuFYuga0rv7uBbVsfctdpo Sw09OlKOy5a/ftQQ2VJWGyRyC3120eox2S+hqINNHwbdDaWjn/6nj46Rg0x5dPR+aMRt4vIl/6rU zywRFDo72Oz5xVKy34cykE6oaeS64mGbroUUIhQiFCIUIhQiFCLSCQ2Fp2ZQHQ1aMQP7S6jmgLOl cBh0JjIaNbzju4VoiNMiMNK94VfZ1knPTyLOr2n3oe1pFOGZwFdj+OgDEpeXfcv5MC3xtickPj0D 724Vw4rn2WmX1R54+XKd1TKlPOV9iLhrndF3qbB1jHe3ieNnNWIhXRYZgmhqoZoTeTSg17Wyobar 6HOGhGqIWBoWUkQikqbwlLOwn7S2zvRX2EPiToZEP0cg9PtN0aAaUow6aqVrfi98ld7yhythMZvZ KEQoRChEKEQoRChEKEQoRAylBM4YyQ7NU88IUw13WXSksSvmOjOqWBVz/eyWmflD3Rl4LqzcRUho oZSJsY6amfmlVxkxexnG0KMjWqaUgRXnswJ6l102Mq84Qmh6ewS/zqFdIgdd6e0UG3v/XyvfLdR6 Oc9aslN9Uq/KEP5fywe3SvW0YPN9aHZLdWdxfhL1Ktv9tJ9VazhnWmlv5t3Z3179W5PQGbXjsuhL /3SF1d0Bj/+uWcnQw9Qq8D1dF5ISeDeIbJW6XdDUeheOaGFLaBIKEQoRChEKEQoRChEKEQoR6YSs rkMoRChEdM3kz+Q5LbSL0PpDEaRrIdwDbzXpWkghQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhIp1QeDGbUbqK2cykuXZMKZvW5F9hMZsrmVVUd9m2qqcHu9IpToV2RqfT3am7cxRnUZXFuZLn ddlqqmpYreSH0O7zp5SnddkOFCIUIhQiFCJ+CKVfjJJ61LEKhQgsIrGaprH9CvJ3WSljibijPKOF StnXSrmHQcTyTWjOWN114WU2Rkk3pefGjoRChEJEU+2YFXyVUr6v5d1vi6VknNLb+TJ2xnCplmhu K6PsIHd4KkPX5bwxvrO7lfK3UCkPyC9z5JqJ56SVXhXTms1zWmgXChEKEQoRChHPEdq1Du05LbSL ZwptX8eYYrIhC7iOcfvCynfSh6dWcDnHuP0lf/fc4sHpPHWqyYbdc435Js5rNpFdyek89U5y34cy oBChEKEQoRChEKEQkU4IV1ilynPdgULEZfVl2pmr5veGha4Oevdv0QwPpaMlv1uodXvUWbeA5l1x thUAuGqlLauFU2eTr9r77qA6eXvVMp7LnZWutiWctV0hCu0i3bNMIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiEinVB1AYBVE6HpWkghQiFCISKd0PeNsTV2Qb/fe+NM10LphE5jrmf4LMuCQoRC hEJEOqHqUYdJk1lQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiLhc +7G9UlwWFCIUIk6FUlUb3E1+od3Z7tVLvlaRv8t2oxChEKEQoRChEKEQoRChEKEQoRChEKEQoRCR TuiyLmwNM2ZM0rVQOqEfXZZh0ipdCylEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQo RChEKEQoRChEKEQoRChEKEQoRNwutdgRx0/XQgoRrv0gFCIUIhQiFCIUIhQiFCIUItIJVRfuf+d9 uBT92tvcQq3L5FsZ6rLta/Jnt04pAy3kNj2frOiuUjpbaOYI95ldtqq7SuloodkTEii0snVKaWyh FdM1zzqpV3dXKQ0t5L5Bn+zorlIqW2jlZOip0K7WKaWihVZPFec/qXd2VynQQkaDyofQ7u4q5aaF ttf0zNA6pVy0kPUY3/hfKXm6q5STFtodVUzXZf9K2d8q76RrIYUIhQiFCIUIhQiFCIWIqgDe1Svu jPeoS6Ga9+zjdyLFQuaHIgcJ1bMfr9fr+38zpaomrD4lrsQipG4nG+jc2B5zXcHlZEPtt//8vdFu y9tCWVCIUIhQiFCIUIhQiMgr1PteE50ClreFSmlvpRkxEhy5ng0GZ45kv14nn9LzzaNGICEBvMjh 0GWXHQdZOdFwKzT7wFfkvuwzoBChEKEQoRChEKEQoRDxbKHjdXbmErFfr7A7xmLv5O6yDKv1fg2l j1HG5/9vETrYKZX7HMqAQoRChEKEQoRChEKEQoRChEKEQoRCRDqh6vpDFgDIgkKEQoRChEKEQoRC hEKEQsRQBl4p8a+2t0I7svDCalhFBf9OW+jsw2vWyX59fcWvFq6ROf5tS8Jb60FD88t6FmtvL1Q7 m3RCf297jP9WkkAGhoRmbOvTLTRrj6EuoZmraJqFap91vXQt+ZolU8rgSb01vX3VRllVQqmqL684 b965FVotU0rjS/626su7ZEqpPKlXvifd7oG3g+Gh9BW9rfq33odm8Pde8qNRiFCIUIhQiFCIUIhQ iFCISCf0nBKadyJnP586x/j19bUtgFcVLztYUUazuxDJVeWU0ajicNLk0knP7Vus7MrcfOdXC+2W Snen/lsBvC1FtWoPvDU89cm2aNAVPc++y886KzvWIvLJ1pN6Rkno4S5LFcA7iKzA/Pfu1NFcvjGm 2Edxt0wpHRHF2dxWrKwl8onfFQRu+XkrTRUrV5TRPH39eL1elwsnZ3PZZT1lNCMeI7cvaKsqnVYL zTzwFfkfHbtRiFCIUIhQiFCIUIhQiFCIqH6FfWfmStB0LRSyJj+SZ7fQ1pHrJ6umZp7ZZasyFkrp mB/atiZ/F01zjNuSBM7YPvuRYp76YEdXHeQ/qXe2TinZl1pkSDT5FtrdVQfpTuqv1+v1mtFVpuLM 4l8pfc2bKjV5JgoRChHphLpmP0rZnLy9EoUIhQiFCIUIhQiFCIUIhYh0QtX1GGuxMNtsqkYdTgtn Iv889e76MU1ppStIdw5VTzasKrSFQnddGF3ouJSE+WXdC7xnnfwYDbpaaz8jt+yX0OdB6NxYclKP HiQ0m7yHlBl4kShEmIFHhKe3jxKeEhg6Lmt9HMzo2q41aFdP94ibZFNK4B1Tg8Ct2XSRj4+qDLw0 5X5mHviK/I+O3ShEKEQoRChEKEQoRChEKEQ0rUG7GvpEbKT2fQwqqtUyJJq+b9D26jrv3I1MqZTm CNUj1+2pOO9sHZelC+Dt5ja0sD3zJQPDd+pSNsTLKB4WeQMd3j7183enFNU6Y0sAr1bm+LflBSJr nlePCE9tLxCZLkweiUJEbqFVN787wtZ+vLO1YmU0w0u+lpTQvDvQ7AhRczrX7K3lb0to7gjiVe+1 kGYN2syDn5H7Tp0BhQiFCIUIhQiFCIUIhQiFiO9X2OjxleV+ZvHdZSOjisjuntJCW7MWUm8XNj0q vYNuoVQ1rGZGHp/fZbPjskMtNGOKpkkodW1hS0btoivRZGux49UoRDRHg6xPvRuFCIUIhYju3dtn ka6FFCIUIhQiFCIUIhQiFCIUItIJVa1Bm71U8J1LodoJzujibKdd1jPbOq0wW+2S0qvN1KcvPb06 AK2J7QUrxbUyPdGESBXrmMGzhLYnCWTYrqc78XZpDaurA94xPQi8q4ZVU/J2xO8S1Q9XyiCPkvp1 DrVcNTNO7KHU5KlR6d4mj864CrnKInnWs2wHzxFqHXVE8S0UdRJPXYNG3356Cc2r7PCrIc8MnlNC c4dMKTcDxZqB4JYMPAN4uwU+UYhQiFCIUIhQiFCIUIhQiOjeyGjWq213AO/959MnPVvHZVMnPe+6 aPmkZ+sk5vRJz9YPTznpGc3wpOeyWdhdKEQ8R2j7Vk+7QgmfDM/CTl1q0VKjc1aXDi9oiua0dN2u APCpUO2BZlXwrtpZaSXPuTHu4m+VSJhBaM2GCMJKJJQSc1XermOcUe65Wajn4KlqNkxfnPt+gNXB u1OhFQe942/dh2agEKEQoRChEKEQoRChEKEQoRChEKEQkU7ox8jVLedOUIj4cQ5lCFGlayGFCIUI hQiFCIUIhYh0Qr7CEgoRvsISChEKEQoRChEKEQoRChEKEQoRChEKEQoRzn4QChHOfhAKEQoRChEK EQoRChG+MRIKEQoRw5VRonlOC+3iVGjncMhxGaEQoRChEKEQoRChEKEQoRChEKEQ8feEplYbbOG9 9GGkVFW1wU+RT7aUjLorBrm0hehgaTaYXVbDapfIwb8MEu+kq/J1KpRmwupgVkH1Gv5HB51RjPaO rt25Zrba5W6lpewRu3100AFndOdtC50JXDF9P9erg54deHuByE+xre9D7yw/qXegEKEQoRChEKEQ oRChEKEQoRChEKEQoRChEKEQkU7odsV5D27TMxuXnhIKEc8Q+rwf0X9HgjvetuKNcTbeGAmFCIUI hQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWI3EIr0yWu+NVCq/M4Prnssl1ieA6tFvshlCEl 5zKvo+bgM2b+MdFktVhY5kspMWJNQj/+8EJuW7zsKi1n9MTvznyZ1UIhqcmRVAmtvNJuhXZk4DVn As8SOWhaP7QiJlt1DpmavFvinerXj1XkfsnPgEKEQoRChEKEQoRChEKEQoRCRHNRrSU1rGpEzn4+ vRBJ61TLjKmZb6G7LrqaLZshdXkO3VXRmTlp9b+zA9C58fnzSMGcl32GMf1Buhb6G0IzN6t5fgvN njhvEppdYLSUxiKjs2VKqRRaJVNKZRB4lUwpHSf17Lv6rVDKuP07K555z78xziZd8CVdCylENAWB vewzkE7I+xChEKEQoRChEKEQoRChEKEQMVQn/+vrq7xer9A5pOYF3r1TNLWHqW6h0bmi4+9JbGj5 cs32GWf/dpuu0Zq10H1uVH5O05TeyLCoNsZ2mxsUJdMiVVUHLXLASJ+FN8YZo9e7zUdO88t2Mjy2 770lvN/h328F0xYS9KZ/XZ5DPTe9kd876Hq41jxMa9Mx8KRu5W4ZRguH2OnaD0oNnMlQC23fN2jF PSrdK+xQBt4MprTQSNdOERppvaG4fc3vtspVC82eRD99uN4x45LvfmMsZV2Y4Vvo/YAj70G1ZX+v zrPqFho5eMvnN71+nL0uXHXv+7+3bHcYfh86DlDT7ae51p8j197XkNqlqSFj+zNqr7rhG+OsDRtr 6VrQNJNToZ1LUauGQStrf9x2WcQy5fBx2d1NbsYq9KZs8hXl6ZsfHbUyvRfG9BtjK39nGDQLhQiF CIWIdEJNd+oV6xqHWmhqwlsWtk42nDHcQtGiz+yylauGQ1poa47i1kSTUtanKIed1FHd9qzMl9ah TkQrPec+tCNjoZSgEOc7o932jC7b1V2lBLVQZLeFFYiMIt1ilGknde8Xq5rSmy3xzu3qmMen4kRc bZd1P3ZNnj/jTj3CaLedFiLZSbrgS3d96ln8/ZN6FIUIhQiFCIUIhQiFCIUIhYimvRauSFeYLXLB U2iXRYgN5QbdrXPt7cbhNIptleLuiNyuJ+wcimqpdPchhYhpAbwtl/0MhtPbzxi54oa2eooUOUj3 LEuXPRVWVOts4W5PF059dIQm3vaQ7qQuJWjiPBMKEX9faPSpH/7oGGXoaX8QGd4Kfdp/0nOjDGmh T6a9D62SeOeHUIZY3t+/D42iEKEQoRChEKEQoRChEKEQMVyx8kh/j3r9bS4QeUeEVPMugXfU1u1s FmoprdJTt/OO28ooVxKnHxRUIiisQOSUeFmGNbFNZTaI0AXeWUi34jx8Omb0i+TtsiwoRChEKESk Ewq/U4cFX2akGfeQrsuGkrfp94dfYR8RWqhppciFlacDxdplOC3DpSEhOtgd017QehZNTh1Kfx5k Rvd0Cc046B3PujHuQCFCIUIhQiFCIUIhQiFCIWI4Ay/61XZ49mNkb44znrX0tGdDo9H4a3cLHQPJ yGS3IaF3HpOBtz1elu4qi8C8DkIhQiFCIUIhQiHib6dzRZDuJX9avn0pkxbFrZQp5a/n24/KlJLw JX94bD91suERYfLVKEQoRChEKEQoRChEKEQoRKQTCimheUaqwmxbwlN3pKjyFUW6k1ohQiFCIUIh wik9It3EuQ9XQiFCIUIhQiEindC0EpoOpe8IG0obwDtBIUIhQiFCIUIhQiFCIUIhIp2QATwi96jj E+cYi0KMQoRChEKEATzCAB6R7qRWiFCIUIhQiFCIUIgwgEcoRChEKEQoRChEKEQoRChEpBMa3gOv lMVl6Wv3WjiYNunZu6HD6Dyje+AReJX9qT3wwkto7tge41vILecuSPfoUIhIJ9R1Us/cdLarhWbe ErqEZm4l1tVlPYW0a0l3UitEfAu5B94Ft0I7WumH0CNCCy3DoSlFRq9a6TjY50EP4ahRR/geeCMy pdw8Omq2mosUOagal9EGfcfPIi6Kyy7bxbNujDtQiFCIUIhQiFCIUIhQiFCIuM3AG3m77f2sdC2k EKEQoRChEKEQkU5oWlGtXtK1UDqhaRl427dPjUIhQiFCIUIhQiFCIcIAHqEQoRChEKEQoRChEKEQ oRCRTujXhNXuDJh0LaQQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRDxa/ZjdzwvXQspRChEKEQo RChEKEQoRChEpBMarhQXHfBL10IKEQoRChEKEQoRChEKEQoRChF5hd6rCe4qn/lDqJR9dTzfydtl PVVPZyzC7G6hWd1bnd7+/u2jymWi0Ov1uvzmq074X13WUxt/+vYY1D2fvxMJzn64fHm3wCcKEQoR ChEKEQoRChEKEQoR4SU0R4dIoS0UMV4LE1q2w1svvaOVEKHISYdhoVRR6Rnj/dDpmG3zQzOnY0JO 6sjxf7PQ7FzqJqEVid3VQquyzP9GCc3/1JZzt0J3W/TMkqpuoVVSTV22Qqr5HJotle4lP+yyj2ql 7haaJTXUZTOkhs+hrU/7WkZaadoL2vZix1FSoV0WIRV+Do2e5JbQJBQiFCIUIhQiFCIUIhQiFCLS CU3bA6+XdC2kEKEQoRChEKEQoRChEKEQoRChEKEQoRCRTmjacp2tCys/2bqw8oyRlv2VNLmbdCe1 QoRChEKEQoRChEKEQoRCRDqh2wBeKbGvtTWfjy0UtQq49nPSdVmV0Mr8jiUt1PKFntllpWysrhNN 6OLcnjJSLZ/XLDTKlPXU6cv99HZb7Reb1mVT1+Sv7LYpCW8jy36G8stmML1S3LYCAAdLc4N6ira1 8vz09rtvvT2/7E5ie2hha0pgutTkT1JUtZjVSunSuZ476jhja4mEGiIEzcAjFCIUIhQiFCIUIhQi FCIUItIJTcvA6/2s2xZKWXZstVS6c+i5EcU/Ey9rpUloRSs1BfBKmS/1zHhZdKjzjuee1Kta6dmh hRUn+HCsY3s9xjO212NMGVqY1XWh96Ht8bL0E+elJC0QmbIeYy/PfbgSqWqcH2zdJXAW/40Q59Ak hQE8QCFCIUIhQiFCIUIhQiFCISKdEG7jfHA3PJ6+0XWtyNnvTBt1fH19dU0ajM5+VHfZQc3M2fFv Pa11KtQSwD1+Nm1KLzL3Zzh7ajTPdfpuFD3nQMqx/QjfQpGrGkbmsPO2UBYUIhQiFCIUIvIKRcZQ lyTeriJ82WBoiHNGlKH1M09jHT2vssu3Aj8bpx3/HbnU4jYaNLv6wBnpXvJx5Pp+gOis3y6hWQe+ 4lk3xh0oRChEKEQoRChEKEQoRChEYAnNWtItrOyNr32Sbvny7aijphuuAnjbCiK9Xq/nbCffw9TV wtv3t49AIeJvC6W8U7+zvLjfO1HzjM1rPz6JnlWbsm9Qum16RhjuslIWTnq6a3JRiFGIUIhQiFCI cA88QiFCIUIhQiFCIUIhQiFCISKdkBl4hBl4XUJm4F0JmYF3Qroboxl4hEKEQoRChEKEQoQZeIQZ eMR/KwOvq8tnZOB9EnaVRb3kt3yxpoqVLWuFes+paRl4r9cr38LK9y9Q+2VC1g/dsX1P4FEUIhQi FCIUIhQiFCIUItIJmYFHTMnAGxGbkoE3wn8rA2/7uMz9OlagEDE1A+9PJLwNCd3NMW5LeIuUKWXC SZ1uIcH2p/0hEUVIC5098bc/7c/waT8DhQiFCIWI6UKhywZ7GL05ugceoRChEKEQoRChEKEQoRCh EJFOyAw84r+TgdfbUlWLc3sjiyEz+TuKsb2Dl/3QTuzOMU4gfOnp9NBCdFye+CUUGYPv4bSFrqRW iA2tyZ8xtYQTVrWtEiVXPYO2SqxrSm9mVw7PMUZXPXW5DpHu4Xq7Ss+qp2VCBt4ooRl4S1bH1LbS tNUxd0/6lgy80GHQ1UFaCF+u01vxJMUeeBEi1UIzDnrHs26MO1CIUIhQiFCIUIhQiFCIUIj4V8r8 Eerfra6zg3+l9K+9nzEKSddCChEKEQoRChEKEQoRChEKEQoRChEKEQoR6YQM4BEKEQoRChEKEQoR ChEKEQoR6YSmLM7972yPsQOFCIUIhQiFCIUIhQiFCIUIhYhnCbnlXAnOt5+yk0Bvvuoj9sDrYcoe eNPqU+/Y6NoMPOJZd+odKEQoRChEKEQoRChEKEQoRJxm4EW8qvZ+5pQWCo8o7qiqc/C/UmJHE6Gz HzPonv2I2mZnlNAWSrmx4zvD0zEZui2shVJsqHZHWC293d0W0kKRz8JToZ2tlO71Y1go+tXlUmhX t/2tLpvxptk0T72i28K6bPu+0rNaC4VWd1tIl0W+k1cJrWylv3UfKiU+IFMttKpo7d/qshmtZgCP UIhQiFCIUIhQiFCIUIhQiEgnNBzAi/7bdC00FMC72m6u92+/hTJtvp2my45GWRIEbuFSiD50+gza yvPo7sukmPR8/9tpJ/XSrZ5mVtD9uzHXUvr27Pz8m2ahlu7avjtXBH8rCHzWXXdfqKa7m4QeFZ6K oipM3sq0zJeD0USklr9f1mW1519T9lQLny0wvGzw7gN6zpHhFpp5id99oa4WmknuNWizDtJCeAYe QZ+ZbqXn8Aaz0Tzj4boThQiFCIUIhQiFCIUIhQiFiO81aFGVTUY/JzS0EPGlwsv9jBJW7mdZMZvV 9WNCyv1Edu3wHGNUV90K1R74jGWZL2fMuApD8zqmJ5qccVUmalleR2+RrV66shZaf95Cuqf9cJLA tqyFVQzfGKNP8O5o0Cy6umxmXDbs9WNJrvTdk3zWbHJTl5HE1AIANR8+47HyjBvj6LcMXYPW80q6 9OFae7Coe9MPoeg78tBynYjRw5ZX2FZaW8kAHqEQoRChEKEQoRChEKEQoRCRTug0A6+U2MhQcwDv EQUio8ZoYQUie5hej3H0AOH1GFtYVv4wZYiTmF5tkA44k/CY67QQJx346t9GCV2Tv3x+aHuyUkt2 3baY69n+QZGEvA9tL103k+EWSlUpbkbLpXunVohQiFCIUIhQiLCEJqEQoRChEKEQoRChEKEQoRCR Tug2A2+UJYVIZpNO6LvLRkcUqXbnigwiT+myJQlvV2zJ67giOt5fSnCXbV0tvC34UiMTyTODL+/M LDBaytMiisTW4Mvsrjp4xkKCd2bcje9oPoe2VorbXiLhndVddTCcXxbNlPyyEULyyyIJyy+L4ja/ bEce021+2Y5zCaNBI1IOpWcQNpSOIl0LKUQoRChEKEQoRChEpBP68ca4oooXka6F0gndvuRvHQZl QSFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiEindDtlN6OlQ7pWiid0I8uyxC7T9dCChEK EQoRChEKEaclNHc+09K10P9KmbuHSys5W6iUHO9CpTQugV9B3i4rJUe3PSeNYhe/hHbfk/K3UCkP eJalSudazaXQrm7rTgmcxXO6rJQ996RntVApm7Onapjdbc/rslKSZeCdkT7fPpLutNJZrfTcFirl AaGF5Rtd72A4vT1VqZYZNFU9PUhVkWA2ChEKEQoRChEKEZf7l72TftQxk3RC/0rZP/P6TroWUohQ iFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhIJ1Q1C7uSdC2UTuh0FnYn6VpIIUIhQiFCIUIh oroAwNbtMc7YvgT+EelcLoE/SB0mXx3T/yWUfs+XM7atON9e7Pjum2+/U5PA9CXwNQdwxfnBzpHs 1yvTOLo85Vm2E4UIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiF CIUIhQiFCIUIhQiFiHRC4dlTo8uR0rVQOiGzpwiFCIUIhQiFCIUIhYjTrIUUqTifMtvTuV6vV4ra nrnPoVL2V0CtSqNYKXWZxZl+I6NVKEQoRChEKEQoRChEKEQoRChEKEQxETWvAAAOpUlEQVQoRChE KEQoRChEKEQoRChEKEQoRChEKEQoRChEKERUbQV+FQSeEZe9FKqJRB+/Eyl22mWtYfHIMPqvFqqp enr2O19fXyEtdbo65k7m+LdZcf3bq4wOOmMFxI8uy7BqON19KJ1QdUnxVZwKpViDdrB7/5cfLdRT Wzj6C3wL7a5LfZDuKrsUcsnX/zEktKz6cs3BphfMPjtn3g/6vkZ2W9H1T4FPkRkn/g+hlgMse0Gj t0H6+Wh3WsGbUIhQiFCIUIhQiFCIUIi4HUo7ci0KMQoRChEKEVUBvFLWBfGqWuhuvB49PXMr1HKw KKmmc+iY+Zg5Z111Dl0F8aIk3sEWaj1pRwWHIoq1v9PClPvQSCuFCH220kir/c0WikQhQiHibwpF jnjx9WM1VeGpkZ+30rQG7b0rZr3S3hYi+TwotUb4CquzA9QeJOo1pOoqGwnotWIAj1CIUIhQiFCI UIhQiFCIUIhQiFCIUIhQiDADj0iXgVed+bIieFdKxTm0MnhXCqQErg7e/RJqZeqa/N1ZUwfD1Zcf EeIcQSFCISKv0Ejec+TuA8MtFL0VQu4MvNF09Yi7Nr5+tATvIjiNBvUccGq8rDUTL/IBW/W0TzHq mH3gK/LeqbOgEKEQoRChEKEQoRCRTqg6r+OOZesYd6AQoRChEKEQUT378c7MkWxXAO/9Z0tm8nvm F6OoCuAdrUBBvClCdzKf/z69ZFSGEFXeDLwMrVPKzUz+9lp66VooCwoRChHd9RhncVuPcQdhEcUo 0qUE/qpPfZXktiqAd1og8oyjfsPsd+yQAF4kGMBbPeowA49QiFCIUIhQiFCIUIhQiFCIUIhQiFCI UIhIl4E3VLFyxrTM8N5T0WmB1atjtq04b1l6M6PAdmgGXgShGXihiSYZWqeUhDP56fbAS/foSCc0 nMUZTboWyis04ybXQ94WykJIBt6yGufHwa72AD77/1HCMvBKmVhCs2f11JJX2JraDMsiijMPekfu yz4DChEKEQoRChEKEQoR6YTSTQs/ZzpmRU38M5qSJle8ylZnvqx6r666ynzJz4RCxL9S2nct2ZrO tZp0Qv9K4Zkz70OZUIhQiFCIUIhQiFCIUIhQiEgndDr7sTMpL10LKUQoRChEKEQoRChEKEQoRChE KEQoRChEdJXQLOU+gjSl2HFL9t30Bd47Vpof/Oqymi6a1TqnQncin/+2fA88YkZdz+ESmtE8p0Ck 2VP/h0KEQsRzhLZn4GUpqWcJTSJdCc1f70NnUrMl3hkqobn0fYgOtm358urbwXPu1LsIvzGOdnH+ geLZwc6+9az70lBexztTNwfdye1CgpUpybdCsw96R7ouU4hQiEgn9OOyz1ClKV0LKUQoRChEKEQ0 Jd6uyH8dfsmPrlhZVaGphqhhUdMMGu2BFyHVPfsxK4gXfpWNCg4H8JZGFHegEKEQoRChEKEQoRCh EJFOyD3wCIUIhQiFCIUIhQiFCIUIA3iEQsSvhZW7SddCChEKEd6pCYUIhQiFCIUIhQiFCIUIhQiF CIWIdEJONhAKEQoRChEKEQoRChEKEadr8t2m5w2FCMvSEwoRChHeqQmFCIUIhQiFCIUIhQiFCIUI hQiFCIUIhYj8QrvL0/8QWlE9h/i3u0U+Ga6MEk26Sc9/GVYzvJP/st+NQoRChHkdhEKEQoRChEJE UwnNT2YMCkJbKOJR0y00a7TSJTRz/BbSZZFvBc1CsweWTUIrhtpDXTbjBa5aaNXb5O2NccdERFeX zXzXDrsPRVG9X8fWvadq2P7oWLUzTlMLrRg4Dj/LtpeDnt11f+M+dMaSGud3zOq65z7taxltJUto EgoRChEKEQoRChEKEQoRBvAIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWIdEKW0CQUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCKallq05gZdrYu9+5uqFvr6+rr88Kuf3S3SvftZeCpO7d98fX2d tlRTGsXxv1qRnr/BLM6zDzv+7fMD3//78++u/uaTKZVRWv7uUzB8CTzJ0M/T3YcUIhQiFCIUIhQi FCIUItIJmYFHKEQoRChEKEQoRChEKEQoRChEKEQoRChETA3gDQtdUROMW1YgsiUgF8Gt0FkXtgbk WukK4L3/+/ayY8So4HBEMVUJzRkoRChEKEQoRChEKEQoRKQTMoBHKEQoRChEKEQoRChEKEQoRChE KEQoRChEDMXLZgx6hxLeooN3l0KtEZ1IseptC1dt+/Rr9qO1aHZ0ke0fV1nEN/+7Abws28pftlDL N69ZcDAstAuFCIWIvEIjl27k4yNvC51R00pTV8dEPJdGPwPfh85evpa+D/UecOoatLtlXTNlLoXe D0RLvqLfhwzgEQoRChEKEQoRChEKEQoRChEKEQoRChEKEZcZeLUzaltygygDL3J65nJ+qCeIty2A dwjMkDIDj8gbwItke7zsquRqD3+zhSJRiFCICBGKfHxMaaF096ER0kUUqwN4pdQF8aa/D71DrRHx 5O+Ol82QQaGag7VGH4nud+pZPOuy34FChEKEQoSbgxIKEQoRChEKEQoRChEKEemEmmY/3rmLDo28 6HXHy2Zk310KjSQIjPJLqKeLpgqRyOe/Tw3g7Vz6fjAcwIsm3X3oMiVw16AxbwtlQSFCIeJSaFdm 8GVK4C6e02Wl1L2kLU8JPDvoDJGDX+9Dr9ereVvmSC4z8GqIjpVdCtUcbNZV2f0KO4tnXfY7UIhQ iFCIaFqMcsWy5O0dKEQoRChEKEQoRChEKESkE6reA2/VxPpwBl40KLR6rnF4CXw0VS/5K2dAsMtS TccYwCsKMQoRChEKEQoRChEKEemETDQhFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiwjLwokiXgXfa ZTsz8H4JnR3gWMp81RrTyo5dyZzJzZLqjpdtjUqvZGhh5YxWSheV7srrmEn3zkqzTurbfYNqWyZS rnojoxVl65qEfvzRxAdu131o5t266ll2xdT70PvlvXOj0L+VozhDGh8dZ9l3VzIR5xTuCVzLtIqV PVl1SypW1tRkWL7z9qyD3pHujVEhQiFCIUIhQiFCIUIhQiFCIeJ24nz7lN47u6Se0WU7UYj4V0p9 bOxg5mg2XQulE/pXCpfHTJXwthqFCIUIhQiFCIUIhQiFiOqaDSkrVq4Qe06XXUUWZ7/OGsAjFCIU IhQiFCIUIhQiFCIUIhQiFCIUIhQiqkto3hEZPUrXQgoRChEKEQoRChEKEQoRuYV6drWdXgCghRmh quoiEncV4SM5TXg74wjezV591RRR7P29FpoDeGc/25K8vYrc96EMKEQoRChEKEQoRChEKEQoRChE KEQoRKQTOs3AaxnMRk8+/O/sQ1LWsNpF6AxaaGG2LN0W1mXTaljVMqsFh6eFownpsu2bpaeYFl4F ttCqSpUHzV22JfNlZ7dVJyudsXwm/5MV96XnPu1TbFL8mP1cLSLxTvr8su0ZeCsk3nneObQahQiF CIUIhQiFCIUIhQiFCIUIhQiFiHRC3QG81r+p3XDktIVWTN1dfYHTiCKxdCa/lyVbzs3irkcuI4qR tLTeZQtdfcj7vy/fcq6VKZthtRK9pc9tiPOTnhZo/ZvbFloh8El3l/WkUdT8XnesYxZdMdfac63n SwzHXKNZttSi9jyrirmubKVpsY7eLxH66Ji6sWPkg7Pls5paaEVUKPwFLWSV3kya39fNwAMUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCIu98DrCeLV/t0dl/Gy1o36ImS+hSI+bEk6V01EKJqmWMcVU7On aAZ2Sw2rK7YlmtTOU29NxUmRaLKDrswXE012kvtO3XLQJZnAd6yaX69aP3TIrAjs/RJqPcjyEpqf rTK7634I1X7bmV2XN0ex9eE5q5X+F/lhEZ9jAI9QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIjIWUKT DrKSrgy8gyVTeiNMXQK/i8uYa/p5amJ7Tc9Z3AaBa2Md20toziS/0KPC5CuoCpOvpKqFrlL80mcC R7AknauF7rRSVzaUYk3PUsrTuqyUzUHgMx6bmhzFs9JKU1WBT7+TwKqb5Heh2rsW+U8Xqr0t5bvj WfYtlGWBQ7ouU4hQiFCIUIhQiFCIUIhIJ1T1Tl3L344GZaH7nXrWFF9XC6UqMjore/Ng+Bz6b6YE njG7qw66u2zrxPmqWfxSnjbpueq8eec5k56p5hh3dNVBVZdtnWNceYmf0ZXwNpPL/LJSNk96ntHT YukrVraSTsh5akIhQiFCIUIhQiFCIUIhomsGbeZgoGqT4kNkBSi0emhU3UIHW2c/doxin3OV7Rrj P6eFdqEQoRChEPEMoe1ppcTKyawfrx8ZpoUvawsfbJk431Eq84rbOmg7uvBXHbTdM/qYo7iaqpTA 1Du8zUYhQiFCIUIhYmhB0wyem5q8iqZM4BSL4s6kti+sTJmB93q9LgtnbxE6SLUGbQUKEQoRChEK EemEbmfQHlOIZCYKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRP+YYdy9mKiVhCylE KEQoRChEfC/OzbCWupSTuh+7xXKuyX9faHKQorpOBqmcV9k7u1spfwvtRiFCIUIh4plC2zNf0u/O Vcq6l7fmFedbly/vyMxrKpFA/x7BZRGJXZl4TQu8V1A16ki5BH4VChEKEQoRChG/hFJOWL2ztZRv Bn7NMb6zrZTv7ioE7+Qcdbxn1u2OKn630G6Rg9xXWQYUIhQiFCIUIhQiFCIUIhQiFCIUIhQimmId pcwfUJ4K3U1aHT+rEXv/nNov0j2DNmumDWucv3+zT4m71uoV/lGxsnbCis6vkYmvripfLfHY1ovg dg3aHbOutl9FRrs+JHBKsLlw/xmpdiuNRiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCISKd0P8DU3MdyMKZsxcAAAAASUVORK5CYII= "
+ preserveAspectRatio="none"
+ height="1244.6"
+ width="9.5249996"
+ style="display:none" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#fd0000;fill-opacity:0.6350711;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
+ x="-2.5308407e-06"
+ y="-873.23492"
+ id="text4630"><tspan
+ sodipodi:role="line"
+ x="-2.5308407e-06"
+ y="-863.87115"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.58194447px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#fd0000;fill-opacity:0.6350711;stroke:none;stroke-width:0.26458332;stroke-opacity:1"
+ id="tspan4634" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.26181126px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.20578496"
+ x="-3.5527137e-15"
+ y="-272.16272"
+ id="text4642"
+ inkscape:export-xdpi="91.400002"
+ inkscape:export-ydpi="91.400002"><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-263.08344"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.3770504px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4614" /><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-250.12434"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4658"> ̀</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-237.16527"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4553"> ́</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-224.20619"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4555"> ̂</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-211.24712"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4557"> ̃</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-198.28804"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4559"> ̈</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-185.32896"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4561"> ̊</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-172.36989"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4609"> ̧</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-159.41081"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan8898">ı</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-146.45174"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4565">ß</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-133.49266"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4742">Ø</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-120.53358"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4750">ø</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-107.5745"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4626">Æ</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-94.615425"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4788">æ</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-81.656349"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4792">Ð</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-68.697273"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4796">ð</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-55.738197"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4798">Þ</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-42.779121"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4637">þ</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-29.820045"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4767">«</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-16.86097"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4771">»</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="-3.9018936"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4643">¡</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="9.0571823"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4720">¿</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="22.016258"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4775">¢</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="34.975334"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4724">£</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="47.934425"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4726">¤</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="60.893501"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan4654">¥</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="73.852577"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan881">¹</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="86.811653"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan864">²</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="99.770729"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan862">³</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="112.7298"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan866">º</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="125.68888"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan869">ª</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="138.64796"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan871">©</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="151.60704"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan873">®</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="164.56612"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan875">±</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="177.52519"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan877">×</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="190.48427"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan879">÷</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="203.44334"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan886">¼</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="216.40242"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan888">½</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="229.3615"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan890">¾</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="242.32057"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan882">µ</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="255.27965"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan892">¶</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="268.23871"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan896">¦</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="281.19778"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan898">§</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="294.15686"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan900">¬</tspan><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="306.98413"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan868" /><tspan
+ sodipodi:role="line"
+ x="-3.5527137e-15"
+ y="319.8114"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496"
+ id="tspan860" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="0"
+ y="-1286.5312"
+ id="text5550"><tspan
+ sodipodi:role="line"
+ id="tspan5548"
+ x="0"
+ y="-1277.1675"
+ style="stroke-width:0.26458332" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="0"
+ y="-1286.5312"
+ id="text8872"><tspan
+ sodipodi:role="line"
+ id="tspan8870"
+ x="0"
+ y="-1277.1675"
+ style="stroke-width:0.26458332" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="0"
+ y="-1269.8625"
+ id="text8876"><tspan
+ sodipodi:role="line"
+ id="tspan8874"
+ x="0"
+ y="-1260.4988"
+ style="stroke-width:0.26458332" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="0"
+ y="196.98749"
+ id="text4641"><tspan
+ sodipodi:role="line"
+ id="tspan4639"
+ x="0"
+ y="206.35126"
+ style="stroke-width:0.26458332" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="0"
+ y="230.325"
+ id="text4649"><tspan
+ sodipodi:role="line"
+ id="tspan4647"
+ x="0"
+ y="239.68877"
+ style="stroke-width:0.26458332" /></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+ x="0"
+ y="10.456248"
+ id="text4532"><tspan
+ sodipodi:role="line"
+ id="tspan4530"
+ x="0"
+ y="19.820017"
+ style="stroke-width:0.26458332" /></text>
+ </g>
+</svg>
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp
new file mode 100644
index 0000000..0e251f7
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp
@@ -0,0 +1,46 @@
+/*******************
+ * font_size_t.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if BOTH(FTDI_EXTENDED, TOUCH_UI_USE_UTF8)
+
+namespace FTDI {
+ // Returns the height of a standard FTDI romfont
+ uint8_t font_size_t::get_romfont_height(uint8_t font) {
+ static const uint8_t tbl[] PROGMEM = {
+ 8, 8, 16, 16, 13, 17, 20, 22, 29, 38, 16, 20, 25, 28, 36, 49, 63, 83, 108
+ };
+ return pgm_read_byte(&tbl[font - 16]);
+ }
+
+ // Sets the scaling coefficient to match a romfont size
+ font_size_t font_size_t::from_romfont(uint8_t font) {
+ return font_size_t(uint32_t(std_height) * 256 / get_romfont_height(font));
+ }
+
+ // Returns the height of the font
+ uint8_t font_size_t::get_height() const {
+ return scale(std_height);
+ }
+}
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h
new file mode 100644
index 0000000..a2cb8b2
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h
@@ -0,0 +1,55 @@
+/*****************
+ * font_size_t.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+class CommandProcessor;
+
+namespace FTDI {
+
+ /* The unicode rendering of different font sizes happens by scaling a
+ * large-sized font bitmap using the FTDI bitmap transformation matrix.
+ * This keeps us from having to have load bitmaps for all font sizes.
+ *
+ * The font_size_t class helps manage this scaling factor.
+ */
+ class font_size_t {
+ private:
+ // Standard height for font bitmaps
+ static constexpr uint8_t std_height = 49;
+
+ // 8.8 fixed point scaling coefficient
+ uint16_t coefficient;
+
+ font_size_t(uint16_t v) : coefficient(v) {}
+ public:
+ font_size_t() : coefficient(256) {}
+
+ static uint8_t get_romfont_height(uint8_t font);
+
+ static font_size_t from_romfont(uint8_t size);
+
+ template<typename T> T scale(T val) const {return (int32_t(val) * 256 / coefficient);}
+
+ uint8_t get_height() const;
+ uint16_t get_coefficient() const {return coefficient;}
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp
new file mode 100644
index 0000000..d12bf97
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp
@@ -0,0 +1,107 @@
+/*************************
+ * standard_char_set.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if BOTH(FTDI_EXTENDED, TOUCH_UI_USE_UTF8)
+
+ constexpr static uint8_t std_font = 31;
+
+ /* Lookup table of the char widths for standard ROMFONT 31 */
+
+ uint8_t FTDI::StandardCharSet::std_char_width(char c) {
+ static const uint8_t tbl[] PROGMEM = {
+ 10, 11, 15, 26, 25, 31, 26, 10, 15, 14, 18, 24, 9, 18, 11, 17, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 10, 10, 21, 23, 22, 20, 37, 27, 27, 26,
+ 28, 23, 22, 28, 29, 12, 23, 26, 22, 35, 29, 28, 26, 29, 27, 26, 26, 28,
+ 27, 36, 27, 26, 25, 12, 18, 12, 18, 21, 13, 23, 24, 22, 24, 22, 15, 24,
+ 24, 10, 11, 22, 10, 36, 24, 24, 24, 24, 15, 22, 14, 24, 21, 32, 21, 21,
+ 22, 15, 10, 15, 29, 10
+ };
+ return pgm_read_byte(&tbl[c - ' ']);
+ }
+
+ /**
+ * Load bitmap data into RAMG. This function is called once at the start
+ * of the program.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ */
+
+ uint32_t FTDI::StandardCharSet::load_data(uint32_t addr) {
+ return addr;
+ }
+
+ /**
+ * Populates the bitmap handles for the custom into the display list.
+ * This function is called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::StandardCharSet::load_bitmaps(CommandProcessor& cmd) {
+ CLCD::FontMetrics std_fm(std_font);
+ set_font_bitmap(cmd, std_fm, std_font);
+ }
+
+ /**
+ * Renders a character at location x and y. The x position is incremented
+ * by the width of the character.
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the character. On output,
+ * incremented to the location of the next character.
+ *
+ * fs - A scaling object used to scale the font. The display will
+ * already be configured to scale bitmaps, but positions
+ * must be scaled using fs.scale()
+ *
+ * c - The unicode code point to draw. If the renderer does not
+ * support the character, it should draw nothing.
+ */
+
+ bool FTDI::StandardCharSet::render_glyph(CommandProcessor* cmd, int &x, int &y, font_size_t fs, utf8_char_t c) {
+ uint8_t which = (c >= ' ' && c < 128) ? c : '?';
+ uint8_t width = std_char_width(which);
+
+ if (c == '\t') {
+ // Special handling for the tab character
+ which = ' ';
+ width = std_char_width(' ');
+ }
+
+ // Draw the character
+ if (cmd) ext_vertex2ii(*cmd, x, y, std_font, which);
+
+ // Increment X to the next character position
+ x += fs.scale(width);
+ return true;
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h
new file mode 100644
index 0000000..48794d4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h
@@ -0,0 +1,30 @@
+/***********************
+ * standard_char_set.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+namespace FTDI {
+ class StandardCharSet {
+ public:
+ static uint8_t std_char_width(char);
+ static uint32_t load_data(uint32_t addr);
+ static void load_bitmaps(CommandProcessor&);
+ static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp
new file mode 100644
index 0000000..39b8759
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp
@@ -0,0 +1,238 @@
+/***************
+ * unicode.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if BOTH(FTDI_EXTENDED, TOUCH_UI_USE_UTF8)
+
+ using namespace FTDI;
+
+ /**
+ * Return true if a string has UTF8 characters
+ *
+ * Parameters:
+ *
+ * c - Pointer to a string.
+ *
+ * Returns: True if the strings has UTF8 characters
+ */
+
+ bool FTDI::has_utf8_chars(const char *str) {
+ for (;;) {
+ const char c = *str++;
+ if (!c) break;
+ if ((c & 0xC0) == 0x80) return true;
+ }
+ return false;
+ }
+
+ bool FTDI::has_utf8_chars(progmem_str _str) {
+ const char *str = (const char *) _str;
+ for (;;) {
+ const char c = pgm_read_byte(str++);
+ if (!c) break;
+ if ((c & 0xC0) == 0x80) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return a character in a UTF8 string and increment the
+ * pointer to the next character
+ *
+ * Parameters:
+ *
+ * c - Pointer to a UTF8 encoded string.
+ *
+ * Returns: The packed bytes of a UTF8 encoding of a single
+ * character (this is not the unicode codepoint)
+ */
+
+ utf8_char_t FTDI::get_utf8_char_and_inc(const char *&c) {
+ utf8_char_t val = *(uint8_t*)c++;
+ while ((*c & 0xC0) == 0x80)
+ val = (val << 8) | *(uint8_t*)c++;
+ return val;
+ }
+
+ utf8_char_t FTDI::get_utf8_char_and_inc(char *&c) {
+ utf8_char_t val = *(uint8_t*)c++;
+ while ((*c & 0xC0) == 0x80)
+ val = (val << 8) | *(uint8_t*)c++;
+ return val;
+ }
+
+ /**
+ * Helper function to draw and/or measure a UTF8 string
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the string.
+ *
+ * str - The UTF8 string to draw or measure.
+ *
+ * fs - A scaling object used to specify the font size.
+ */
+
+ static uint16_t render_utf8_text(CommandProcessor* cmd, int x, int y, const char *str, font_size_t fs) {
+ const int start_x = x;
+ while (*str) {
+ const utf8_char_t c = get_utf8_char_and_inc(str);
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ CyrillicCharSet::render_glyph(cmd, x, y, fs, c) ||
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ WesternCharSet::render_glyph(cmd, x, y, fs, c) ||
+ #endif
+ StandardCharSet::render_glyph(cmd, x, y, fs, c);
+ }
+ return x - start_x;
+ }
+
+ /**
+ * Load the font bitmap data into RAMG. Called once at program start.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ */
+
+ void FTDI::load_utf8_data(uint32_t addr) {
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ addr = CyrillicCharSet::load_data(addr);
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ addr = WesternCharSet::load_data(addr);
+ #endif
+ addr = StandardCharSet::load_data(addr);
+ }
+
+ /**
+ * Populate the bitmap handles for the custom fonts into the display list.
+ * Called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::load_utf8_bitmaps(CommandProcessor &cmd) {
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ CyrillicCharSet::load_bitmaps(cmd);
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ WesternCharSet::load_bitmaps(cmd);
+ #endif
+ StandardCharSet::load_bitmaps(cmd);
+ }
+
+ /**
+ * Measure a UTF8 text character
+ *
+ * Parameters:
+ *
+ * c - The unicode code point to measure.
+ *
+ * fs - A scaling object used to specify the font size.
+ *
+ * Returns: A width in pixels
+ */
+
+ uint16_t FTDI::get_utf8_char_width(utf8_char_t c, font_size_t fs) {
+ int x = 0, y = 0;
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ CyrillicCharSet::render_glyph(nullptr, x, y, fs, c) ||
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ WesternCharSet::render_glyph(nullptr, x, y, fs, c) ||
+ #endif
+ StandardCharSet::render_glyph(nullptr, x, y, fs, c);
+ return x;
+ }
+
+ /**
+ * Measure a UTF8 text string
+ *
+ * Parameters:
+ *
+ * str - The UTF8 string to measure.
+ *
+ * fs - A scaling object used to specify the font size.
+ *
+ * Returns: A width in pixels
+ */
+
+ uint16_t FTDI::get_utf8_text_width(const char *str, font_size_t fs) {
+ return render_utf8_text(nullptr, 0, 0, str, fs);
+ }
+
+ uint16_t FTDI::get_utf8_text_width(progmem_str pstr, font_size_t fs) {
+ char str[strlen_P((const char*)pstr) + 1];
+ strcpy_P(str, (const char*)pstr);
+ return get_utf8_text_width(str, fs);
+ }
+
+ /**
+ * Draw a UTF8 text string
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ *
+ * x, y - The location at which to draw the string.
+ *
+ * str - The UTF8 string to draw.
+ *
+ * fs - A scaling object used to specify the font size.
+ *
+ * options - Text alignment options (i.e. OPT_CENTERX, OPT_CENTERY, OPT_CENTER or OPT_RIGHTX)
+ *
+ */
+
+ void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, const char *str, font_size_t fs, uint16_t options) {
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(BITMAP_TRANSFORM_A(fs.get_coefficient()));
+ cmd.cmd(BITMAP_TRANSFORM_E(fs.get_coefficient()));
+ cmd.cmd(BEGIN(BITMAPS));
+
+ // Apply alignment options
+ if (options & OPT_CENTERX)
+ x -= get_utf8_text_width(str, fs) / 2;
+ else if (options & OPT_RIGHTX)
+ x -= get_utf8_text_width(str, fs);
+ if (options & OPT_CENTERY)
+ y -= fs.get_height()/2;
+
+ // Render the text
+ render_utf8_text(&cmd, x, y, str, fs);
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+
+ void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, progmem_str pstr, font_size_t fs, uint16_t options) {
+ char str[strlen_P((const char*)pstr) + 1];
+ strcpy_P(str, (const char*)pstr);
+ draw_utf8_text(cmd, x, y, (const char*) str, fs, options);
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h
new file mode 100644
index 0000000..5bb87d9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h
@@ -0,0 +1,112 @@
+/*************
+ * unicode.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+class CommandProcessor;
+
+namespace FTDI {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ typedef uint16_t utf8_char_t;
+
+ /**
+ * Converts a 32-bit codepoint into UTF-8. This compile-time function
+ * will be useful until the u8'a' character literal becomes more common.
+ */
+ constexpr uint32_t utf8(const uint32_t c) {
+ return (c < 0x7F ) ? c :
+ (c < 0x7FF) ? (0x0000C080 | ((c & 0b011111000000) << 2) | (c & 0b111111)) :
+ (c < 0xFFFF) ? (0x00E08080 | ((c & 0b001111000000000000) << 4) | ((c & 0b111111000000) << 2) | (c & 0b111111)) :
+ (0xF0808080 | ((c & 0b000111000000000000000000) << 6) | ((c & 0b111111000000000000) << 4) | ((c & 0b111111000000) << 2) | (c & 0b111111));
+ }
+
+ /* Returns true if the string has UTF8 string characters */
+
+ bool has_utf8_chars(progmem_str str);
+ bool has_utf8_chars(const char *str);
+
+ /* Returns the next character in a UTF8 string and increments the
+ * pointer to the next character */
+
+ utf8_char_t get_utf8_char_and_inc(const char *&c);
+ utf8_char_t get_utf8_char_and_inc(char *&c);
+
+ /* Returns the next character in a UTF8 string, without incrementing */
+
+ inline utf8_char_t get_utf8_char(const char *c) {return get_utf8_char_and_inc(c);}
+
+ void load_utf8_data(uint32_t addr);
+ #else
+ typedef char utf8_char_t;
+
+ inline utf8_char_t get_utf8_char_and_inc(const char *&c) {return *c++;}
+ inline utf8_char_t get_utf8_char(const char *c) {return *c;}
+
+ inline void load_utf8_data(uint32_t) {}
+ #endif
+
+ void load_utf8_bitmaps(CommandProcessor& cmd);
+
+ uint16_t get_utf8_char_width(utf8_char_t, font_size_t);
+ uint16_t get_utf8_text_width(progmem_str, font_size_t);
+ uint16_t get_utf8_text_width(const char *, font_size_t);
+
+ void draw_utf8_text(CommandProcessor&, int x, int y, progmem_str, font_size_t, uint16_t options = 0);
+ void draw_utf8_text(CommandProcessor&, int x, int y, const char *, font_size_t, uint16_t options = 0);
+
+ // Similar to CLCD::FontMetrics, but can be used with UTF8 encoded strings.
+
+ struct FontMetrics {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ font_size_t fs;
+ #else
+ CLCD::FontMetrics fm;
+ #endif
+
+ inline void load(uint8_t rom_font_size) {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ fs = font_size_t::from_romfont(rom_font_size);
+ #else
+ fm.load(rom_font_size);
+ #endif
+ }
+
+ inline uint16_t get_char_width(utf8_char_t c) const {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ return get_utf8_char_width(c, fs);
+ #else
+ return fm.char_widths[(uint8_t)c];
+ #endif
+ }
+
+ inline uint8_t get_height() const {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ return fs.get_height();
+ #else
+ return fm.height;
+ #endif
+ }
+
+ inline FontMetrics(uint8_t rom_font_size) {
+ load(rom_font_size);
+ }
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp
new file mode 100644
index 0000000..4fb2f8f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp
@@ -0,0 +1,455 @@
+/************************
+ * western_char_set.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if ALL(FTDI_EXTENDED, TOUCH_UI_USE_UTF8, TOUCH_UI_UTF8_WESTERN_CHARSET)
+
+ #include "western_char_set_bitmap_31.h"
+
+ #define NUM_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
+
+ using namespace FTDI;
+
+ constexpr static uint8_t std_font = 31;
+ constexpr static uint8_t alt_font = 1;
+
+ uint32_t FTDI::WesternCharSet::bitmap_addr;
+
+ /* Glyphs in the WesternCharSet bitmap */
+
+ enum {
+ GRAVE,
+ ACUTE,
+ CIRCUMFLEX,
+ TILDE,
+ DIAERESIS,
+ DOT_ABOVE,
+ CEDILLA,
+ NO_DOT_I,
+ #if ENABLED(TOUCH_UI_UTF8_GERMANIC)
+ SHARP_S,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ LRG_O_STROKE,
+ SML_O_STROKE,
+ LRG_AE,
+ SML_AE,
+ LRG_ETH,
+ SML_ETH,
+ LRG_THORN,
+ SML_THORN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ LEFT_DBL_QUOTE,
+ RIGHT_DBL_QUOTE,
+ INV_EXCLAMATION,
+ INV_QUESTION,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_CURRENCY)
+ CENT_SIGN,
+ POUND_SIGN,
+ CURRENCY_SIGN,
+ YEN_SIGN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ SUPERSCRIPT_1,
+ SUPERSCRIPT_2,
+ SUPERSCRIPT_3,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ MASCULINE_ORDINAL,
+ FEMININE_ORDINAL,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ COPYRIGHT_SIGN,
+ REGISTERED_SIGN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ PLUS_MINUS_SIGN,
+ MULTIPLICATION_SIGN,
+ DIVISION_SIGN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_FRACTIONS)
+ FRACTION_QUARTER,
+ FRACTION_HALF,
+ FRACTION_THREE_FOURTHS,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ MICRON_SIGN,
+ PILCROW_SIGN,
+ BROKEN_BAR,
+ SECTION_SIGN,
+ NOT_SIGN
+ #endif
+ };
+
+ /* Centerline of characters that can take accents */
+
+ constexpr int8_t mid_a = 12,
+ mid_e = 12,
+ mid_i = 5,
+ mid_o = 12,
+ mid_u = 12,
+ mid_y = 11,
+ mid_n = 12,
+ mid_c = 12,
+ mid_A = 13,
+ mid_E = 13,
+ mid_I = 6,
+ mid_O = 14,
+ mid_U = 14,
+ mid_Y = 13,
+ mid_N = 15,
+ mid_C = 13;
+
+ /* Centerline of accent glyphs */
+
+ constexpr int8_t mid_accent = 16;
+
+ /* When reusing the DOT_ABOVE accent glyph for the degree sign, we need to trim the leading space */
+ constexpr uint8_t deg_sign_leading = 9;
+
+ /* Look-up table for constructing characters (must be ordered by unicode)
+ *
+ * Characters are either complete symbols from the Western Char Set bitmap,
+ * or they are constructed using a standard letter from the romfont and
+ * drawing an accent from the Western Char Set bitmap over it.
+ */
+
+ #define UTF8(A) uint16_t(utf8(U##A))
+
+ PROGMEM constexpr struct {
+ uint16_t unicode;
+ uint8_t std_char; // Glyph from standard ROMFONT (zero if none)
+ uint8_t alt_char; // Glyph from Western Char Set bitmap
+ uint8_t alt_data; // For accented characters, the centerline; else char width
+ } char_recipe[] = {
+ {0, 0, NO_DOT_I, 10 },
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('¡'), 0 , INV_EXCLAMATION, 13 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_CURRENCY)
+ {UTF8('¢'), 0 , CENT_SIGN, 23 },
+ {UTF8('£'), 0 , POUND_SIGN, 24 },
+ {UTF8('¤'), 0 , CURRENCY_SIGN, 26 },
+ {UTF8('¥'), 0 , YEN_SIGN, 26 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ {UTF8('¦'), 0 , BROKEN_BAR, 11 },
+ {UTF8('§'), 0 , SECTION_SIGN, 21 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ {UTF8('©'), 0 , COPYRIGHT_SIGN, 38 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ {UTF8('ª'), 0 , FEMININE_ORDINAL, 19 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('«'), 0 , LEFT_DBL_QUOTE, 23 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ {UTF8('¬'), 0 , NOT_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ {UTF8('®'), 0 , REGISTERED_SIGN, 38 },
+ #endif
+ {UTF8('°'), 0 , DOT_ABOVE, 24 },
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ {UTF8('±'), 0 , NOT_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ {UTF8('²'), 0 , SUPERSCRIPT_2, 16 },
+ {UTF8('³'), 0 , SUPERSCRIPT_3, 16 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ {UTF8('µ'), 0 , MICRON_SIGN, 28 },
+ {UTF8('¶'), 0 , PILCROW_SIGN, 24 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ {UTF8('¹'), 0 , SUPERSCRIPT_1, 16 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ {UTF8('º'), 0 , MASCULINE_ORDINAL, 19 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('»'), 0 , RIGHT_DBL_QUOTE, 24 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_FRACTIONS)
+ {UTF8('¼'), 0 , FRACTION_QUARTER, 40 },
+ {UTF8('½'), 0 , FRACTION_HALF, 40 },
+ {UTF8('¾'), 0 , FRACTION_THREE_FOURTHS, 40 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('¿'), 0 , INV_QUESTION, 21 },
+ #endif
+ {UTF8('À'), 'A', GRAVE, mid_A},
+ {UTF8('Á'), 'A', ACUTE, mid_A},
+ {UTF8('Â'), 'A', CIRCUMFLEX, mid_A},
+ {UTF8('Ã'), 'A', TILDE, mid_A},
+ {UTF8('Ä'), 'A', DIAERESIS, mid_A},
+ {UTF8('Å'), 'A', DOT_ABOVE, mid_A},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Æ'), 0 , LRG_AE, 40},
+ #endif
+ {UTF8('Ç'), 'C', CEDILLA, mid_C},
+ {UTF8('È'), 'E', GRAVE, mid_E},
+ {UTF8('É'), 'E', ACUTE, mid_E},
+ {UTF8('Ê'), 'E', CIRCUMFLEX, mid_E},
+ {UTF8('Ë'), 'E', DIAERESIS, mid_E},
+ {UTF8('Ì'), 'I', GRAVE, mid_I},
+ {UTF8('Í'), 'I', ACUTE, mid_I},
+ {UTF8('Î'), 'I', CIRCUMFLEX, mid_I},
+ {UTF8('Ï'), 'I', DIAERESIS, mid_I},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Ð'), 0, LRG_ETH, 31 },
+ #endif
+ {UTF8('Ñ'), 'N', TILDE, mid_N},
+ {UTF8('Ò'), 'O', GRAVE, mid_O},
+ {UTF8('Ó'), 'O', ACUTE, mid_O},
+ {UTF8('Ô'), 'O', CIRCUMFLEX, mid_O},
+ {UTF8('Õ'), 'O', TILDE, mid_O},
+ {UTF8('Ö'), 'O', DIAERESIS, mid_O},
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ {UTF8('×'), 0 , MULTIPLICATION_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Ø'), 0 , LRG_O_STROKE, 32 },
+ #endif
+ {UTF8('Ù'), 'U', GRAVE, mid_U},
+ {UTF8('Ú'), 'U', ACUTE, mid_U},
+ {UTF8('Û'), 'U', CIRCUMFLEX, mid_U},
+ {UTF8('Ü'), 'U', DIAERESIS, mid_U},
+ {UTF8('Ý'), 'Y', ACUTE, mid_Y},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Þ'), 0 , LRG_THORN, 25 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_GERMANIC)
+ {UTF8('ß'), 0 , SHARP_S, 26 },
+ #endif
+ {UTF8('à'), 'a', GRAVE, mid_a},
+ {UTF8('á'), 'a', ACUTE, mid_a},
+ {UTF8('â'), 'a', CIRCUMFLEX, mid_a},
+ {UTF8('ã'), 'a', TILDE, mid_a},
+ {UTF8('ä'), 'a', DIAERESIS, mid_a},
+ {UTF8('å'), 'a', DOT_ABOVE, mid_a},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('æ'), 0 , SML_AE, 40 },
+ #endif
+ {UTF8('ç'), 'c', CEDILLA, mid_c},
+ {UTF8('è'), 'e', GRAVE, mid_e},
+ {UTF8('é'), 'e', ACUTE, mid_e},
+ {UTF8('ê'), 'e', CIRCUMFLEX, mid_e},
+ {UTF8('ë'), 'e', DIAERESIS, mid_e},
+ {UTF8('ì'), 'i', GRAVE, mid_i},
+ {UTF8('í'), 'i', ACUTE, mid_i},
+ {UTF8('î'), 'i', CIRCUMFLEX, mid_i},
+ {UTF8('ï'), 'i', DIAERESIS, mid_i},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('ð'), 0, SML_ETH, 24 },
+ #endif
+ {UTF8('ñ'), 'n', TILDE, mid_n},
+ {UTF8('ò'), 'o', GRAVE, mid_o},
+ {UTF8('ó'), 'o', ACUTE, mid_o},
+ {UTF8('ô'), 'o', CIRCUMFLEX, mid_o},
+ {UTF8('õ'), 'o', TILDE, mid_o},
+ {UTF8('ö'), 'o', DIAERESIS, mid_o},
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ {UTF8('÷'), 0 , DIVISION_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('ø'), 0 , SML_O_STROKE, 25 },
+ #endif
+ {UTF8('ù'), 'u', GRAVE, mid_u},
+ {UTF8('ú'), 'u', ACUTE, mid_u},
+ {UTF8('û'), 'u', CIRCUMFLEX, mid_u},
+ {UTF8('ü'), 'u', DIAERESIS, mid_u},
+ {UTF8('ý'), 'y', ACUTE, mid_y},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('þ'), 0 , SML_THORN, 25 },
+ #endif
+ {UTF8('ÿ'), 'y', DIAERESIS, mid_y},
+ };
+
+ static_assert(UTF8('¡') == 0xC2A1, "Incorrect encoding for character");
+
+ /* Compile-time check that the table is in sorted order */
+
+ constexpr bool is_sorted(size_t n) {
+ return n < 2 ? true : char_recipe[n-2].unicode < char_recipe[n-1].unicode && is_sorted(n-1);
+ }
+
+ static_assert(is_sorted(NUM_ELEMENTS(char_recipe)), "The table must be sorted by unicode value");
+
+ /* Performs a binary search to find a unicode character in the table */
+
+ static int8_t find_char_data(FTDI::utf8_char_t c) {
+ int8_t min = 0, max = NUM_ELEMENTS(char_recipe), index;
+ for (;;) {
+ index = (min + max)/2;
+ const uint16_t char_at = pgm_read_word(&char_recipe[index].unicode);
+ if (char_at == c) break;
+ if (min == max) return -1;
+ if (c > char_at)
+ min = index + 1;
+ else
+ max = index;
+ }
+ return index;
+ }
+
+ static void get_char_data(uint8_t index, uint8_t &std_char, uint8_t &alt_char, uint8_t &alt_data) {
+ std_char = pgm_read_byte(&char_recipe[index].std_char);
+ alt_char = pgm_read_byte(&char_recipe[index].alt_char);
+ alt_data = pgm_read_byte(&char_recipe[index].alt_data);
+ }
+
+ /**
+ * Load bitmap data into RAMG. This function is called once at the start
+ * of the program.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ */
+
+ uint32_t FTDI::WesternCharSet::load_data(uint32_t addr) {
+ if (addr % 4 != 0)
+ addr += 4 - (addr % 4);
+
+ // Load the alternative font metrics
+ CLCD::FontMetrics alt_fm;
+ alt_fm.ptr = addr + 148;
+ alt_fm.format = L4;
+ alt_fm.stride = 19;
+ alt_fm.width = 38;
+ alt_fm.height = 49;
+ LOOP_L_N(i, 127)
+ alt_fm.char_widths[i] = 0;
+
+ // For special characters, copy the character widths from the char tables
+ LOOP_L_N(i, NUM_ELEMENTS(char_recipe)) {
+ uint8_t std_char, alt_char, alt_data;
+ get_char_data(i, std_char, alt_char, alt_data);
+ if (std_char == 0)
+ alt_fm.char_widths[alt_char] = alt_data;
+ }
+ CLCD::mem_write_bulk(addr, &alt_fm, 148);
+
+ // Decode the RLE data and load it into RAMG as a bitmap
+ uint32_t lastaddr = write_rle_data(addr + 148, font, sizeof(font));
+
+ bitmap_addr = addr;
+
+ return lastaddr;
+ }
+
+ /**
+ * Populates the bitmap handles for the custom into the display list.
+ * This function is called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::WesternCharSet::load_bitmaps(CommandProcessor& cmd) {
+ CLCD::FontMetrics alt_fm;
+ alt_fm.ptr = bitmap_addr + 148;
+ alt_fm.format = L4;
+ alt_fm.stride = 19;
+ alt_fm.width = 38;
+ alt_fm.height = 49;
+ set_font_bitmap(cmd, alt_fm, alt_font);
+ }
+
+ /**
+ * Renders a character at location x and y. The x position is incremented
+ * by the width of the character.
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the character. On output,
+ * incremented to the location of the next character.
+ *
+ * fs - A scaling object used to scale the font. The display will
+ * already be configured to scale bitmaps, but positions
+ * must be scaled using fs.scale()
+ *
+ * c - The unicode code point to draw. If the renderer does not
+ * support the character, it should return false.
+ *
+ * Returns: Whether the character was supported.
+ */
+
+ bool FTDI::WesternCharSet::render_glyph(CommandProcessor* cmd, int &x, int &y, font_size_t fs, utf8_char_t c) {
+
+ // A supported character?
+ if (c < UTF8('¡') || c > UTF8('ÿ')) return false;
+
+ int8_t index = find_char_data(c);
+ if (index == -1) return false;
+
+ // Determine character characteristics
+ uint8_t std_char, alt_char, alt_data;
+ get_char_data(index, std_char, alt_char, alt_data);
+
+ bool base_special;
+ uint8_t base_width;
+ uint8_t base_char;
+ uint8_t accent_char;
+ int8_t accent_dx, accent_dy;
+
+ if (std_char == 0) {
+ // Special character, non-accented
+ base_width = alt_data;
+ base_special = true;
+ base_char = alt_char;
+ accent_char = 0;
+ if (c == UTF8('°'))
+ x -= fs.scale(deg_sign_leading);
+ }
+ else {
+ // Regular character with accent:
+ accent_dx = alt_data - mid_accent;
+ accent_dy = isupper(std_char) ? -7 : 0;
+ accent_char = alt_char;
+ base_width = StandardCharSet::std_char_width(std_char);
+ base_special = std_char == 'i';
+ base_char = base_special ? NO_DOT_I : std_char;
+ }
+
+ // If cmd != nullptr, draw the glyph to the screen
+ if (cmd) {
+ ext_vertex2ii(*cmd, x, y, base_special ? alt_font : std_font, base_char);
+ if (accent_char)
+ ext_vertex2ii(*cmd, x + fs.scale(accent_dx), y + fs.scale(accent_dy), alt_font, accent_char);
+ }
+
+ // Increment X to the next character position
+ x += fs.scale(base_width);
+ return true;
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8 && TOUCH_UI_UTF8_WESTERN_CHARSET
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h
new file mode 100644
index 0000000..683093d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h
@@ -0,0 +1,31 @@
+/**********************
+ * western_char_set.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+namespace FTDI {
+ class WesternCharSet {
+ private:
+ static uint32_t bitmap_addr;
+ public:
+ static uint32_t load_data(uint32_t addr);
+ static void load_bitmaps(CommandProcessor&);
+ static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
+ };
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h
new file mode 100644
index 0000000..3f85cf0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h
@@ -0,0 +1,1315 @@
+/********************************
+ * western_european_bitmap_31.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/* This is a dump of "font_bitmaps/western_european_bitmap_31.png"
+ * using the tool "bitmap2cpp.py". The tool converts the image into
+ * 16-level grayscale and packs two pixels per byte. The resulting
+ * bytes are then RLE compressed to yield (count, byte) pairs.
+ */
+
+const unsigned char font[] PROGMEM = {
+
+ /* 0 GRAVE */
+ 0x76, 0x00, 0x01, 0x08, 0x01, 0xEE, 0x01, 0xE5, 0x11, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xD0,
+ 0x10, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xF9, 0x11, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF2,
+ 0x11, 0x00, 0x01, 0x5F, 0x01, 0xFD, 0x11, 0x00, 0x01, 0x06, 0x01, 0x99,
+ 0x01, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xA4, 0x00,
+
+ /* 1 ACUTE */
+ 0x7B, 0x00, 0x01, 0x9E, 0x01, 0xEE, 0x01, 0x50, 0x0F, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF8, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xD1, 0x10, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x01, 0x20, 0x0F, 0x00,
+ 0x01, 0x01, 0x01, 0xEF, 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xAA,
+ 0x01, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xA5, 0x00,
+
+ /* 2 CIRCUMFLEX */
+ 0x79, 0x00, 0x01, 0xCF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x07, 0x02, 0xFF,
+ 0x01, 0x60, 0x0F, 0x00, 0x01, 0x2F, 0x02, 0xFF, 0x01, 0xF2, 0x0F, 0x00,
+ 0x01, 0xCF, 0x01, 0xF6, 0x01, 0x6F, 0x01, 0xFB, 0x0E, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x60, 0x0D, 0x00,
+ 0x01, 0x1F, 0x01, 0xFD, 0x01, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xF1,
+ 0x0D, 0x00, 0x01, 0xBF, 0x01, 0xF3, 0x02, 0x00, 0x01, 0x3F, 0x01, 0xFB,
+ 0x0C, 0x00, 0x01, 0x02, 0x01, 0x99, 0x01, 0x50, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0x99, 0x01, 0x20, 0xFF, 0x00, 0xFF, 0x00, 0xA2, 0x00,
+
+ /* 3 TILDE */
+ 0x7C, 0x00, 0x01, 0x11, 0x0D, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xC3,
+ 0x02, 0x00, 0x01, 0xFF, 0x01, 0x80, 0x0C, 0x00, 0x01, 0xAF, 0x02, 0xFF,
+ 0x01, 0x50, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xD9, 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0x40, 0x0B, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x3E,
+ 0x02, 0xFF, 0x01, 0xFD, 0x0C, 0x00, 0x01, 0x09, 0x01, 0xFE, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xF4, 0x0C, 0x00, 0x01, 0x07,
+ 0x01, 0xA8, 0x02, 0x00, 0x01, 0x06, 0x01, 0x98, 0x01, 0x20, 0xFF, 0x00,
+ 0xFF, 0x00, 0xB6, 0x00,
+
+ /* 4 DIAERESIS */
+ 0x8A, 0x00, 0x02, 0x44, 0x02, 0x00, 0x02, 0x44, 0x0D, 0x00, 0x02, 0xFF,
+ 0x01, 0x10, 0x01, 0x01, 0x02, 0xFF, 0x0D, 0x00, 0x02, 0xFF, 0x01, 0x10,
+ 0x01, 0x01, 0x02, 0xFF, 0x0D, 0x00, 0x02, 0xFF, 0x01, 0x10, 0x01, 0x01,
+ 0x02, 0xFF, 0x0D, 0x00, 0x02, 0xCC, 0x01, 0x10, 0x01, 0x01, 0x02, 0xCC,
+ 0xFF, 0x00, 0xFF, 0x00, 0xC9, 0x00,
+
+ /* 5 DOT_ABOVE / DEGREE_SIGN */
+ 0x2D, 0x00, 0x01, 0x13, 0x01, 0x30, 0x10, 0x00, 0x01, 0x2B, 0x02, 0xFF,
+ 0x01, 0xA1, 0x0E, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFD,
+ 0x01, 0x10, 0x0D, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x94, 0x01, 0x5A,
+ 0x01, 0xFF, 0x01, 0xB0, 0x0D, 0x00, 0x01, 0x4F, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x9F, 0x01, 0xF2, 0x0D, 0x00, 0x01, 0x8F, 0x01, 0xF0, 0x02, 0x00,
+ 0x01, 0x2F, 0x01, 0xF6, 0x0D, 0x00, 0x01, 0x8F, 0x01, 0xE0, 0x02, 0x00,
+ 0x01, 0x0F, 0x01, 0xF7, 0x0D, 0x00, 0x01, 0x7F, 0x01, 0xF2, 0x02, 0x00,
+ 0x01, 0x4F, 0x01, 0xF5, 0x0D, 0x00, 0x01, 0x2F, 0x01, 0xFC, 0x01, 0x10,
+ 0x01, 0x02, 0x01, 0xDF, 0x01, 0xF0, 0x0D, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xFB, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x60, 0x0E, 0x00, 0x01, 0x9F,
+ 0x02, 0xFF, 0x01, 0xF8, 0x0F, 0x00, 0x01, 0x03, 0x01, 0x9C, 0x01, 0xC9,
+ 0x01, 0x30, 0xFF, 0x00, 0xFF, 0x00, 0xA4, 0x00,
+
+ /* 6 CEDILLA */
+ 0xFF, 0x00, 0xFF, 0x00, 0xEE, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0x20,
+ 0x11, 0x00, 0x01, 0xCF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x3F, 0x01, 0xF6,
+ 0x11, 0x00, 0x01, 0x0F, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x3F, 0x01, 0xFD,
+ 0x0E, 0x00, 0x01, 0x07, 0x01, 0xD9, 0x01, 0x89, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0E, 0x00, 0x01, 0x07, 0x03, 0xFF, 0x01, 0xF3, 0x0E, 0x00, 0x01, 0x04,
+ 0x01, 0xBD, 0x01, 0xEE, 0x01, 0xD9, 0x01, 0x20, 0x2F, 0x00,
+
+ /* 7 NO_DOT_I */
+ 0xFF, 0x00, 0x32, 0x00, 0x01, 0x01, 0x01, 0x99, 0x01, 0x96, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0xCD, 0x00,
+
+#if ENABLED(TOUCH_UI_UTF8_GERMANIC)
+ /* 8 SHARP_S */
+ 0x8A, 0x00, 0x01, 0x35, 0x01, 0x66, 0x01, 0x52, 0x0E, 0x00, 0x01, 0x03,
+ 0x01, 0xAF, 0x03, 0xFF, 0x01, 0xE7, 0x0D, 0x00, 0x01, 0x7F, 0x05, 0xFF,
+ 0x01, 0xC1, 0x0B, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xFC, 0x01, 0xAA,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFC, 0x0B, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0xF9, 0x01, 0x10, 0x01, 0x00, 0x01, 0x02, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x70, 0x0A, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x80, 0x03, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xE0, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF3, 0x09, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xFB, 0x04, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF7,
+ 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0x9E, 0x01, 0xFF, 0x01, 0xF8, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0x01, 0x01, 0xAF, 0x02, 0xFF, 0x01, 0xD7,
+ 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x1D,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x50, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xFA, 0x0C, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF4, 0x0C, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x01, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF4, 0x0C, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF9, 0x0C, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00,
+ 0x01, 0x02, 0x02, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x1D, 0x02, 0xFF,
+ 0x01, 0xD3, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00,
+ 0x01, 0x01, 0x01, 0xCF, 0x02, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x03, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xFB,
+ 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x2B,
+ 0x02, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8,
+ 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF6, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFD,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFD,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x02, 0x01, 0x84,
+ 0x03, 0x00, 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xEC, 0x01, 0xA9,
+ 0x01, 0xAC, 0x02, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x01, 0x02, 0x05, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x08, 0x00,
+ 0x01, 0x03, 0x01, 0xEE, 0x01, 0xE7, 0x01, 0x01, 0x01, 0xBF, 0x03, 0xFF,
+ 0x01, 0xFE, 0x01, 0x80, 0x0E, 0x00, 0x01, 0x35, 0x01, 0x78, 0x01, 0x76,
+ 0x01, 0x30, 0xB4, 0x00,
+#endif
+
+#if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ /* 9 LRG_O_STROKE */
+ 0x93, 0x00, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x47, 0x01, 0x9A, 0x01, 0xBA,
+ 0x01, 0x95, 0x01, 0x10, 0x02, 0x00, 0x01, 0x07, 0x01, 0xF8, 0x08, 0x00,
+ 0x01, 0x02, 0x01, 0xAF, 0x04, 0xFF, 0x01, 0xFC, 0x01, 0x50, 0x01, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x30, 0x07, 0x00, 0x01, 0x8F, 0x06, 0xFF,
+ 0x01, 0xFC, 0x01, 0x23, 0x01, 0xFF, 0x01, 0xF6, 0x07, 0x00, 0x01, 0x1C,
+ 0x03, 0xFF, 0x01, 0xCA, 0x01, 0x9B, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xFE,
+ 0x01, 0xFF, 0x01, 0x80, 0x07, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x50, 0x02, 0x00, 0x01, 0x02, 0x01, 0x9F, 0x02, 0xFF, 0x01, 0xFA,
+ 0x07, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x03,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF3, 0x07, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xF9, 0x06, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xFC, 0x07, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x06, 0x03, 0xFF,
+ 0x01, 0x60, 0x05, 0x00, 0x01, 0x04, 0x02, 0xFF, 0x01, 0x30, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFC, 0x05, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xF7, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xA0,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0xF2, 0x05, 0x00, 0x01, 0xCF, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xD1, 0x01, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x04, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x05, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF4, 0x02, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x01, 0x10, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x03, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0x01, 0x02, 0xFF,
+ 0x01, 0x30, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x02, 0x00,
+ 0x01, 0x01, 0x01, 0xEF, 0x01, 0xF8, 0x03, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xB0, 0x02, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0x03, 0x02, 0xFF,
+ 0x01, 0x10, 0x04, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00,
+ 0x01, 0xBF, 0x01, 0xFD, 0x04, 0x00, 0x01, 0x04, 0x02, 0xFF, 0x05, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xE1, 0x04, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFE, 0x05, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF,
+ 0x01, 0x30, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF5,
+ 0x05, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF7, 0x05, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF2, 0x05, 0x00, 0x01, 0x03, 0x02, 0xFF,
+ 0x01, 0xEF, 0x01, 0xFA, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x06, 0x00, 0x01, 0xCF, 0x02, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x06,
+ 0x02, 0xFF, 0x01, 0x40, 0x06, 0x00, 0x01, 0x2F, 0x02, 0xFF, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x0B,
+ 0x02, 0xFF, 0x01, 0xD2, 0x04, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0xE1,
+ 0x07, 0x00, 0x01, 0x5F, 0x03, 0xFF, 0x01, 0x93, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0xCF, 0x02, 0xFF, 0x01, 0x30, 0x06, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xFB, 0x03, 0xFF, 0x01, 0xFD, 0x01, 0xDE, 0x03, 0xFF, 0x01, 0xE3,
+ 0x07, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x4D, 0x06, 0xFF,
+ 0x01, 0xFA, 0x01, 0x10, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFB, 0x02, 0x00,
+ 0x01, 0x5C, 0x04, 0xFF, 0x01, 0xE9, 0x01, 0x30, 0x08, 0x00, 0x01, 0x1C,
+ 0x01, 0xD0, 0x03, 0x00, 0x01, 0x04, 0x01, 0x67, 0x01, 0x86, 0x01, 0x53,
+ 0x0B, 0x00, 0x01, 0x10, 0xA8, 0x00,
+
+ /* 10 SML_O_STROKE */
+ 0xFF, 0x00, 0x15, 0x00, 0x01, 0x02, 0x01, 0x20, 0x0C, 0x00, 0x01, 0x02,
+ 0x01, 0x32, 0x01, 0x10, 0x02, 0x00, 0x01, 0x1D, 0x01, 0xE3, 0x0A, 0x00,
+ 0x01, 0x01, 0x01, 0x7C, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0x82, 0x01, 0x00,
+ 0x01, 0xCF, 0x01, 0xF7, 0x0A, 0x00, 0x01, 0x6E, 0x05, 0xFF, 0x01, 0x89,
+ 0x01, 0xFF, 0x01, 0xA0, 0x09, 0x00, 0x01, 0x08, 0x07, 0xFF, 0x01, 0xFC,
+ 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x50, 0x01, 0x00,
+ 0x01, 0x3A, 0x02, 0xFF, 0x01, 0xF1, 0x09, 0x00, 0x01, 0x01, 0x02, 0xFF,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xF5, 0x09, 0x00,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x01, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF3,
+ 0x03, 0x00, 0x01, 0x0B, 0x03, 0xFF, 0x01, 0x30, 0x08, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFA, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x80, 0x08, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x80,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0xB0, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00,
+ 0x01, 0x3F, 0x01, 0xFE, 0x01, 0x10, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE0,
+ 0x08, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x40, 0x01, 0x00, 0x01, 0x02,
+ 0x01, 0xEF, 0x01, 0xF3, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0,
+ 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x01, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0x50, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF0,
+ 0x08, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30, 0x01, 0x00, 0x01, 0xBF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xB0,
+ 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x60, 0x01, 0x5F, 0x01, 0xFD, 0x03, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA3,
+ 0x01, 0xFF, 0x01, 0xE2, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x90,
+ 0x08, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0xFF, 0x01, 0x40,
+ 0x03, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x08, 0x00, 0x01, 0x0A,
+ 0x02, 0xFF, 0x01, 0xF6, 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFE,
+ 0x09, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xF8, 0x0A, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF7,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xD0, 0x09, 0x00,
+ 0x01, 0x04, 0x03, 0xFF, 0x01, 0xFC, 0x01, 0xAB, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x20, 0x09, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xAF,
+ 0x05, 0xFF, 0x01, 0xD2, 0x09, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xF5,
+ 0x01, 0x04, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xD6, 0x0A, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0x70, 0x01, 0x00, 0x01, 0x01, 0x01, 0x46, 0x01, 0x76,
+ 0x01, 0x52, 0x0C, 0x00, 0x01, 0x28, 0xA9, 0x00,
+
+ /* 11 LRG_AE */
+ 0x9E, 0x00, 0x01, 0x14, 0x0B, 0x44, 0x01, 0x41, 0x06, 0x00, 0x01, 0x8F,
+ 0x0B, 0xFF, 0x01, 0xF3, 0x06, 0x00, 0x01, 0xEF, 0x0B, 0xFF, 0x01, 0xF3,
+ 0x05, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0xEE, 0x09, 0xFF, 0x01, 0xF3,
+ 0x05, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF5, 0x01, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x63, 0x06, 0x33, 0x01, 0x30, 0x05, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x0C, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x10,
+ 0x01, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xFA, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x0B, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF3, 0x02, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x0A, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFE, 0x03, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF9,
+ 0x03, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xED, 0x06, 0xDD, 0x01, 0x80,
+ 0x03, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0xDF,
+ 0x08, 0xFF, 0x01, 0xA0, 0x03, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x03, 0x00, 0x01, 0xDF, 0x08, 0xFF, 0x01, 0xA0, 0x03, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x40, 0x03, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA8,
+ 0x06, 0x88, 0x01, 0x50, 0x02, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFE,
+ 0x04, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x09, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF4, 0x04, 0x33, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x09, 0x00, 0x01, 0x7F, 0x08, 0xFF, 0x01, 0x40,
+ 0x09, 0x00, 0x01, 0xEF, 0x08, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x05,
+ 0x09, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF7,
+ 0x05, 0x33, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x80, 0x05, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x05, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xFB, 0x06, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA8, 0x06, 0x88,
+ 0x01, 0x85, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF4, 0x06, 0x00, 0x01, 0xDF,
+ 0x08, 0xFF, 0x01, 0xF9, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xE0, 0x06, 0x00,
+ 0x01, 0xDF, 0x08, 0xFF, 0x01, 0xF9, 0x01, 0x8D, 0x01, 0xDD, 0x01, 0x60,
+ 0x06, 0x00, 0x01, 0xBD, 0x08, 0xDD, 0x01, 0xD8, 0xBE, 0x00,
+
+ /* 12 SML_AE */
+ 0xFF, 0x00, 0x22, 0x00, 0x01, 0x01, 0x01, 0x34, 0x01, 0x31, 0x06, 0x00,
+ 0x01, 0x12, 0x01, 0x42, 0x01, 0x10, 0x05, 0x00, 0x01, 0x02, 0x01, 0x7B,
+ 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x60, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0x9E, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0x81, 0x04, 0x00, 0x01, 0xBF,
+ 0x05, 0xFF, 0x01, 0xFE, 0x01, 0x40, 0x01, 0x01, 0x01, 0x9F, 0x05, 0xFF,
+ 0x01, 0x60, 0x03, 0x00, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xEE, 0x03, 0xFF,
+ 0x01, 0xF5, 0x01, 0x1D, 0x03, 0xFF, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF8,
+ 0x03, 0x00, 0x01, 0xDF, 0x01, 0xB6, 0x01, 0x30, 0x01, 0x00, 0x01, 0x01,
+ 0x01, 0x5D, 0x02, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xE7, 0x01, 0x20,
+ 0x01, 0x00, 0x01, 0x29, 0x02, 0xFF, 0x01, 0x50, 0x02, 0x00, 0x01, 0x71,
+ 0x05, 0x00, 0x01, 0xAF, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x10, 0x03, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x0D, 0x02, 0xFF,
+ 0x01, 0xD0, 0x04, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7, 0x08, 0x00,
+ 0x01, 0x06, 0x02, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0xEF, 0x01, 0xFD,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFD, 0x06, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x04, 0x00, 0x01, 0x02, 0x01, 0x45, 0x02, 0x66, 0x01, 0x67,
+ 0x01, 0xFF, 0x01, 0xF9, 0x06, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x03, 0x00,
+ 0x01, 0x4A, 0x06, 0xFF, 0x01, 0xFB, 0x03, 0x66, 0x01, 0x67, 0x02, 0x77,
+ 0x01, 0xAF, 0x01, 0xFF, 0x02, 0x00, 0x01, 0x1B, 0x10, 0xFF, 0x01, 0x00,
+ 0x01, 0x01, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xCA, 0x01, 0x98, 0x01, 0x88,
+ 0x01, 0x89, 0x0A, 0xFF, 0x01, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x40, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFA, 0x08, 0x77,
+ 0x01, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x04, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x70,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFA, 0x09, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFE,
+ 0x09, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0F,
+ 0x02, 0xFF, 0x01, 0x50, 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x60,
+ 0x04, 0x00, 0x01, 0x8F, 0x02, 0xFF, 0x01, 0xE1, 0x08, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x05, 0x00, 0x01, 0x45, 0x01, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x20, 0x01, 0x00, 0x01, 0x01,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xA2, 0x02, 0xFF, 0x01, 0xE6, 0x01, 0x10,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0x8D, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x05,
+ 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xAB, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xFC,
+ 0x01, 0x00, 0x01, 0x3F, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xBA, 0x01, 0xBC,
+ 0x02, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x7F, 0x05, 0xFF, 0x01, 0xA0,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xCF, 0x06, 0xFF, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x03, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xB4, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xBF, 0x04, 0xFF, 0x01, 0xB7, 0x01, 0x10, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0x46, 0x01, 0x76, 0x01, 0x41, 0x06, 0x00, 0x01, 0x35, 0x01, 0x67,
+ 0x01, 0x64, 0x01, 0x20, 0xAD, 0x00,
+
+ /* 13 LRG_ETH */
+ 0x9A, 0x00, 0x01, 0x34, 0x03, 0x44, 0x01, 0x43, 0x01, 0x21, 0x0D, 0x00,
+ 0x01, 0xBF, 0x05, 0xFF, 0x01, 0xFE, 0x01, 0xB8, 0x01, 0x40, 0x0A, 0x00,
+ 0x01, 0xBF, 0x07, 0xFF, 0x01, 0xFE, 0x01, 0x81, 0x09, 0x00, 0x01, 0xBF,
+ 0x08, 0xFF, 0x01, 0xFE, 0x01, 0x60, 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x61, 0x02, 0x11, 0x01, 0x23, 0x01, 0x58, 0x01, 0xCF, 0x02, 0xFF,
+ 0x01, 0xF9, 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x04, 0x00,
+ 0x01, 0x02, 0x01, 0x9F, 0x02, 0xFF, 0x01, 0x80, 0x07, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x50, 0x05, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xF4, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFD, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x06, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xF0, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x07, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF3, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xF5, 0x04, 0x00, 0x01, 0x23, 0x01, 0x33, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x73, 0x02, 0x33, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xF6, 0x04, 0x00, 0x01, 0xCF, 0x06, 0xFF, 0x01, 0xF2, 0x04, 0x00,
+ 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0xCF, 0x06, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF9, 0x04, 0x00,
+ 0x01, 0x9B, 0x01, 0xBB, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xDB, 0x02, 0xBB,
+ 0x01, 0xB1, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xF7, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00,
+ 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF6, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF4, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xD0, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x06, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x80, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0B, 0x02, 0xFF,
+ 0x01, 0x20, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF9, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x05, 0x00, 0x01, 0x0A, 0x02, 0xFF, 0x01, 0xE1, 0x07, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x04, 0x00, 0x01, 0x29, 0x03, 0xFF,
+ 0x01, 0x30, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xA7, 0x01, 0x77,
+ 0x01, 0x78, 0x01, 0x9A, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xE3, 0x08, 0x00,
+ 0x01, 0xBF, 0x08, 0xFF, 0x01, 0xF9, 0x01, 0x10, 0x08, 0x00, 0x01, 0xBF,
+ 0x07, 0xFF, 0x01, 0xD8, 0x01, 0x10, 0x09, 0x00, 0x01, 0xAD, 0x03, 0xDD,
+ 0x01, 0xDC, 0x01, 0xCB, 0x01, 0xA7, 0x01, 0x41, 0xC7, 0x00,
+
+ /* 14 SML_ETH */
+ 0x88, 0x00, 0x01, 0x38, 0x01, 0x88, 0x01, 0x81, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x5A, 0x01, 0x40, 0x0C, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x04, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0C, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0xFC, 0x02, 0xFF,
+ 0x01, 0xD8, 0x01, 0x20, 0x0C, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xFD,
+ 0x01, 0x82, 0x0D, 0x00, 0x01, 0x5A, 0x03, 0xFF, 0x01, 0xF4, 0x0D, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x87, 0x02, 0xFF, 0x01, 0x30,
+ 0x0C, 0x00, 0x01, 0x6F, 0x01, 0xE9, 0x01, 0x30, 0x01, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0xE2, 0x0C, 0x00, 0x01, 0x03, 0x03, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x23, 0x01, 0x44,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x02, 0x01, 0x9E,
+ 0x04, 0xFF, 0x01, 0xF7, 0x0C, 0x00, 0x01, 0x7F, 0x06, 0xFF, 0x01, 0x30,
+ 0x0A, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0xFE, 0x01, 0xCB, 0x01, 0xDF,
+ 0x02, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFB,
+ 0x01, 0x30, 0x02, 0x00, 0x01, 0x4E, 0x01, 0xFF, 0x01, 0xF5, 0x09, 0x00,
+ 0x01, 0x02, 0x02, 0xFF, 0x01, 0x70, 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xFD, 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x20, 0x08, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x05, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA0, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0xB0, 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0x40, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30, 0x05, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xF0, 0x08, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30, 0x05, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0x40, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA0, 0x05, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x90, 0x08, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x05, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x08, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xFE, 0x09, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x60, 0x03, 0x00,
+ 0x01, 0x3E, 0x01, 0xFF, 0x01, 0xF6, 0x0A, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x01, 0xF9, 0x01, 0x20, 0x01, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xB0,
+ 0x0A, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xBD, 0x02, 0xFF,
+ 0x01, 0xFD, 0x01, 0x10, 0x0B, 0x00, 0x01, 0x7F, 0x05, 0xFF, 0x01, 0xB0,
+ 0x0C, 0x00, 0x01, 0x02, 0x01, 0xAE, 0x03, 0xFF, 0x01, 0xB4, 0x0F, 0x00,
+ 0x01, 0x35, 0x01, 0x65, 0x01, 0x40, 0xB6, 0x00,
+
+ /* 15 LRG_THORN */
+ 0x9A, 0x00, 0x02, 0x55, 0x11, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x05, 0xFF, 0x01, 0xED, 0x01, 0xA7, 0x01, 0x10, 0x0B, 0x00, 0x07, 0xFF,
+ 0x01, 0xFA, 0x01, 0x10, 0x0A, 0x00, 0x08, 0xFF, 0x01, 0xE2, 0x0A, 0x00,
+ 0x02, 0xFF, 0x01, 0x65, 0x01, 0x55, 0x01, 0x56, 0x01, 0x7A, 0x02, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x1B, 0x02, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20,
+ 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xF0, 0x09, 0x00, 0x02, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x09, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6,
+ 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xF7, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20,
+ 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x09, 0x00, 0x02, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xF0, 0x09, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x1B, 0x02, 0xFF, 0x01, 0x80,
+ 0x09, 0x00, 0x02, 0xFF, 0x01, 0x65, 0x02, 0x55, 0x01, 0x7A, 0x02, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x09, 0x00, 0x08, 0xFF, 0x01, 0xE2, 0x0A, 0x00,
+ 0x07, 0xFF, 0x01, 0xFA, 0x01, 0x10, 0x0A, 0x00, 0x05, 0xFF, 0x01, 0xED,
+ 0x01, 0xA7, 0x01, 0x10, 0x0B, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xCC, 0x01, 0x10, 0xCC, 0x00,
+
+ /* 16 SML_THORN */
+ 0x86, 0x00, 0x01, 0x02, 0x01, 0x99, 0x01, 0x94, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x02, 0x00, 0x01, 0x13, 0x01, 0x54, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x00, 0x01, 0x5C, 0x02, 0xFF, 0x01, 0xFD,
+ 0x01, 0x70, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x0B,
+ 0x04, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xEC, 0x01, 0xDF, 0x02, 0xFF,
+ 0x01, 0xE1, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0xFF,
+ 0x01, 0xC3, 0x02, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFC, 0x09, 0x00,
+ 0x01, 0x03, 0x02, 0xFF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x60, 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF3,
+ 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF7, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFC, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF9, 0x06, 0x00, 0x01, 0xFF, 0x01, 0xFD, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xFE, 0x08, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xEF,
+ 0x01, 0xFE, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF9, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xFD, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFC,
+ 0x05, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00,
+ 0x01, 0x03, 0x02, 0xFF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF3, 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0xD0, 0x04, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF,
+ 0x01, 0xFA, 0x03, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x60,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0xFF, 0x01, 0xB3,
+ 0x02, 0x00, 0x01, 0x6E, 0x01, 0xFF, 0x01, 0xFC, 0x09, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xEC, 0x01, 0xCF,
+ 0x02, 0xFF, 0x01, 0xE2, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x01, 0x0B, 0x04, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x09, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x00, 0x01, 0x6C, 0x02, 0xFF, 0x01, 0xFE,
+ 0x01, 0x70, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x23, 0x01, 0x54, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x10, 0x00, 0x01, 0x01, 0x01, 0x66, 0x01, 0x63, 0x22, 0x00,
+#endif // TOUCH_UI_UTF8_SCANDINAVIAN
+
+#if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ /* 17 LEFT_DBL_QUOTE */
+ 0xFF, 0x00, 0x4A, 0x00, 0x01, 0x30, 0x03, 0x00, 0x01, 0x02, 0x0D, 0x00,
+ 0x01, 0x08, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x01, 0x01, 0xC6, 0x0D, 0x00,
+ 0x01, 0xAF, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x1D, 0x01, 0xF6, 0x0C, 0x00,
+ 0x01, 0x1C, 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x50,
+ 0x01, 0x00, 0x01, 0x3E, 0x01, 0xFF, 0x01, 0xE2, 0x0B, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x20, 0x0A, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x30,
+ 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xD1, 0x0B, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0xD2, 0x01, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0B, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x01, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xD0, 0x02, 0x00, 0x01, 0xFF, 0x01, 0xFA, 0x0C, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x50,
+ 0x0C, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x1C,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0C, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFB,
+ 0x02, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x90, 0x0C, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xD1, 0x01, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFA,
+ 0x0C, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x01, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF6, 0x0C, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x5F, 0x01, 0xF6,
+ 0x0D, 0x00, 0x01, 0x1D, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x04, 0x01, 0xE6,
+ 0x0D, 0x00, 0x01, 0x01, 0x01, 0x60, 0x03, 0x00, 0x01, 0x24, 0xFF, 0x00,
+
+ /* 18 RIGHT_DBL_QUOTE */
+ 0xFF, 0x00, 0x46, 0x00, 0x01, 0x20, 0x03, 0x00, 0x01, 0x20, 0x0D, 0x00,
+ 0x01, 0x01, 0x01, 0xE3, 0x03, 0x00, 0x01, 0x5D, 0x01, 0x10, 0x0C, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00, 0x01, 0x5F, 0x01, 0xE2,
+ 0x0C, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF6, 0x02, 0x00, 0x01, 0x5F,
+ 0x01, 0xFE, 0x01, 0x30, 0x0C, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x80,
+ 0x01, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xF5, 0x0C, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xFA, 0x01, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x60, 0x0C, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF9, 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xFC, 0x01, 0x10, 0x01, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0,
+ 0x0C, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD1, 0x01, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x10, 0x0B, 0x00, 0x01, 0x2D,
+ 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x10, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x40,
+ 0x01, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD2, 0x0B, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0xE3, 0x01, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFC,
+ 0x01, 0x10, 0x0A, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10,
+ 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xC1, 0x01, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF9,
+ 0x0B, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x90,
+ 0x02, 0x00, 0x01, 0x5F, 0x01, 0xF6, 0x0C, 0x00, 0x01, 0x01, 0x01, 0xF8,
+ 0x03, 0x00, 0x01, 0x5F, 0x01, 0x40, 0x0C, 0x00, 0x01, 0x01, 0x01, 0x50,
+ 0x03, 0x00, 0x01, 0x43, 0xFF, 0x00, 0x04, 0x00,
+
+ /* 19 INV_EXCLAMATION */
+ 0xFF, 0x00, 0x34, 0x00, 0x01, 0xAD, 0x01, 0xDD, 0x01, 0x40, 0x10, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x34, 0x01, 0x44,
+ 0x01, 0x10, 0x49, 0x00, 0x01, 0x02, 0x01, 0x22, 0x11, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x11, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x11, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x10, 0x10, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x30, 0x10, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x30, 0x10, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x40,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x34,
+ 0x01, 0x44, 0x01, 0x10, 0x33, 0x00,
+
+ /* 20 INV_QUESTION */
+ 0xFF, 0x00, 0x36, 0x00, 0x02, 0xDD, 0x11, 0x00, 0x02, 0xFF, 0x11, 0x00,
+ 0x02, 0xFF, 0x11, 0x00, 0x02, 0xFF, 0x11, 0x00, 0x02, 0xFF, 0x11, 0x00,
+ 0x02, 0x44, 0x37, 0x00, 0x01, 0xBC, 0x01, 0xCB, 0x11, 0x00, 0x01, 0xEF,
+ 0x01, 0xFE, 0x11, 0x00, 0x01, 0xEF, 0x01, 0xFE, 0x11, 0x00, 0x01, 0xEF,
+ 0x01, 0xFE, 0x11, 0x00, 0x01, 0xFF, 0x01, 0xFD, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xFB, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xD0, 0x0F, 0x00, 0x01, 0x0A,
+ 0x02, 0xFF, 0x01, 0x30, 0x0F, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xF4,
+ 0x0F, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0x40, 0x0F, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0F, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0x40,
+ 0x0F, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF8, 0x10, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x05, 0x01, 0xD0, 0x0A, 0x00,
+ 0x01, 0x08, 0x02, 0xFF, 0x01, 0x70, 0x02, 0x00, 0x01, 0x05, 0x01, 0xCF,
+ 0x01, 0xF0, 0x0A, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x98, 0x01, 0x8B, 0x02, 0xFF, 0x01, 0xF0, 0x0B, 0x00, 0x01, 0x3F,
+ 0x06, 0xFF, 0x01, 0xC0, 0x0B, 0x00, 0x01, 0x02, 0x01, 0xCF, 0x04, 0xFF,
+ 0x01, 0xC5, 0x0D, 0x00, 0x01, 0x03, 0x01, 0x8B, 0x01, 0xCC, 0x01, 0xB9,
+ 0x01, 0x62, 0x31, 0x00,
+#endif // TOUCH_UI_UTF8_PUNCTUATION
+
+#if ENABLED(TOUCH_UI_UTF8_CURRENCY)
+ /* 21 CENT_SIGN */
+ 0xB1, 0x00, 0x01, 0x01, 0x01, 0x32, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x11, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFC,
+ 0x11, 0x00, 0x01, 0x39, 0x01, 0xFD, 0x01, 0x42, 0x0E, 0x00, 0x01, 0x05,
+ 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xFB, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x03,
+ 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x4F, 0x02, 0xFF,
+ 0x02, 0xFE, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0xF6, 0x0A, 0x00, 0x01, 0x02,
+ 0x02, 0xFF, 0x01, 0xE6, 0x01, 0x05, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x38,
+ 0x01, 0xE6, 0x0A, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10,
+ 0x01, 0x05, 0x01, 0xFC, 0x02, 0x00, 0x01, 0x02, 0x0A, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0xE1, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x0D, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x60, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFC,
+ 0x0D, 0x00, 0x02, 0xFF, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x0C, 0x00,
+ 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFB, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFC,
+ 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x05, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF7, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x0C, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFC, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x0D, 0x00, 0x02, 0xFF, 0x01, 0x10, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x0D, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x0D, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00,
+ 0x01, 0x05, 0x01, 0xFB, 0x0D, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x30, 0x01, 0x05, 0x01, 0xFB, 0x02, 0x00, 0x01, 0x33, 0x0A, 0x00,
+ 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0x35, 0x01, 0xFB,
+ 0x01, 0x02, 0x01, 0x6C, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x2D, 0x06, 0xFF,
+ 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x01, 0x01, 0x9F, 0x05, 0xFF, 0x01, 0xF5,
+ 0x0C, 0x00, 0x01, 0x02, 0x01, 0x8D, 0x03, 0xFF, 0x01, 0xC7, 0x01, 0x20,
+ 0x0E, 0x00, 0x01, 0x06, 0x01, 0xFC, 0x01, 0x20, 0x10, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x57, 0x00,
+
+ /* 22 POUND_SIGN */
+ 0x9E, 0x00, 0x01, 0x6B, 0x01, 0xDF, 0x01, 0xFD, 0x01, 0xC9, 0x01, 0x40,
+ 0x0D, 0x00, 0x01, 0x6E, 0x05, 0xFF, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x07,
+ 0x06, 0xFF, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x85, 0x01, 0x34, 0x01, 0x7B, 0x01, 0xFF, 0x01, 0x30, 0x0B, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xC1, 0x03, 0x00, 0x01, 0x18, 0x01, 0x30,
+ 0x0A, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x30, 0x0F, 0x00, 0x01, 0x04,
+ 0x01, 0xFF, 0x01, 0xFD, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xFA,
+ 0x10, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF8, 0x10, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x0E, 0x00, 0x01, 0x0A,
+ 0x07, 0xFF, 0x01, 0xF4, 0x0A, 0x00, 0x01, 0x0A, 0x07, 0xFF, 0x01, 0xF4,
+ 0x0A, 0x00, 0x01, 0x08, 0x01, 0xDD, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFE,
+ 0x03, 0xDD, 0x01, 0xD4, 0x0C, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0E, 0x00, 0x01, 0x4B, 0x01, 0xBB, 0x01, 0xBE,
+ 0x01, 0xFF, 0x01, 0xFD, 0x05, 0xBB, 0x01, 0x70, 0x08, 0x00, 0x01, 0x6F,
+ 0x09, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x6F, 0x09, 0xFF, 0x01, 0xA0,
+ 0x08, 0x00, 0x01, 0x4A, 0x09, 0xAA, 0x01, 0x60, 0xC5, 0x00,
+
+ /* 23 CURRENCY_SIGN */
+ 0xFF, 0x00, 0x0D, 0x00, 0x01, 0x30, 0x07, 0x00, 0x01, 0x01, 0x01, 0x40,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xF5, 0x07, 0x00, 0x01, 0x1D, 0x01, 0xF4,
+ 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x01,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x30, 0x07, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xF4, 0x01, 0x00, 0x01, 0x6B, 0x01, 0xDD, 0x01, 0xC8, 0x01, 0x20,
+ 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xFA, 0x08, 0x00, 0x01, 0x05, 0x02, 0xFF,
+ 0x01, 0x8E, 0x03, 0xFF, 0x01, 0xFA, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA0,
+ 0x09, 0x00, 0x01, 0x5F, 0x07, 0xFF, 0x01, 0xFA, 0x0A, 0x00, 0x01, 0x05,
+ 0x02, 0xFF, 0x01, 0xE9, 0x01, 0x55, 0x01, 0x7C, 0x02, 0xFF, 0x01, 0xA0,
+ 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x10, 0x02, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xA0, 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xC0, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF2, 0x0A, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xF7,
+ 0x0A, 0x00, 0x01, 0x4F, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x8F, 0x01, 0xFA,
+ 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFC, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFC,
+ 0x0A, 0x00, 0x01, 0x5F, 0x01, 0xFC, 0x05, 0x00, 0x01, 0x7F, 0x01, 0xFB,
+ 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x10, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0xF8, 0x0A, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0x80, 0x03, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF3, 0x0A, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF5, 0x03, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00,
+ 0x01, 0x01, 0x02, 0xFF, 0x01, 0x92, 0x01, 0x00, 0x01, 0x16, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x60, 0x0A, 0x00, 0x01, 0x1D, 0x03, 0xFF, 0x01, 0xFE,
+ 0x03, 0xFF, 0x01, 0xF4, 0x09, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x05, 0xFF,
+ 0x01, 0xFE, 0x02, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x1D, 0x01, 0xFF,
+ 0x01, 0xFA, 0x01, 0x06, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x81,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF4, 0x08, 0x00, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x01, 0x00, 0x01, 0x01, 0x01, 0x44, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0x05, 0x02, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFA,
+ 0x07, 0x00, 0x01, 0x4F, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x05, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x05, 0x01, 0x80, 0xEB, 0x00,
+
+ /* 24 YEN_SIGN */
+ 0x98, 0x00, 0x01, 0x01, 0x01, 0x88, 0x01, 0x85, 0x07, 0x00, 0x01, 0x38,
+ 0x01, 0x88, 0x01, 0x40, 0x07, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2, 0x05, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFA,
+ 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x60, 0x09, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x0A, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF5, 0x0A, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x01, 0x01, 0xEF,
+ 0x01, 0xFD, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x50, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3, 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF7, 0x01, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xA0, 0x0A, 0x00,
+ 0x01, 0x2A, 0x02, 0xAA, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0xCA, 0x01, 0xAA, 0x01, 0xA5, 0x08, 0x00, 0x01, 0x4F,
+ 0x04, 0xFF, 0x01, 0x83, 0x04, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x3C,
+ 0x02, 0xCC, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0xFF, 0x01, 0xFC,
+ 0x02, 0xCC, 0x01, 0xC6, 0x0B, 0x00, 0x01, 0x03, 0x03, 0xFF, 0x01, 0x70,
+ 0x0F, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xFE, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xF5, 0x0C, 0x00, 0x01, 0x01, 0x03, 0x11, 0x01, 0x1E,
+ 0x01, 0xFF, 0x01, 0xF3, 0x03, 0x11, 0x01, 0x10, 0x08, 0x00, 0x01, 0x4F,
+ 0x09, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x4F, 0x09, 0xFF, 0x01, 0xF8,
+ 0x08, 0x00, 0x01, 0x27, 0x03, 0x77, 0x01, 0x7E, 0x01, 0xFF, 0x01, 0xF8,
+ 0x03, 0x77, 0x01, 0x73, 0x0C, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x08,
+ 0x01, 0x99, 0x01, 0x91, 0xC9, 0x00,
+#endif // TOUCH_UI_UTF8_CURRENCY
+
+#if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ /* 25 SUPERSCRIPT_ONE */
+ 0x99, 0x00, 0x01, 0x01, 0x01, 0x36, 0x01, 0x9B, 0x01, 0xBB, 0x01, 0x20,
+ 0x0E, 0x00, 0x01, 0x3F, 0x03, 0xFF, 0x01, 0x20, 0x0E, 0x00, 0x01, 0x3F,
+ 0x01, 0xFE, 0x01, 0xBE, 0x01, 0xFF, 0x01, 0x20, 0x0E, 0x00, 0x01, 0x14,
+ 0x01, 0x10, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x0F, 0x00, 0x01, 0x11, 0x01, 0x1C, 0x01, 0xFF,
+ 0x01, 0x31, 0x01, 0x11, 0x0D, 0x00, 0x01, 0x0D, 0x05, 0xFF, 0x01, 0x40,
+ 0x0C, 0x00, 0x01, 0x0D, 0x05, 0xFF, 0x01, 0x40, 0x0C, 0x00, 0x01, 0x01,
+ 0x05, 0x22, 0xFF, 0x00, 0xC2, 0x00,
+
+ /* 26 SUPERSCRIPT_TWO */
+ 0x88, 0x00, 0x01, 0x01, 0x10, 0x00, 0x01, 0x16, 0x01, 0xAE, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x92, 0x0E, 0x00, 0x05, 0xFF, 0x01, 0x60, 0x0D, 0x00,
+ 0x01, 0xFE, 0x01, 0x84, 0x01, 0x22, 0x01, 0x5C, 0x01, 0xFF, 0x01, 0xF3,
+ 0x0D, 0x00, 0x01, 0x50, 0x03, 0x00, 0x01, 0xCF, 0x01, 0xFA, 0x11, 0x00,
+ 0x01, 0x5F, 0x01, 0xFC, 0x11, 0x00, 0x01, 0x5F, 0x01, 0xFB, 0x11, 0x00,
+ 0x01, 0xCF, 0x01, 0xF4, 0x10, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x6F, 0x01, 0xFE, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xE2, 0x10, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x30,
+ 0x0F, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xE3, 0x10, 0x00, 0x01, 0x6F,
+ 0x01, 0xFE, 0x01, 0x20, 0x0F, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xD1,
+ 0x10, 0x00, 0x01, 0xAF, 0x01, 0xFD, 0x01, 0x43, 0x03, 0x33, 0x0C, 0x00,
+ 0x01, 0x01, 0x06, 0xFF, 0x0C, 0x00, 0x01, 0x01, 0x06, 0xFF, 0x0D, 0x00,
+ 0x06, 0x22, 0xFF, 0x00, 0xC2, 0x00,
+
+ /* 27 SUPERSCRIPT_THREE */
+ 0x88, 0x00, 0x01, 0x01, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x39, 0x01, 0xCE,
+ 0x02, 0xFF, 0x01, 0xB5, 0x0E, 0x00, 0x01, 0x7F, 0x04, 0xFF, 0x01, 0xB0,
+ 0x0D, 0x00, 0x01, 0x6B, 0x01, 0x73, 0x01, 0x22, 0x01, 0x38, 0x01, 0xFF,
+ 0x01, 0xF9, 0x11, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x11, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x11, 0x00, 0x01, 0x4F, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x27,
+ 0x01, 0xFF, 0x01, 0xF3, 0x0E, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xFA,
+ 0x01, 0x20, 0x0E, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x40,
+ 0x0E, 0x00, 0x01, 0x01, 0x01, 0x23, 0x01, 0x49, 0x01, 0xFF, 0x01, 0xF6,
+ 0x11, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x10, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x60,
+ 0x10, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0x40, 0x0C, 0x00, 0x01, 0xA4,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xDF, 0x01, 0xFD, 0x0D, 0x00, 0x02, 0xFF,
+ 0x01, 0xDE, 0x02, 0xFF, 0x01, 0xE3, 0x0D, 0x00, 0x01, 0xAE, 0x03, 0xFF,
+ 0x01, 0xE9, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x24, 0x01, 0x55, 0x01, 0x52,
+ 0xFF, 0x00, 0xC4, 0x00,
+#endif // TOUCH_UI_UTF8_SUPERSCRIPTS
+
+#if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ /* 28 MASCULINE_ORDINAL */
+ 0x89, 0x00, 0x01, 0x01, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x01, 0x01, 0x8D,
+ 0x02, 0xFF, 0x01, 0xB4, 0x0E, 0x00, 0x01, 0x4F, 0x04, 0xFF, 0x01, 0xA0,
+ 0x0C, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x63, 0x01, 0x48,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xA0,
+ 0x02, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x6F,
+ 0x01, 0xFE, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xD0, 0x0B, 0x00,
+ 0x01, 0xBF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF3, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xF6, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF1, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xF7, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF1, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xF7, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xF6, 0x0B, 0x00,
+ 0x01, 0xCF, 0x01, 0xF6, 0x04, 0x00, 0x01, 0xEF, 0x01, 0xF4, 0x0B, 0x00,
+ 0x01, 0x8F, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF0,
+ 0x0B, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0x1D,
+ 0x01, 0xFF, 0x01, 0x90, 0x0B, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF8,
+ 0x01, 0x10, 0x01, 0x04, 0x01, 0xDF, 0x01, 0xFE, 0x01, 0x10, 0x0C, 0x00,
+ 0x01, 0xAF, 0x04, 0xFF, 0x01, 0xE3, 0x0D, 0x00, 0x01, 0x05, 0x01, 0xDF,
+ 0x02, 0xFF, 0x01, 0xFA, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x02, 0x01, 0x56,
+ 0x01, 0x64, 0x21, 0x00, 0x01, 0x16, 0x06, 0x66, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x3F, 0x06, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x3F, 0x06, 0xFF,
+ 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x01, 0x06, 0x11, 0xFF, 0x00, 0x75, 0x00,
+
+ /* 29 FEMININE_ORDINAL */
+ 0x89, 0x00, 0x01, 0x12, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x49, 0x01, 0xDF,
+ 0x02, 0xFF, 0x01, 0xB4, 0x0D, 0x00, 0x01, 0x07, 0x05, 0xFF, 0x01, 0xA0,
+ 0x0C, 0x00, 0x01, 0x07, 0x01, 0xFC, 0x01, 0x74, 0x01, 0x33, 0x01, 0x59,
+ 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0x03, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x10, 0x10, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0x50, 0x0E, 0x00, 0x01, 0x01, 0x01, 0x11, 0x01, 0x16, 0x01, 0xFF,
+ 0x01, 0x80, 0x0C, 0x00, 0x01, 0x05, 0x01, 0xAE, 0x04, 0xFF, 0x01, 0x90,
+ 0x0B, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xA0, 0x0B, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xE9, 0x01, 0x65, 0x01, 0x44, 0x01, 0x48,
+ 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x5F, 0x01, 0xFD, 0x01, 0x10,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x9F,
+ 0x01, 0xF6, 0x03, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00,
+ 0x01, 0xAF, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xA0,
+ 0x0B, 0x00, 0x01, 0x9F, 0x01, 0xFA, 0x03, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA2, 0x01, 0x00,
+ 0x01, 0x3B, 0x02, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x0A, 0x04, 0xFF,
+ 0x01, 0xE7, 0x01, 0xFF, 0x01, 0xA0, 0x0C, 0x00, 0x01, 0x8F, 0x02, 0xFF,
+ 0x01, 0xF9, 0x01, 0x15, 0x01, 0xFF, 0x01, 0xA0, 0x0D, 0x00, 0x01, 0x46,
+ 0x01, 0x64, 0x02, 0x00, 0x01, 0x11, 0x1F, 0x00, 0x01, 0x16, 0x06, 0x66,
+ 0x01, 0x40, 0x0B, 0x00, 0x01, 0x3F, 0x06, 0xFF, 0x01, 0xB0, 0x0B, 0x00,
+ 0x01, 0x3F, 0x06, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x01, 0x06, 0x11,
+ 0xFF, 0x00, 0x75, 0x00,
+#endif // TOUCH_UI_UTF8_ORDINALS
+
+#if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ /* 30 COPYRIGHT_SIGN */
+ 0xA0, 0x00, 0x01, 0x01, 0x01, 0x45, 0x01, 0x76, 0x01, 0x43, 0x0E, 0x00,
+ 0x01, 0x28, 0x01, 0xDF, 0x03, 0xFF, 0x01, 0xE9, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xDB, 0x01, 0xAB, 0x01, 0xCE, 0x01, 0xFF,
+ 0x01, 0xFB, 0x01, 0x30, 0x09, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFB,
+ 0x01, 0x50, 0x03, 0x00, 0x01, 0x38, 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00,
+ 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00, 0x01, 0x19, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x5F, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x3F, 0x01, 0xF8, 0x03, 0x00,
+ 0x01, 0x46, 0x01, 0x88, 0x01, 0x65, 0x01, 0x10, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0x80, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xA0, 0x01, 0x00,
+ 0x01, 0x01, 0x01, 0x9F, 0x03, 0xFF, 0x01, 0xFC, 0x01, 0x60, 0x01, 0x00,
+ 0x01, 0x4F, 0x01, 0xF4, 0x05, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00,
+ 0x01, 0x4E, 0x02, 0xFF, 0x01, 0xED, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x01, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xF4,
+ 0x01, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x61, 0x01, 0x00,
+ 0x01, 0x01, 0x01, 0x4A, 0x01, 0xA0, 0x02, 0x00, 0x01, 0xEF, 0x01, 0x60,
+ 0x04, 0x00, 0x01, 0x6F, 0x01, 0xC0, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xC1, 0x07, 0x00, 0x01, 0x7F, 0x01, 0xB0, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x60, 0x01, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xF0, 0x04, 0x00, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0xDF, 0x01, 0xF9, 0x08, 0x00, 0x01, 0x0D, 0x01, 0xF4, 0x03, 0x00,
+ 0x01, 0x01, 0x01, 0xFE, 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF4,
+ 0x08, 0x00, 0x01, 0x0A, 0x01, 0xF6, 0x03, 0x00, 0x01, 0x03, 0x01, 0xFD,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0x08,
+ 0x01, 0xF8, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x07, 0x01, 0xF9, 0x03, 0x00,
+ 0x01, 0x03, 0x01, 0xFD, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0x08, 0x01, 0xF8, 0x03, 0x00, 0x01, 0x01, 0x01, 0xFE,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF3, 0x08, 0x00, 0x01, 0x09,
+ 0x01, 0xF7, 0x04, 0x00, 0x01, 0xFF, 0x01, 0x10, 0x01, 0x00, 0x01, 0xDF,
+ 0x01, 0xF8, 0x08, 0x00, 0x01, 0x0C, 0x01, 0xF5, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x60, 0x01, 0x00, 0x01, 0x8F, 0x01, 0xFE, 0x01, 0x10, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xF1, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xB0, 0x01, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x6F, 0x01, 0xC0,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x50, 0x02, 0x00, 0x01, 0x29, 0x01, 0xA0, 0x02, 0x00,
+ 0x01, 0xEF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00,
+ 0x01, 0x6F, 0x02, 0xFF, 0x01, 0xDB, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0xB0,
+ 0x01, 0x00, 0x01, 0x07, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x01, 0x01, 0xEF,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x02, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xFE,
+ 0x01, 0x70, 0x01, 0x00, 0x01, 0x4F, 0x01, 0xF4, 0x06, 0x00, 0x01, 0x4F,
+ 0x01, 0xF7, 0x02, 0x00, 0x01, 0x01, 0x01, 0x58, 0x01, 0x9A, 0x01, 0x86,
+ 0x01, 0x30, 0x01, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0x80, 0x06, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0x90, 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFB,
+ 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00, 0x01, 0x18,
+ 0x01, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFA,
+ 0x01, 0x40, 0x03, 0x00, 0x01, 0x27, 0x01, 0xEF, 0x01, 0xF8, 0x0A, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xCA, 0x01, 0x9A, 0x01, 0xBE, 0x01, 0xFF,
+ 0x01, 0xFC, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x29, 0x01, 0xDF, 0x03, 0xFF,
+ 0x01, 0xFA, 0x01, 0x40, 0x0D, 0x00, 0x01, 0x02, 0x01, 0x46, 0x01, 0x76,
+ 0x01, 0x53, 0xC5, 0x00,
+
+ /* 31 REGISTERED_SIGN */
+ 0xA0, 0x00, 0x01, 0x02, 0x01, 0x46, 0x01, 0x76, 0x01, 0x53, 0x0E, 0x00,
+ 0x01, 0x28, 0x01, 0xDF, 0x03, 0xFF, 0x01, 0xEA, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xCB, 0x01, 0x9A, 0x01, 0xCE, 0x01, 0xFF,
+ 0x01, 0xFC, 0x01, 0x30, 0x09, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFA,
+ 0x01, 0x40, 0x03, 0x00, 0x01, 0x38, 0x01, 0xFF, 0x01, 0xF8, 0x09, 0x00,
+ 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00, 0x01, 0x18, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0x90, 0x07, 0x00,
+ 0x01, 0x4F, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x3F, 0x01, 0xF7, 0x01, 0x00,
+ 0x01, 0x13, 0x02, 0x33, 0x01, 0x32, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0x80, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x7F,
+ 0x03, 0xFF, 0x01, 0xFD, 0x01, 0x81, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xF5,
+ 0x05, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x01, 0xDD, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x30, 0x01, 0x00,
+ 0x01, 0x08, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xF4, 0x02, 0x00,
+ 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x3C, 0x01, 0xFF, 0x01, 0xD0,
+ 0x02, 0x00, 0x01, 0xEF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xC0,
+ 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF3, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xB0, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x60, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x03, 0x00, 0x01, 0xFF,
+ 0x01, 0xF4, 0x02, 0x00, 0x01, 0x1F, 0x01, 0xF0, 0x04, 0x00, 0x01, 0xFF,
+ 0x01, 0x10, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x03, 0x00, 0x01, 0xFF,
+ 0x01, 0xF2, 0x02, 0x00, 0x01, 0x0C, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0xFE, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x02, 0x00, 0x01, 0x0A, 0x01, 0xF6, 0x03, 0x00,
+ 0x01, 0x03, 0x01, 0xFD, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFD, 0x01, 0x88,
+ 0x01, 0x9A, 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x30, 0x02, 0x00, 0x01, 0x08,
+ 0x01, 0xF8, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x7F,
+ 0x03, 0xFF, 0x01, 0xFE, 0x01, 0x91, 0x03, 0x00, 0x01, 0x07, 0x01, 0xF9,
+ 0x03, 0x00, 0x01, 0x03, 0x01, 0xFD, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFC,
+ 0x01, 0x78, 0x01, 0xDF, 0x01, 0xFD, 0x01, 0x20, 0x03, 0x00, 0x01, 0x08,
+ 0x01, 0xF8, 0x03, 0x00, 0x01, 0x01, 0x01, 0xFE, 0x03, 0x00, 0x01, 0x7F,
+ 0x01, 0xFA, 0x01, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xF6, 0x04, 0x00, 0x01, 0xFF, 0x01, 0x10, 0x02, 0x00,
+ 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xF8, 0x03, 0x00,
+ 0x01, 0x0C, 0x01, 0xF5, 0x04, 0x00, 0x01, 0xBF, 0x01, 0x60, 0x02, 0x00,
+ 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x30,
+ 0x02, 0x00, 0x01, 0x1F, 0x01, 0xF1, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xC0,
+ 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xD0, 0x02, 0x00, 0x01, 0x6F, 0x01, 0xB0, 0x04, 0x00, 0x01, 0x1F,
+ 0x01, 0xF4, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x01,
+ 0x01, 0xEF, 0x01, 0xF7, 0x02, 0x00, 0x01, 0xEF, 0x01, 0x60, 0x04, 0x00,
+ 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x03, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x08, 0x01, 0xFE, 0x06, 0x00,
+ 0x01, 0xEF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x5A, 0x01, 0xA6, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xAA, 0x01, 0x60, 0x01, 0x4F, 0x01, 0xF4, 0x06, 0x00,
+ 0x01, 0x3F, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0x80,
+ 0x06, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0x90, 0x07, 0x00, 0x01, 0x4F,
+ 0x01, 0xFB, 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00,
+ 0x01, 0x19, 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x04, 0x01, 0xEF,
+ 0x01, 0xFA, 0x01, 0x40, 0x03, 0x00, 0x01, 0x38, 0x01, 0xEF, 0x01, 0xF8,
+ 0x0A, 0x00, 0x01, 0x19, 0x02, 0xFF, 0x01, 0xCB, 0x01, 0x9A, 0x01, 0xCE,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x28, 0x01, 0xDF,
+ 0x03, 0xFF, 0x01, 0xEA, 0x01, 0x40, 0x0D, 0x00, 0x01, 0x02, 0x01, 0x45,
+ 0x01, 0x76, 0x01, 0x43, 0xC5, 0x00,
+#endif // TOUCH_UI_UTF8_COPYRIGHT
+
+#if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ /* 32 PLUS_MINUS_SIGN */
+ 0xEB, 0x00, 0x01, 0x02, 0x01, 0x77, 0x01, 0x70, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x0B, 0x00, 0x01, 0x6A, 0x04, 0xAA, 0x01, 0xAC,
+ 0x01, 0xFF, 0x01, 0xFA, 0x05, 0xAA, 0x01, 0x20, 0x05, 0x00, 0x01, 0x9F,
+ 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40,
+ 0x05, 0x00, 0x01, 0x7C, 0x04, 0xCC, 0x01, 0xCD, 0x01, 0xFF, 0x01, 0xFC,
+ 0x05, 0xCC, 0x01, 0x30, 0x0A, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x03, 0x01, 0x99, 0x01, 0x90, 0x44, 0x00, 0x01, 0x9F,
+ 0x0C, 0xFF, 0x01, 0x30, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40,
+ 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x47,
+ 0x0C, 0x77, 0x01, 0x10, 0xC1, 0x00,
+
+ /* 33 MULTIPLICATION_SIGN */
+ 0xFF, 0x00, 0x0E, 0x00, 0x01, 0x09, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x03,
+ 0x01, 0xE4, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0x40, 0x06, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x05, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x03, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x09, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB, 0x03, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0A, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x01, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x0B, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB3, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x0D, 0x00, 0x01, 0x3E,
+ 0x03, 0xFF, 0x01, 0xFB, 0x0E, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x02, 0xFF,
+ 0x01, 0xB0, 0x0F, 0x00, 0x01, 0x5F, 0x02, 0xFF, 0x01, 0x10, 0x0E, 0x00,
+ 0x01, 0x03, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xB0, 0x0E, 0x00, 0x01, 0x3E,
+ 0x03, 0xFF, 0x01, 0xFB, 0x0D, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB3, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0B, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x0A, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x03, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB,
+ 0x09, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB,
+ 0x07, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x07, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00,
+ 0x01, 0x09, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x02, 0x01, 0xE4, 0xE9, 0x00,
+
+ /* 34 DIVISION_SIGN */
+ 0xFF, 0x00, 0x25, 0x00, 0x01, 0x17, 0x01, 0x77, 0x01, 0x76, 0x10, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x17, 0x01, 0x77,
+ 0x01, 0x76, 0x31, 0x00, 0x01, 0x24, 0x0C, 0x44, 0x01, 0x10, 0x05, 0x00,
+ 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF,
+ 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00,
+ 0x01, 0x12, 0x0C, 0x22, 0x31, 0x00, 0x01, 0x18, 0x01, 0x88, 0x01, 0x87,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x16,
+ 0x01, 0x66, 0x01, 0x65, 0xFF, 0x00, 0x01, 0x00,
+#endif // TOUCH_UI_UTF8_MATHEMATICS
+
+#if ENABLED(TOUCH_UI_UTF8_FRACTIONS)
+ /* 35 FRACTION_QUARTER */
+ 0x92, 0x00, 0x01, 0x01, 0x01, 0x44, 0x01, 0x40, 0x04, 0x00, 0x01, 0x04,
+ 0x01, 0x79, 0x01, 0xCE, 0x01, 0xEE, 0x01, 0x20, 0x07, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x3F, 0x03, 0xFF, 0x01, 0x20,
+ 0x07, 0x00, 0x01, 0x3F, 0x01, 0xFE, 0x01, 0x10, 0x04, 0x00, 0x01, 0x3F,
+ 0x01, 0xDB, 0x01, 0x8D, 0x01, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0xDF,
+ 0x01, 0xF5, 0x05, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x06, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x20, 0x07, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00,
+ 0x01, 0xAF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE1, 0x08, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x7F,
+ 0x01, 0xFC, 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF2, 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFE,
+ 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0xDF,
+ 0x01, 0xF5, 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xB0, 0x04, 0x00, 0x01, 0x37, 0x01, 0x77,
+ 0x02, 0x00, 0x01, 0x04, 0x01, 0x55, 0x01, 0x5D, 0x01, 0xFF, 0x01, 0x75,
+ 0x01, 0x55, 0x01, 0x10, 0x01, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x20,
+ 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x02, 0x00, 0x01, 0x0D,
+ 0x05, 0xFF, 0x01, 0x40, 0x01, 0x00, 0x01, 0xAF, 0x01, 0xF8, 0x04, 0x00,
+ 0x01, 0x0C, 0x02, 0xFF, 0x02, 0x00, 0x01, 0x0C, 0x05, 0xEE, 0x01, 0x40,
+ 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0, 0x04, 0x00, 0x01, 0x8F, 0x01, 0xBE,
+ 0x01, 0xFF, 0x09, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50, 0x03, 0x00,
+ 0x01, 0x04, 0x01, 0xFE, 0x01, 0x1E, 0x01, 0xFF, 0x09, 0x00, 0x01, 0x7F,
+ 0x01, 0xFC, 0x04, 0x00, 0x01, 0x1E, 0x01, 0xF4, 0x01, 0x0E, 0x01, 0xFF,
+ 0x08, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x80, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x80, 0x03, 0x00, 0x01, 0x08, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x04, 0x00, 0x01, 0x4F,
+ 0x01, 0xE1, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0xDF,
+ 0x01, 0xF5, 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x0E, 0x01, 0xFF, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xB0,
+ 0x03, 0x00, 0x01, 0x0B, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x07, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x3F,
+ 0x01, 0xF8, 0x02, 0x88, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x88, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x4F, 0x06, 0xFF, 0x05, 0x00,
+ 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0, 0x04, 0x00, 0x01, 0x2A, 0x03, 0xAA,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xAA, 0x05, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0x50, 0x08, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x06, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF2, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x05, 0x01, 0x66,
+ 0xBF, 0x00,
+
+ /* 36 FRACTION_HALF */
+ 0x92, 0x00, 0x01, 0x01, 0x01, 0x44, 0x01, 0x40, 0x04, 0x00, 0x01, 0x04,
+ 0x01, 0x7A, 0x01, 0xCE, 0x01, 0xEE, 0x01, 0x20, 0x07, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00, 0x01, 0x3F, 0x03, 0xFF, 0x01, 0x20,
+ 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x3F, 0x01, 0xDA,
+ 0x01, 0x7D, 0x01, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0xDF, 0x01, 0xF5,
+ 0x07, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x06, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00, 0x01, 0xAF, 0x01, 0xF8, 0x08, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x04, 0x01, 0xFF,
+ 0x01, 0xE0, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x05, 0x00, 0x01, 0x7F, 0x01, 0xFC, 0x09, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF2,
+ 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xF5, 0x0A, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xB0,
+ 0x01, 0x00, 0x01, 0x04, 0x01, 0x8A, 0x01, 0xCC, 0x01, 0xA7, 0x01, 0x10,
+ 0x02, 0x00, 0x01, 0x04, 0x01, 0x55, 0x01, 0x5D, 0x01, 0xFF, 0x01, 0x75,
+ 0x01, 0x55, 0x01, 0x10, 0x01, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20,
+ 0x01, 0x06, 0x04, 0xFF, 0x01, 0xF7, 0x02, 0x00, 0x01, 0x0D, 0x05, 0xFF,
+ 0x01, 0x40, 0x01, 0x00, 0x01, 0xBF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xA7, 0x01, 0x68, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x70,
+ 0x01, 0x00, 0x01, 0x0B, 0x05, 0xDD, 0x01, 0x40, 0x01, 0x04, 0x01, 0xFF,
+ 0x01, 0xE0, 0x01, 0x00, 0x01, 0x05, 0x01, 0x60, 0x02, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0xEF, 0x01, 0xF4, 0x08, 0x00, 0x01, 0x7F, 0x01, 0xFB,
+ 0x07, 0x00, 0x01, 0xCF, 0x01, 0xF3, 0x07, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF2, 0x06, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xE0, 0x07, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x80, 0x06, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0x50, 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x07, 0x00, 0x01, 0xAF,
+ 0x01, 0xFA, 0x08, 0x00, 0x01, 0xDF, 0x01, 0xF5, 0x06, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xB0,
+ 0x06, 0x00, 0x01, 0x8F, 0x01, 0xFD, 0x01, 0x10, 0x07, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xC1,
+ 0x08, 0x00, 0x01, 0xBF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xAF, 0x01, 0xFB,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50,
+ 0x04, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xF9, 0x09, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x05, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFE, 0x03, 0xEE,
+ 0x01, 0xE6, 0x04, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF2, 0x05, 0x00,
+ 0x01, 0x0A, 0x05, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xEE,
+ 0x01, 0x70, 0x05, 0x00, 0x01, 0x04, 0x05, 0x66, 0x01, 0x62, 0xBE, 0x00,
+
+ /* 37 FRACTION_THREE_FOURTHS */
+ 0x87, 0x00, 0x01, 0x02, 0x01, 0x34, 0x01, 0x42, 0x08, 0x00, 0x01, 0x01,
+ 0x01, 0x55, 0x01, 0x50, 0x04, 0x00, 0x01, 0x4C, 0x03, 0xFF, 0x01, 0xE9,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xFE, 0x02, 0xFF, 0x01, 0xE2, 0x06, 0x00,
+ 0x01, 0x4F, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x47, 0x01, 0x30, 0x01, 0x00,
+ 0x01, 0x05, 0x01, 0xEF, 0x01, 0xFB, 0x06, 0x00, 0x01, 0xDF, 0x01, 0xF5,
+ 0x09, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xB0, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x20, 0x09, 0x00, 0x01, 0x6F, 0x01, 0xFB, 0x05, 0x00,
+ 0x01, 0xBF, 0x01, 0xF8, 0x07, 0x00, 0x01, 0x03, 0x01, 0x44, 0x01, 0x5A,
+ 0x01, 0xFF, 0x01, 0xD1, 0x04, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0,
+ 0x07, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xE7, 0x05, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x0B, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x70, 0x04, 0x00, 0x01, 0x7F, 0x01, 0xFB, 0x0A, 0x00,
+ 0x01, 0x16, 0x01, 0xDF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0x20, 0x02, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x80, 0x0B, 0x00, 0x01, 0x0A, 0x01, 0xFF,
+ 0x01, 0x60, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x0C, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xF5, 0x0C, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x30, 0x01, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xB0, 0x04, 0x00, 0x01, 0x47, 0x01, 0x77, 0x02, 0x00, 0x01, 0xD7,
+ 0x01, 0x42, 0x01, 0x01, 0x01, 0x38, 0x01, 0xEF, 0x01, 0xFC, 0x02, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x02, 0x00, 0x05, 0xFF, 0x01, 0xC1, 0x02, 0x00, 0x01, 0xBF, 0x01, 0xF8,
+ 0x04, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x02, 0x00, 0x01, 0x7B, 0x01, 0xEF,
+ 0x02, 0xFF, 0x01, 0xB6, 0x02, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x9F, 0x01, 0xBE, 0x01, 0xFF, 0x04, 0x00, 0x01, 0x22,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50, 0x03, 0x00,
+ 0x01, 0x04, 0x01, 0xFE, 0x01, 0x1E, 0x01, 0xFF, 0x09, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x04, 0x00, 0x01, 0x1E, 0x01, 0xF3, 0x01, 0x0E, 0x01, 0xFF,
+ 0x08, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xCF,
+ 0x01, 0x70, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x80, 0x03, 0x00, 0x01, 0x08, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x08, 0x00, 0x01, 0x5F, 0x01, 0xFE, 0x04, 0x00, 0x01, 0x4F,
+ 0x01, 0xE1, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0xDF,
+ 0x01, 0xF4, 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x0E, 0x01, 0xFF, 0x07, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xB0,
+ 0x03, 0x00, 0x01, 0x0B, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x07, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x3F,
+ 0x01, 0xF9, 0x02, 0x99, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x99, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x4F, 0x06, 0xFF, 0x05, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xD0, 0x04, 0x00, 0x01, 0x29, 0x03, 0x99,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x99, 0x05, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0x40, 0x08, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x06, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF2, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00,
+ 0x01, 0x0A, 0x01, 0xEE, 0x01, 0x70, 0x09, 0x00, 0x01, 0x04, 0x01, 0x55,
+ 0xBF, 0x00,
+#endif // TOUCH_UI_UTF8_FRACTIONS
+
+#if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ /* 38 MICRON_SIGN */
+ 0xFF, 0x00, 0x1F, 0x00, 0x01, 0x02, 0x01, 0x44, 0x01, 0x40, 0x05, 0x00,
+ 0x01, 0x14, 0x01, 0x44, 0x01, 0x10, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF4, 0x05, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF6, 0x05, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x07, 0x02, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x02, 0xFF,
+ 0x01, 0xD2, 0x03, 0x00, 0x01, 0x6F, 0x02, 0xFF, 0x01, 0xA0, 0x08, 0x00,
+ 0x01, 0x07, 0x03, 0xFF, 0x01, 0xA6, 0x01, 0x55, 0x01, 0x8D, 0x03, 0xFF,
+ 0x01, 0xF9, 0x01, 0xA4, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7,
+ 0x05, 0xFF, 0x01, 0x5D, 0x02, 0xFF, 0x01, 0xF4, 0x07, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x5F, 0x03, 0xFF, 0x01, 0xF5, 0x01, 0x06,
+ 0x02, 0xFF, 0x01, 0xF4, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3,
+ 0x01, 0x01, 0x01, 0x7C, 0x01, 0xDD, 0x01, 0xC7, 0x01, 0x10, 0x01, 0x00,
+ 0x01, 0x6C, 0x01, 0xDB, 0x01, 0x50, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xEE, 0x01, 0xE3, 0x35, 0x00,
+
+ /* 39 PILCROW_SIGN */
+ 0x9C, 0x00, 0x01, 0x16, 0x01, 0x9B, 0x04, 0xCC, 0x01, 0xCA, 0x0B, 0x00,
+ 0x01, 0x19, 0x06, 0xFF, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xEF,
+ 0x03, 0xFF, 0x01, 0xFB, 0x01, 0xAA, 0x01, 0xAF, 0x01, 0xFD, 0x0A, 0x00,
+ 0x01, 0x2E, 0x04, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD,
+ 0x0A, 0x00, 0x01, 0xBF, 0x04, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F,
+ 0x01, 0xFD, 0x09, 0x00, 0x01, 0x03, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x08, 0x05, 0xFF, 0x01, 0xF2,
+ 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x0B, 0x05, 0xFF,
+ 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x0C,
+ 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00,
+ 0x01, 0x0B, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD,
+ 0x09, 0x00, 0x01, 0x0A, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F,
+ 0x01, 0xFD, 0x09, 0x00, 0x01, 0x06, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0xEF, 0x04, 0xFF, 0x01, 0xF2,
+ 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x6F, 0x04, 0xFF,
+ 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x08,
+ 0x04, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x0B, 0x00,
+ 0x01, 0x5E, 0x03, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD,
+ 0x0C, 0x00, 0x01, 0x6B, 0x02, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F,
+ 0x01, 0xFD, 0x0D, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0x34, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x04, 0x01, 0x43, 0x7A, 0x00,
+
+ /* 40 BROKEN_BAR */
+ 0xAD, 0x00, 0x01, 0x07, 0x01, 0x99, 0x01, 0x60, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x08, 0x01, 0xBB, 0x01, 0x70, 0x6F, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x04,
+ 0x01, 0x55, 0x01, 0x30, 0x47, 0x00,
+
+ /* 41 SECTION_SIGN */
+ 0x89, 0x00, 0x01, 0x35, 0x01, 0x64, 0x01, 0x31, 0x0E, 0x00, 0x01, 0x01,
+ 0x01, 0x9E, 0x03, 0xFF, 0x01, 0xD9, 0x01, 0x30, 0x0C, 0x00, 0x01, 0x2E,
+ 0x05, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFB,
+ 0x01, 0x98, 0x01, 0xAE, 0x01, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x02, 0x00, 0x01, 0x39, 0x01, 0xA0,
+ 0x0B, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x10, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xE4, 0x10, 0x00, 0x01, 0x1D, 0x02, 0xFF,
+ 0x01, 0xA1, 0x0F, 0x00, 0x01, 0x4E, 0x03, 0xFF, 0x01, 0x70, 0x0D, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x30, 0x0C, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x60, 0x01, 0x07,
+ 0x02, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0xBF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xC0, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xF3,
+ 0x03, 0x00, 0x01, 0x4E, 0x01, 0xFF, 0x01, 0xFB, 0x0A, 0x00, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x40, 0x09, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x90, 0x0A, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x20, 0x03, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xB0, 0x0A, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0A, 0x00, 0x01, 0x0A, 0x02, 0xFF, 0x01, 0x91, 0x02, 0x00,
+ 0x01, 0x0C, 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x01, 0x8F, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x60, 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x10,
+ 0x0B, 0x00, 0x01, 0x03, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x46,
+ 0x01, 0xFF, 0x01, 0xF5, 0x0D, 0x00, 0x01, 0x07, 0x04, 0xFF, 0x01, 0x50,
+ 0x0E, 0x00, 0x01, 0x2A, 0x02, 0xFF, 0x01, 0xF5, 0x10, 0x00, 0x01, 0x4E,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x0F, 0x00, 0x01, 0x01, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0xC0, 0x10, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0xF3,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF3, 0x0B, 0x00, 0x01, 0x08, 0x01, 0xE8, 0x01, 0x20,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xE0, 0x0B, 0x00,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0xCB, 0x01, 0xDF, 0x02, 0xFF,
+ 0x01, 0x40, 0x0B, 0x00, 0x01, 0x08, 0x05, 0xFF, 0x01, 0xF5, 0x0D, 0x00,
+ 0x01, 0x49, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xE8, 0x01, 0x20, 0x0F, 0x00,
+ 0x01, 0x12, 0x01, 0x21, 0x7F, 0x00,
+
+ /* 42 NOT_SIGN */
+ 0xFF, 0x00, 0x7F, 0x00, 0x01, 0x12, 0x0C, 0x22, 0x06, 0x00, 0x01, 0x9F,
+ 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40,
+ 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x24,
+ 0x0A, 0x44, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x17, 0x01, 0x77, 0x01, 0x10,
+ 0xFF, 0x00, 0x34, 0x00
+#endif // TOUCH_UI_UTF8_SYMBOLS
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/bitmap2cpp.py b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/bitmap2cpp.py
new file mode 100644
index 0000000..0c4499e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/bitmap2cpp.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+
+# 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: <https://www.gnu.org/licenses/>.
+
+from __future__ import print_function
+from PIL import Image
+import argparse
+import textwrap
+
+def pack_rle(data):
+ """Use run-length encoding to pack the bytes"""
+ rle = []
+ value = data[0]
+ count = 0
+ for i in data:
+ if i != value or count == 255:
+ rle.append(count)
+ rle.append(value)
+ value = i
+ count = 1
+ else:
+ count += 1
+ rle.append(count)
+ rle.append(value)
+ return rle
+
+class WriteSource:
+ def __init__(self, lines_in_blocks):
+ self.blocks = []
+ self.values = []
+ self.block_size = lines_in_blocks
+ self.rows = 0
+
+ def add_pixel(self, value):
+ self.values.append(value)
+
+ def convert_to_4bpp(self, data, chunk_size = 0):
+ # Invert the image
+ data = list(map(lambda i: 255 - i, data))
+ # Quanitize 8-bit values into 4-bits
+ data = list(map(lambda i: i >> 4, data))
+ # Make sure there is an even number of elements
+ if (len(data) & 1) == 1:
+ data.append(0)
+ # Combine each two adjacent values into one
+ i = iter(data)
+ data = list(map(lambda a, b: a << 4 | b, i ,i))
+ # Pack the data
+ data = pack_rle(data)
+ # Convert values into hex strings
+ return list(map(lambda a: "0x" + format(a, '02x'), data))
+
+ def end_row(self, y):
+ # Pad each row into even number of values
+ if len(self.values) & 1:
+ self.values.append(0)
+
+ self.rows += 1
+ if self.block_size and (self.rows % self.block_size) == 0:
+ self.blocks.append(self.values)
+ self.values = []
+
+ def write(self):
+ if len(self.values):
+ self.blocks.append(self.values)
+
+ block_strs = [];
+ for b in self.blocks:
+ data = self.convert_to_4bpp(b)
+ data = ', '.join(data)
+ data = textwrap.fill(data, 75, initial_indent = ' ', subsequent_indent = ' ')
+ block_strs.append(data)
+
+ print("const unsigned char font[] PROGMEM = {")
+ for i, b in enumerate(block_strs):
+ if i:
+ print(',')
+ print('\n /* {} */'.format(i))
+ print(b, end='')
+ print("\n};")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Converts a grayscale bitmap into a 16-level RLE packed C array for use as font data')
+ parser.add_argument("input")
+ parser.add_argument('--char_height', help='Adds a separator every so many lines', type=int)
+ args = parser.parse_args()
+
+ writer = WriteSource(args.char_height)
+
+ img = Image.open(args.input).convert('L')
+ for y in range(img.height):
+ for x in range(img.width):
+ writer.add_pixel(img.getpixel((x,y)))
+ writer.end_row(y)
+ writer.write()
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/circular_progress.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/circular_progress.h
new file mode 100644
index 0000000..6695134
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/circular_progress.h
@@ -0,0 +1,105 @@
+/***********************
+ * circular_progress.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/* This function draws a circular progress "ring" */
+
+void draw_circular_progress(CommandProcessor& cmd, int x, int y, int w, int h, float percent, char *text, uint32_t bgcolor, uint32_t fgcolor) {
+ using namespace FTDI;
+
+ const float rim = 0.3;
+ const float a = percent/100.0*2.0*PI;
+ const float a1 = min(PI/2, a);
+ const float a2 = min(PI/2, a-a1);
+ const float a3 = min(PI/2, a-a1-a2);
+ const float a4 = min(PI/2, a-a1-a2-a3);
+
+ const int ro = min(w,h) * 8;
+ const int rr = ro * rim;
+ const int cx = x * 16 + w * 8;
+ const int cy = y * 16 + h * 8;
+
+ // Load a rim shape into stencil buffer
+ 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));
+ cmd.cmd(BEGIN(POINTS));
+ cmd.cmd(POINT_SIZE(ro));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(POINT_SIZE(ro - rr));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(RESTORE_CONTEXT());
+
+ // Mask further drawing by stencil buffer
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(STENCIL_FUNC(STENCIL_FUNC_NOTEQUAL, 0, 255));
+
+ // Fill the background
+ cmd.cmd(COLOR_RGB(bgcolor));
+ cmd.cmd(BEGIN(POINTS));
+ cmd.cmd(POINT_SIZE(ro));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(COLOR_RGB(fgcolor));
+
+ // Paint upper-right quadrant
+ cmd.cmd(BEGIN(EDGE_STRIP_A));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx + ro*sin(a1) + 16,cy - ro*cos(a1) + 8));
+
+ // Paint lower-right quadrant
+ if (a > PI/2) {
+ cmd.cmd(BEGIN(EDGE_STRIP_R));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx + ro*cos(a2),cy + ro*sin(a2) + 16));
+ }
+
+ // Paint lower-left quadrant
+ if (a > PI) {
+ cmd.cmd(BEGIN(EDGE_STRIP_B));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx - ro*sin(a3) - 8,cy + ro*cos(a3)));
+ }
+
+ // Paint upper-left quadrant
+ if (a > 1.5*PI) {
+ cmd.cmd(BEGIN(EDGE_STRIP_L));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx - ro*cos(a4),cy - ro*sin(a4)));
+ }
+ cmd.cmd(RESTORE_CONTEXT());
+
+ // Draw the text
+
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(COLOR_RGB(fgcolor));
+ cmd.text(x,y,w,h,text, OPT_CENTERX | OPT_CENTERY);
+ cmd.cmd(RESTORE_CONTEXT());
+}
+
+void draw_circular_progress(CommandProcessor& cmd, int x, int y, int w, int h, float percent, uint32_t bgcolor, uint32_t fgcolor) {
+ char str[5];
+ sprintf(str,"%d\%%",int(percent));
+ draw_circular_progress(cmd, x, y, w, h, percent, str, bgcolor, fgcolor);
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/poly_ui.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/poly_ui.h
new file mode 100644
index 0000000..ba41650
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/poly_ui.h
@@ -0,0 +1,408 @@
+/*************
+ * poly_ui.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * The PolyReader class iterates over an array of (x,y) pairs.
+ * For supporting polygons with holes an end-of-loop marker may
+ * be embedded into the data stream:
+ *
+ * const PROGMEM uint16_t data[] = {
+ * x, y, x, y, ..., eol,
+ * ...
+ * x, y, x, y, ..., eol
+ * }
+ *
+ * The PolyReader object can be used to iterate over the points.
+ *
+ * PolyReader r(data, N_ELEMENTS(data));
+ *
+ * for (r.start();r.has_more(); r.next()) {
+ * uint16_t x = r.x;
+ * uint16_t y = r.y;
+ *
+ * // Do something with the point
+ * ...
+ *
+ * // Do something else if this point
+ * // closes a loop.
+ * if (r.end_of_loop()) {
+ * ...
+ * }
+ * }
+ */
+
+class PolyReader {
+ public:
+ typedef uint16_t type_t;
+
+ private:
+ static constexpr type_t eol = 0xFFFF;
+
+ const type_t *p, *top, *end;
+ type_t start_x, start_y;
+
+ void close_loop() {
+ x = start_x;
+ y = start_y;
+ start_x = eol;
+ start_y = eol;
+ }
+
+ public:
+ type_t x, y;
+
+ // Begin reading a polygon data structure
+ PolyReader(const uint16_t data[], const size_t n_elements) : top(data), end(data + n_elements) {
+ start();
+ }
+
+ void start() {
+ p = top;
+ start_x = eol;
+ next();
+ }
+
+ // Reads the next point in the polygon data structure
+ void next() {
+ if (!p) return;
+
+ if (p == end) {
+ if (start_x != eol)
+ close_loop();
+ else
+ p = nullptr;
+ }
+ else {
+ x = pgm_read_word_far(p++);
+ if (x == eol)
+ close_loop();
+ else {
+ y = pgm_read_word_far(p++);
+ if (start_x == eol) {
+ start_x = x;
+ start_y = y;
+ }
+ }
+ }
+ }
+
+ bool has_more() { return p != nullptr; }
+ bool end_of_loop() { return start_x == eol; }
+};
+
+/**
+ * The TransformedPolyReader class works like the PolyReader,
+ * but the (x,y) input is assumed to be normalized onto a
+ * unit square and then mapped to the full 16-bits, i.e.
+ * (0.0,1.0) => (0x0000,0xFFFE). This class will scale the
+ * data to fit the entire display, a bounding box, or apply
+ * some arbitrary affine transform.
+ *
+ * This class is suitable for reading data from "svg2cpp.py"
+ */
+class TransformedPolyReader : public PolyReader {
+ private:
+ /**
+ * Fixed point type for fast transformations, supports
+ * values from 0 to 1024, with 1/32 precision.
+ */
+ static constexpr uint8_t fract_bits = 5;
+ typedef int16_t fix_t;
+ fix_t makefix(float f) { return f * (1 << fract_bits); }
+
+ // First two rows of 3x3 transformation matrix
+ fix_t a, b, c;
+ fix_t d, e, f;
+
+ void transform() {
+ /**
+ * Values from PolyReader vary from 0 to FFFE.
+ * As an approximation to dividing by FFFE,
+ * we perform a bit shift right by 16.
+ */
+ const int32_t px = PolyReader::x;
+ const int32_t py = PolyReader::y;
+ const int32_t round = 1 << (fract_bits-1);
+ x = (((((a * px) + (b * py)) >> 16) + c) + round) >> fract_bits;
+ y = (((((d * px) + (e * py)) >> 16) + f) + round) >> fract_bits;
+ }
+
+ void set_transform(
+ fix_t A, fix_t B, fix_t C,
+ fix_t D, fix_t E, fix_t F
+ ) {
+ a = A; b = B; c = C;
+ d = D; e = E; f = F;
+ }
+
+ public:
+ typedef int16_t type_t;
+
+ type_t x, y;
+
+ TransformedPolyReader(const uint16_t data[], const size_t n) : PolyReader(data, n) {
+ scale_to_fit();
+ transform();
+ }
+
+ // Set an arbitrary affine transform
+ void set_transform(
+ float A, float B, float C,
+ float D, float E, float F
+ ) {
+ set_transform(
+ makefix(A), makefix(B), makefix(C),
+ makefix(D), makefix(E), makefix(F)
+ );
+ }
+
+ // Scale the data to fit a specified bounding box
+ void scale_to_fit(type_t x_min, type_t y_min, type_t x_max, type_t y_max) {
+ fix_t sx = makefix(x_max - x_min);
+ fix_t sy = makefix(y_max - y_min);
+ fix_t tx = makefix(x_min);
+ fix_t ty = makefix(y_min);
+ set_transform(
+ sx, 0, tx,
+ 0, sy, ty
+ );
+ }
+
+ // Scale to fit the entire display (default)
+ void scale_to_fit() {
+ scale_to_fit(0, 0, FTDI::display_width, FTDI::display_height);
+ }
+
+ void next() {
+ PolyReader::next();
+ transform();
+ }
+};
+
+/**
+ * The DeduplicatedPolyReader wraps around another PolyReader
+ * class to remove repeated points from the data. This could
+ * happen when scaling down using TransformedPolyReader, for
+ * example.
+ */
+template<class POLY_READER>
+class DeduplicatedPolyReader : public POLY_READER {
+ private:
+ typename POLY_READER::type_t last_x, last_y;
+
+ static constexpr typename POLY_READER::type_t eol = 0xFFFF;
+
+ public:
+ DeduplicatedPolyReader(const uint16_t data[], const size_t n) : POLY_READER(data, n) {
+ last_x = POLY_READER::x;
+ last_y = POLY_READER::y;
+ }
+
+ void next() {
+ do {
+ if (!POLY_READER::has_more()) return;
+ POLY_READER::next();
+ } while (POLY_READER::x == last_x && POLY_READER::y == last_y && !POLY_READER::end_of_loop());
+ if (POLY_READER::end_of_loop()) {
+ last_x = last_y = eol;
+ }
+ else {
+ last_x = POLY_READER::x;
+ last_y = POLY_READER::y;
+ }
+ }
+};
+
+/**
+ * The helper class allows you to build an interface based on arbitrary
+ * shapes.
+ */
+template<class POLY_READER=DeduplicatedPolyReader<TransformedPolyReader>>
+class GenericPolyUI {
+ private:
+ CommandProcessor &cmd;
+
+ // Attributes used to paint buttons
+
+ uint32_t btn_fill_color = 0x000000;
+ uint32_t btn_shadow_color = 0xF3E0E0;
+ uint8_t btn_shadow_depth = 5;
+ uint32_t btn_stroke_color = 0x000000;
+ uint8_t btn_stroke_width = 28;
+
+ draw_mode_t mode;
+
+ public:
+ enum ButtonStyle : uint8_t {
+ FILL = 1,
+ STROKE = 2,
+ SHADOW = 4,
+ REGULAR = 7
+ };
+
+ typedef POLY_READER poly_reader_t;
+
+ GenericPolyUI(CommandProcessor &c, draw_mode_t what = BOTH) : cmd(c), mode(what) {}
+
+ // Fills a polygon with the current COLOR_RGB
+ void fill(poly_reader_t r, bool clip = true) {
+ using namespace FTDI;
+ int16_t x, y, w, h;
+
+ if (clip) {
+ // Clipping reduces the number of pixels that are
+ // filled, allowing more complex shapes to be drawn
+ // in the alloted time.
+ bounds(r, x, y, w, h);
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(SCISSOR_XY(x, y));
+ cmd.cmd(SCISSOR_SIZE(w, h));
+ }
+
+ Polygon p(cmd);
+ p.begin_fill();
+ p.begin_loop();
+ for (r.start();r.has_more();r.next()) {
+ p(r.x * 16, r.y * 16);
+ if (r.end_of_loop()) {
+ p.end_loop();
+ p.begin_loop();
+ }
+ }
+ p.end_loop();
+ p.end_fill();
+ if (clip)
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+
+ void shadow(poly_reader_t r, uint8_t offset) {
+ #if FTDI_API_LEVEL >= 810
+ using namespace FTDI;
+ cmd.cmd(VERTEX_TRANSLATE_X(offset * 16));
+ cmd.cmd(VERTEX_TRANSLATE_Y(offset * 16));
+ fill(r, false);
+ cmd.cmd(VERTEX_TRANSLATE_X(0));
+ cmd.cmd(VERTEX_TRANSLATE_Y(0));
+ #endif
+ }
+
+ // Strokes a polygon with the current COLOR_RGB
+ void stroke(poly_reader_t r) {
+ using namespace FTDI;
+ Polygon p(cmd);
+ p.begin_stroke();
+ p.begin_loop();
+ for (r.start();r.has_more(); r.next()) {
+ p(r.x * 16, r.y * 16);
+ if (r.end_of_loop()) {
+ p.end_loop();
+ p.begin_loop();
+ }
+ }
+ p.end_loop();
+ p.end_stroke();
+ }
+
+ // Compute the bounds of a polygon
+ void bounds(poly_reader_t r, int16_t &x, int16_t &y, int16_t &w, int16_t &h) {
+ int16_t x_min = INT16_MAX;
+ int16_t y_min = INT16_MAX;
+ int16_t x_max = INT16_MIN;
+ int16_t y_max = INT16_MIN;
+ for (r.start(); r.has_more(); r.next()) {
+ x_min = min(x_min, int16_t(r.x));
+ x_max = max(x_max, int16_t(r.x));
+ y_min = min(y_min, int16_t(r.y));
+ y_max = max(y_max, int16_t(r.y));
+ }
+ x = x_min;
+ y = y_min;
+ w = x_max - x_min;
+ h = y_max - y_min;
+ }
+
+ /**
+ * Draw shaped buttons. Buttons are drawn out of a polygon which is
+ * filled and stroked on top of a drop shadow. The button will
+ * become "pushed" when touched.
+ */
+
+ void button_fill(const uint32_t color) {
+ btn_fill_color = color;
+ }
+
+ void button_stroke(const uint32_t color, const uint8_t width) {
+ btn_stroke_color = color;
+ btn_stroke_width = width;
+ }
+
+ void button_shadow(const uint32_t color, const uint8_t depth) {
+ btn_shadow_color = color;
+ btn_shadow_depth = depth;
+ }
+
+ void button(const uint8_t tag, poly_reader_t r, uint8_t style = REGULAR) {
+ using namespace FTDI;
+ // Draw the shadow
+ #if FTDI_API_LEVEL >= 810
+ if (mode & BACKGROUND && style & SHADOW) {
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(TAG(tag));
+ cmd.cmd(VERTEX_TRANSLATE_X(btn_shadow_depth * 16));
+ cmd.cmd(VERTEX_TRANSLATE_Y(btn_shadow_depth * 16));
+ cmd.cmd(COLOR_RGB(btn_shadow_color));
+ fill(r, false);
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+ #endif
+
+ if (mode & FOREGROUND) {
+ cmd.cmd(SAVE_CONTEXT());
+ #if FTDI_API_LEVEL >= 810
+ if (EventLoop::get_pressed_tag() == tag) {
+ // "Push" the button
+ cmd.cmd(VERTEX_TRANSLATE_X(btn_shadow_depth * 16));
+ cmd.cmd(VERTEX_TRANSLATE_Y(btn_shadow_depth * 16));
+ }
+ #endif
+ // Draw the fill and stroke
+ cmd.cmd(TAG(tag));
+ if (style & FILL) {
+ cmd.cmd(COLOR_RGB(btn_fill_color));
+ fill(r, false);
+ }
+ if (style & STROKE) {
+ cmd.cmd(COLOR_RGB(btn_stroke_color));
+ cmd.cmd(LINE_WIDTH(btn_stroke_width));
+ stroke(r);
+ }
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+ }
+
+ void color(const uint32_t color) {
+ cmd.cmd(FTDI::COLOR_RGB(color));
+ }
+};
+
+typedef GenericPolyUI<> PolyUI;
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/svg2cpp.py b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/svg2cpp.py
new file mode 100644
index 0000000..c6eba39
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/svg2cpp.py
@@ -0,0 +1,280 @@
+#!/usr/bin/python
+
+# 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: <https://www.gnu.org/licenses/>.
+
+from __future__ import print_function
+import argparse, re, sys
+
+usage = '''
+This program extracts line segments from a SVG file and writes
+them as coordinates in a C array. The x and y values will be
+scaled from 0x0000 to 0xFFFE. 0xFFFF is used as path separator.
+
+This program can only interpret straight segments, not curves.
+It also cannot handle SVG transform attributes. To convert an
+SVG file into the proper format, use the following procedure:
+
+ - Load SVG file into Inkscape
+ - Convert all Objects to Paths (Path -> Object to Path)
+ - Convert all Strokes to Paths (Path -> Stroke to Path)
+ - Combine all paths into one (Path -> Combine) [1]
+ - Convert all curves into short line segments
+ (Extensions -> Modify Paths -> Flatten Beziers...)
+ - Save as new SVG
+ - Convert into a header file using this utility
+ - To give paths individual names, break apart paths and
+ use the XML Editor to set the "id" attributes.
+
+[1] Combining paths is necessary to remove transforms. You
+could also use inkscape-applytransforms Inkscape extension.
+
+'''
+
+header = '''
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+'''
+
+class ComputeBoundingBox:
+ def reset(self):
+ self.x_min = float(" inf")
+ self.y_min = float(" inf")
+ self.x_max = float("-inf")
+ self.y_max = float("-inf")
+ self.n_points = 0
+ self.n_paths = 0
+
+ def command(self, type, x, y):
+ self.x_min = min(self.x_min, x)
+ self.x_max = max(self.x_max, x)
+ self.y_min = min(self.y_min, y)
+ self.y_max = max(self.y_max, y)
+
+ if type == "M":
+ self.n_paths += 1
+ self.n_points += 1
+
+ def scale(self, x, y):
+ x -= self.x_min
+ y -= self.y_min
+ x /= self.x_max - self.x_min
+ y /= self.y_max - self.y_min
+ #y = 1 - y # Flip upside down
+ return (x, y)
+
+ def path_finished(self, id):
+ pass
+
+ def write(self):
+ print("constexpr float x_min = %f;" % self.x_min)
+ print("constexpr float x_max = %f;" % self.x_max)
+ print("constexpr float y_min = %f;" % self.y_min)
+ print("constexpr float y_max = %f;" % self.y_max)
+ print()
+
+ def from_svg_view_box(self, svg):
+ s = re.search('<svg[^>]+>', svg);
+ if s:
+ m = re.search('viewBox="([0-9-.]+) ([0-9-.]+) ([0-9-.]+) ([0-9-.]+)"', svg)
+ if m:
+ self.x_min = float(m.group(1))
+ self.y_min = float(m.group(2))
+ self.x_max = float(m.group(3))
+ self.y_max = float(m.group(4))
+ return True
+ return False
+
+# op
+class WriteDataStructure:
+ def __init__(self, bounding_box):
+ self.bounds = bounding_box
+
+ def reset(self, ):
+ self.hex_words = []
+
+ def push(self, value):
+ self.hex_words.append("0x%04X" % (0xFFFF & int(value)))
+
+ def command(self, type, x, y):
+ if type == "M":
+ self.push(0xFFFF)
+ x, y = self.bounds.scale(x,y)
+ self.push(x * 0xFFFE)
+ self.push(y * 0xFFFE)
+
+ def path_finished(self, id):
+ if self.hex_words and self.hex_words[0] == "0xFFFF":
+ self.hex_words.pop(0)
+ print("const PROGMEM uint16_t", id + "[] = {" + ", ".join (self.hex_words) + "};")
+ self.hex_words = []
+
+class Parser:
+ def __init__(self, op):
+ self.op = op
+ self.reset()
+
+ def reset(self):
+ self.last_x = 0
+ self.last_y = 0
+ self.initial_x = 0
+ self.initial_y = 0
+
+ def process_svg_path_L_or_M(self, cmd, x, y):
+ self.op.command(cmd, x, y)
+ self.last_x = x
+ self.last_y = y
+ if cmd == "M":
+ self.initial_x = x
+ self.initial_y = y
+
+ def process_svg_path_data_cmd(self, id, cmd, a, b):
+ """Converts the various types of moves into L or M commands
+ and dispatches to process_svg_path_L_or_M for futher processing."""
+ if cmd == "Z" or cmd == "z":
+ self.process_svg_path_L_or_M("L", self.initial_x, self.initial_y)
+ elif cmd == "H":
+ self.process_svg_path_L_or_M("L", a, self.last_y)
+ elif cmd == "V":
+ self.process_svg_path_L_or_M("L", self.last_x, a)
+ elif cmd == "h":
+ self.process_svg_path_L_or_M("L", self.last_x + a, self.last_y)
+ elif cmd == "v":
+ self.process_svg_path_L_or_M("L", self.last_x, self.last_y + a)
+ elif cmd == "L":
+ self.process_svg_path_L_or_M("L", a, b)
+ elif cmd == "l":
+ self.process_svg_path_L_or_M("L", self.last_x + a, self.last_y + b)
+ elif cmd == "M":
+ self.process_svg_path_L_or_M("M", a, b)
+ elif cmd == "m":
+ self.process_svg_path_L_or_M("M", self.last_x + a, self.last_y + b)
+ else:
+ print("Unsupported path data command:", cmd, "in path", id, "\n", file=sys.stderr)
+ quit()
+
+ def eat_token(self, regex):
+ """Looks for a token at the start of self.d.
+ If found, the token is removed."""
+ self.m = re.match(regex,self.d)
+ if self.m:
+ self.d = self.d[self.m.end():]
+ return self.m
+
+ def process_svg_path_data(self, id, d):
+ """Breaks up the "d" attribute into individual commands
+ and calls "process_svg_path_data_cmd" for each"""
+
+ self.d = d
+ while (self.d):
+ if self.eat_token('\s+'):
+ pass # Just eat the spaces
+
+ elif self.eat_token('([LMHVZlmhvz])'):
+ cmd = self.m.group(1)
+ # The following commands take no arguments
+ if cmd == "Z" or cmd == "z":
+ self.process_svg_path_data_cmd(id, cmd, 0, 0)
+
+ elif self.eat_token('([CScsQqTtAa])'):
+ print("Unsupported path data command:", self.m.group(1), "in path", id, "\n", file=sys.stderr)
+ quit()
+
+ elif self.eat_token('([ ,]*[-0-9e.]+)+'):
+ # Process list of coordinates following command
+ coords = re.split('[ ,]+', self.m.group(0))
+ # The following commands take two arguments
+ if cmd == "L" or cmd == "l":
+ while coords:
+ self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), float(coords.pop(0)))
+ elif cmd == "M":
+ while coords:
+ self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), float(coords.pop(0)))
+ # If a MOVETO has multiple points, the subsequent ones are assumed to be LINETO
+ cmd = "L"
+ elif cmd == "m":
+ while coords:
+ self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), float(coords.pop(0)))
+ # If a MOVETO has multiple points, the subsequent ones are assumed to be LINETO
+ cmd = "l"
+ # Assume all other commands are single argument
+ else:
+ while coords:
+ self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), 0)
+ else:
+ print("Syntax error:", d, "in path", id, "\n", file=sys.stderr)
+ quit()
+
+ def process_svg_paths(self, svg):
+ self.op.reset()
+ for path in re.findall('<path[^>]+>', svg):
+ id = "<none>"
+ m = re.search(' id="(.*)"', path)
+ if m:
+ id = m.group(1)
+
+ m = re.search(' transform="(.*)"', path)
+ if m:
+ print("Found transform in path", id, "! Cannot process file!", file=sys.stderr)
+ quit()
+
+ m = re.search(' d="(.*)"', path)
+ if m:
+ self.process_svg_path_data(id, m.group(1))
+ self.op.path_finished(id)
+ self.reset()
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("filename")
+ args = parser.parse_args()
+
+ f = open(args.filename, "r")
+ data = f.read()
+
+ print(header)
+
+ b = ComputeBoundingBox()
+ if not b.from_svg_view_box(data):
+ # Can't find the view box, so use the bounding box of the elements themselves.
+ p = Parser(b)
+ p.process_svg_paths(data)
+ b.write()
+
+ w = WriteDataStructure(b)
+ p = Parser(w)
+ p.process_svg_paths(data)
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h
new file mode 100644
index 0000000..c5ddbb4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h
@@ -0,0 +1,27 @@
+/******************
+ * ftdi_eve_lib.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "compat.h"
+#include "basic/ftdi_basic.h"
+#include "extended/ftdi_extended.h"
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.cpp
new file mode 100644
index 0000000..e4ecdc8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.cpp
@@ -0,0 +1,27 @@
+/****************
+ * language.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+
+#include "../../../../../MarlinCore.h"
+
+#include "language.h"
+
+uint8_t lang = 0;
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.h
new file mode 100644
index 0000000..cbc05c5
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.h
@@ -0,0 +1,23 @@
+/**************
+ * language.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+#pragma once
+
+#include "language_en.h"
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language_en.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language_en.h
new file mode 100644
index 0000000..c898e7b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language_en.h
@@ -0,0 +1,176 @@
+/*****************
+ * language_en.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "language.h"
+
+#if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ #define COPYRIGHT_SIGN u8"©"
+#else
+ #define COPYRIGHT_SIGN u8"(c)"
+#endif
+
+#if ENABLED(TOUCH_UI_UTF8_WESTERN_CHARSET)
+ #define DEGREE_SIGN u8"°"
+#else
+ #define DEGREE_SIGN u8" "
+#endif
+
+namespace Language_en {
+ PROGMEM Language_Str MSG_BUTTON_OKAY = u8"Okay";
+ PROGMEM Language_Str MSG_BUTTON_MENU = u8"Menu";
+ PROGMEM Language_Str MSG_BUTTON_MEDIA = u8"Media";
+ PROGMEM Language_Str MSG_BUTTON_OPEN = u8"Open";
+ PROGMEM Language_Str MSG_CLEAN_NOZZLE = u8"Clean Nozzle";
+ PROGMEM Language_Str MSG_VMAX_X = u8"Vmax X";
+ PROGMEM Language_Str MSG_VMAX_Y = u8"Vmax Y";
+ PROGMEM Language_Str MSG_VMAX_Z = u8"Vmax Z";
+ PROGMEM Language_Str MSG_ACCEL_PRINTING = u8"Printing";
+ PROGMEM Language_Str MSG_ACCEL_TRAVEL = u8"Travel";
+ PROGMEM Language_Str MSG_ACCEL_RETRACT = u8"Retraction";
+ PROGMEM Language_Str MSG_AMAX_X = u8"Amax X";
+ PROGMEM Language_Str MSG_AMAX_Y = u8"Amax Y";
+ PROGMEM Language_Str MSG_AMAX_Z = u8"Amax Z";
+ PROGMEM Language_Str MSG_AXIS_X = u8"X";
+ PROGMEM Language_Str MSG_AXIS_X2 = u8"X2";
+ PROGMEM Language_Str MSG_AXIS_Y = u8"Y";
+ PROGMEM Language_Str MSG_AXIS_Y2 = u8"Y2";
+ PROGMEM Language_Str MSG_AXIS_Z = u8"Z";
+ PROGMEM Language_Str MSG_AXIS_Z2 = u8"Z2";
+ PROGMEM Language_Str MSG_AXIS_E = u8"E";
+ PROGMEM Language_Str MSG_AXIS_E1 = u8"E1";
+ PROGMEM Language_Str MSG_AXIS_E2 = u8"E2";
+ PROGMEM Language_Str MSG_AXIS_E3 = u8"E3";
+ PROGMEM Language_Str MSG_AXIS_E4 = u8"E4";
+ PROGMEM Language_Str MSG_AXIS_ALL = u8"All";
+ PROGMEM Language_Str MSG_HOME = u8"Home";
+ PROGMEM Language_Str MSG_PRINT_STARTING = u8"Print starting";
+ PROGMEM Language_Str MSG_PRINT_FINISHED = u8"Print finished";
+ PROGMEM Language_Str MSG_PRINT_ERROR = u8"Print error";
+ PROGMEM Language_Str MSG_ABOUT_TOUCH_PANEL_1 = u8"Color Touch Panel";
+ PROGMEM Language_Str MSG_ABOUT_TOUCH_PANEL_2 = WEBSITE_URL;
+ PROGMEM Language_Str MSG_LICENSE = u8"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.\n\nTo view a copy of the GNU General "
+ "Public License, go to the following location: https://www.gnu.org/licenses.";
+ PROGMEM Language_Str MSG_RUNOUT_1 = u8"Runout 1";
+ PROGMEM Language_Str MSG_RUNOUT_2 = u8"Runout 2";
+ PROGMEM Language_Str MSG_DISPLAY_MENU = u8"Display";
+ PROGMEM Language_Str MSG_INTERFACE = u8"Interface";
+ PROGMEM Language_Str MSG_MEASURE_AUTOMATICALLY = u8"Measure automatically";
+ PROGMEM Language_Str MSG_H_OFFSET = u8"H Offset";
+ PROGMEM Language_Str MSG_V_OFFSET = u8"V Offset";
+ PROGMEM Language_Str MSG_TOUCH_SCREEN = u8"Touch Screen";
+ PROGMEM Language_Str MSG_CALIBRATE = u8"Calibrate";
+ PROGMEM Language_Str MSG_UNITS_MILLIAMP = u8"mA";
+ PROGMEM Language_Str MSG_UNITS_MM = u8"mm";
+ PROGMEM Language_Str MSG_UNITS_MM_S = u8"mm/s";
+ PROGMEM Language_Str MSG_UNITS_MM_S2 = u8"mm/s" SUPERSCRIPT_TWO;
+ PROGMEM Language_Str MSG_UNITS_STEP_MM = u8"st/mm";
+ PROGMEM Language_Str MSG_UNITS_PERCENT = u8"%";
+ PROGMEM Language_Str MSG_UNITS_C = DEGREE_SIGN u8"C";
+ PROGMEM Language_Str MSG_IDLE = u8"idle";
+ PROGMEM Language_Str MSG_SET_MAXIMUM = u8"Set Maximum";
+ PROGMEM Language_Str MSG_PRINT_SPEED = u8"Print Speed";
+ PROGMEM Language_Str MSG_LINEAR_ADVANCE = u8"Linear Advance";
+ PROGMEM Language_Str MSG_LINEAR_ADVANCE_K = u8"K";
+ PROGMEM Language_Str MSG_LINEAR_ADVANCE_K1 = u8"K E1";
+ PROGMEM Language_Str MSG_LINEAR_ADVANCE_K2 = u8"K E2";
+ PROGMEM Language_Str MSG_LINEAR_ADVANCE_K3 = u8"K E3";
+ PROGMEM Language_Str MSG_LINEAR_ADVANCE_K4 = u8"K E4";
+ PROGMEM Language_Str MSG_NUDGE_NOZZLE = u8"Nudge Nozzle";
+ PROGMEM Language_Str MSG_ADJUST_BOTH_NOZZLES = u8"Adjust Both Nozzles";
+ PROGMEM Language_Str MSG_SHOW_OFFSETS = u8"Show Offsets";
+ PROGMEM Language_Str MSG_INCREMENT = u8"Increment";
+ PROGMEM Language_Str MSG_ERASE_FLASH_WARNING = u8"Are you sure? SPI flash will be erased.";
+ PROGMEM Language_Str MSG_ERASING = u8"Erasing...";
+ PROGMEM Language_Str MSG_ERASED = u8"SPI flash erased";
+ PROGMEM Language_Str MSG_CALIBRATION_WARNING = u8"For best results, unload the filament and clean the hotend prior to starting calibration. Continue?";
+ PROGMEM Language_Str MSG_START_PRINT_CONFIRMATION = u8"Start printing %s?";
+ PROGMEM Language_Str MSG_ABORT_WARNING = u8"Are you sure you want to cancel the print?";
+ PROGMEM Language_Str MSG_EXTRUDER_SELECTION = u8"Extruder Selection";
+ PROGMEM Language_Str MSG_CURRENT_TEMPERATURE = u8"Current Temp";
+ PROGMEM Language_Str MSG_REMOVAL_TEMPERATURE = u8"Removal Temp";
+ PROGMEM Language_Str MSG_CAUTION = u8"Caution:";
+ PROGMEM Language_Str MSG_HOT = u8"Hot!";
+ PROGMEM Language_Str MSG_UNLOAD_FILAMENT = u8"Unload/Retract";
+ PROGMEM Language_Str MSG_LOAD_FILAMENT = u8"Load/Extrude";
+ PROGMEM Language_Str MSG_MOMENTARY = u8"Momentary";
+ PROGMEM Language_Str MSG_CONTINUOUS = u8"Continuous";
+ PROGMEM Language_Str MSG_PLEASE_WAIT = u8"Please wait...";
+ PROGMEM Language_Str MSG_PRINT_MENU = u8"Print Menu";
+ PROGMEM Language_Str MSG_FINE_MOTION = u8"Fine motion";
+ PROGMEM Language_Str MSG_ENABLE_MEDIA = u8"Enable Media";
+ PROGMEM Language_Str MSG_INSERT_MEDIA = u8"Insert Media...";
+ PROGMEM Language_Str MSG_LCD_BRIGHTNESS = u8"LCD brightness";
+ PROGMEM Language_Str MSG_SOUND_VOLUME = u8"Sound volume";
+ PROGMEM Language_Str MSG_SCREEN_LOCK = u8"Screen lock";
+ PROGMEM Language_Str MSG_BOOT_SCREEN = u8"Boot screen";
+ PROGMEM Language_Str MSG_SOUNDS = u8"Sounds";
+ PROGMEM Language_Str MSG_CLICK_SOUNDS = u8"Click sounds";
+ PROGMEM Language_Str MSG_EEPROM_RESTORED = u8"Settings restored from backup";
+ PROGMEM Language_Str MSG_EEPROM_RESET = u8"Settings restored to default";
+ PROGMEM Language_Str MSG_EEPROM_SAVED = u8"Settings saved!";
+ PROGMEM Language_Str MSG_EEPROM_SAVE_PROMPT = u8"Do you wish to save these settings as defaults?";
+ PROGMEM Language_Str MSG_EEPROM_RESET_WARNING = u8"Are you sure? Customizations will be lost.";
+
+ PROGMEM Language_Str MSG_PASSCODE_REJECTED = u8"Wrong passcode!";
+ PROGMEM Language_Str MSG_PASSCODE_ACCEPTED = u8"Passcode accepted!";
+ PROGMEM Language_Str MSG_PASSCODE_SELECT = u8"Select Passcode:";
+ PROGMEM Language_Str MSG_PASSCODE_REQUEST = u8"Enter Passcode:";
+
+ PROGMEM Language_Str MSG_TOUCH_CALIBRATION_START = u8"Release to begin screen calibration";
+ PROGMEM Language_Str MSG_TOUCH_CALIBRATION_PROMPT = u8"Touch the dots to calibrate";
+ PROGMEM Language_Str MSG_AUTOLEVEL_X_AXIS = u8"Level X Axis";
+ PROGMEM Language_Str MSG_BED_MAPPING_DONE = u8"Bed mapping finished";
+ PROGMEM Language_Str MSG_BED_MAPPING_INCOMPLETE = u8"Not all points probed";
+ PROGMEM Language_Str MSG_LEVELING = u8"Leveling";
+ PROGMEM Language_Str MSG_SHOW_MESH = u8"Show Bed Mesh";
+
+ #if ENABLED(TOUCH_UI_LULZBOT_BIO)
+ PROGMEM Language_Str MSG_MOVE_TO_HOME = u8"Move to Home";
+ PROGMEM Language_Str MSG_RAISE_PLUNGER = u8"Raise Plunger";
+ PROGMEM Language_Str MSG_RELEASE_XY_AXIS = u8"Release X and Y Axis";
+ PROGMEM Language_Str MSG_BED_TEMPERATURE = u8"Bed Temperature";
+ PROGMEM Language_Str MSG_HOME_XYZ_WARNING = u8"About to move to home position. Ensure the top and the bed of the printer are clear.\n\nContinue?";
+ PROGMEM Language_Str MSG_HOME_E_WARNING = u8"About to re-home plunger and auto-level. Remove syringe prior to proceeding.\n\nContinue?";
+ #endif
+
+ #ifdef TOUCH_UI_COCOA_PRESS
+ PROGMEM Language_Str MSG_BODY = u8"Body";
+ PROGMEM Language_Str MSG_INTERNAL = u8"Internal";
+ PROGMEM Language_Str MSG_EXTERNAL = u8"External";
+ PROGMEM Language_Str MSG_CHOCOLATE = u8"Chocolate";
+ PROGMEM Language_Str MSG_UNLOAD_CARTRIDGE = u8"Unload Cartridge";
+ PROGMEM Language_Str MSG_LOAD_CHOCOLATE = u8"Load Chocolate";
+ PROGMEM Language_Str MSG_CARTRIDGE_IN = u8"Cartridge In";
+ PROGMEM Language_Str MSG_CARTRIDGE_OUT = u8"Cartridge Out";
+ PROGMEM Language_Str MSG_PREHEAT_CHOCOLATE = u8"Preheat Chocolate";
+ PROGMEM Language_Str MSG_PREHEAT_FINISHED = u8"Preheat finished";
+ PROGMEM Language_Str MSG_PREHEAT = u8"Preheat";
+ PROGMEM Language_Str MSG_BUTTON_PAUSE = u8"Pause";
+ PROGMEM Language_Str MSG_BUTTON_RESUME = u8"Resume";
+ PROGMEM Language_Str MSG_ELAPSED_PRINT = u8"Elapsed Print";
+ PROGMEM Language_Str MSG_XYZ_MOVE = u8"XYZ Move";
+ PROGMEM Language_Str MSG_E_MOVE = u8"Extrusion Move";
+ #endif
+}; // namespace Language_en
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/marlin_events.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/marlin_events.cpp
new file mode 100644
index 0000000..fc9b5d0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/marlin_events.cpp
@@ -0,0 +1,184 @@
+/*********************
+ * marlin_events.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "compat.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens/screens.h"
+
+namespace ExtUI {
+ using namespace Theme;
+ using namespace FTDI;
+
+ void onStartup() {
+ EventLoop::setup();
+ }
+
+ void onIdle() {
+ EventLoop::loop();
+ }
+
+ void onPrinterKilled(PGM_P const error, PGM_P const component) {
+ char str[strlen_P(error) + strlen_P(component) + 3];
+ sprintf_P(str, PSTR(S_FMT ": " S_FMT), error, component);
+ KillScreen::show(str);
+ }
+
+ void onMediaInserted() {
+ if (AT_SCREEN(StatusScreen))
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_MEDIA_INSERTED));
+ sound.play(media_inserted, PLAY_ASYNCHRONOUS);
+ }
+
+ void onMediaRemoved() {
+ if (isPrintingFromMedia()) {
+ stopPrint();
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FAILED);
+ }
+ else
+ sound.play(media_removed, PLAY_ASYNCHRONOUS);
+
+ if (AT_SCREEN(StatusScreen) || isPrintingFromMedia())
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_MEDIA_REMOVED));
+
+ #if ENABLED(SDSUPPORT)
+ if (AT_SCREEN(FilesScreen)) GOTO_SCREEN(StatusScreen);
+ #endif
+ }
+
+ void onMediaError() {
+ sound.play(sad_trombone, PLAY_ASYNCHRONOUS);
+ AlertDialogBox::showError(F("Unable to read media."));
+ }
+
+ void onStatusChanged(const char* lcd_msg) {
+ StatusScreen::setStatusMessage(lcd_msg);
+ }
+
+ void onStatusChanged(progmem_str lcd_msg) {
+ StatusScreen::setStatusMessage(lcd_msg);
+ }
+
+ void onPrintTimerStarted() {
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_STARTED);
+ }
+
+ void onPrintTimerStopped() {
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FINISHED);
+ }
+
+ void onPrintTimerPaused() {}
+
+ void onPrintFinished() {}
+
+ void onFilamentRunout(const extruder_t extruder) {
+ char lcd_msg[30];
+ sprintf_P(lcd_msg, PSTR("Extruder %d Filament Error"), extruder + 1);
+ StatusScreen::setStatusMessage(lcd_msg);
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FAILED, FTDI::PLAY_SYNCHRONOUS);
+ }
+
+ void onHomingStart() {}
+ void onHomingComplete() {}
+
+ void onFactoryReset() {
+ InterfaceSettingsScreen::defaultSettings();
+ }
+
+ void onStoreSettings(char *buff) {
+ InterfaceSettingsScreen::saveSettings(buff);
+ }
+
+ void onLoadSettings(const char *buff) {
+ InterfaceSettingsScreen::loadSettings(buff);
+ }
+
+ void onConfigurationStoreWritten(bool success) {
+ #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE
+ if (success && InterfaceSettingsScreen::backupEEPROM()) {
+ SERIAL_ECHOLNPGM("Made backup of EEPROM to SPI Flash");
+ }
+ #else
+ UNUSED(success);
+ #endif
+ }
+
+ void onConfigurationStoreRead(bool) {
+ }
+
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {
+ sound.play_tone(frequency, duration);
+ }
+
+ void onUserConfirmRequired(const char * const msg) {
+ if (msg)
+ ConfirmUserRequestAlertBox::show(msg);
+ else
+ ConfirmUserRequestAlertBox::hide();
+ }
+
+ #if HAS_LEVELING && HAS_MESH
+ void onMeshLevelingStart() {}
+
+ void onMeshUpdate(const int8_t x, const int8_t y, const float val) {
+ BedMeshScreen::onMeshUpdate(x, y, val);
+ }
+
+ void onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t state) {
+ BedMeshScreen::onMeshUpdate(x, y, state);
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ //SERIAL_ECHOLNPAIR("OnPidTuning:", rst);
+ switch (rst) {
+ case PID_BAD_EXTRUDER_NUM:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_BAD_EXTRUDER_NUM));
+ break;
+ case PID_TEMP_TOO_HIGH:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
+ break;
+ case PID_TUNING_TIMEOUT:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_TIMEOUT));
+ break;
+ case PID_DONE:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE));
+ break;
+ }
+ GOTO_SCREEN(StatusScreen);
+ }
+ #endif // HAS_PID_HEATING
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/pin_mappings.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/pin_mappings.h
new file mode 100644
index 0000000..ae95a64
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/pin_mappings.h
@@ -0,0 +1,144 @@
+/******************
+ * pin_mappings.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+/* This file defines mappings from the ULTRA_LCD pins functions to new
+ * functions for the FTDI display. These mappings allows any board that
+ * support ULTRA_LCD via EXP1 and EXP2 connectors to use FTDI modules
+ * without adding new pin definitions to the board.
+ */
+
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(F6_TFT_PINMAP) // FYSETC F6 - ATmega2560
+
+ #define CLCD_SPI_CS 33
+ #define CLCD_MOD_RESET 31
+
+#elif ENABLED(S6_TFT_PINMAP) // FYSETC S6 - STM32F4
+
+ #define CLCD_SPI_CS PC7
+ #define CLCD_MOD_RESET PC6
+
+#elif ENABLED(CR10_TFT_PINMAP) // FYSETC S6 - STM32F4 - with TOUCH_UI_ULTIPANEL
+
+ #define CLCD_USE_SOFT_SPI
+ #define CLCD_SOFT_SPI_SCLK LCD_PINS_D4 // PORTA1 Pin 6
+ #define CLCD_SOFT_SPI_MOSI LCD_PINS_ENABLE // PORTC1 Pin 8
+ #define CLCD_SPI_CS LCD_PINS_RS // PORTA3 Pin 7
+ #define CLCD_SOFT_SPI_MISO 16 // PORTC0 BTN_ENC Pin 2
+ #define CLCD_MOD_RESET 11 // PORTD3 BTN_EN1 Pin 3
+ #define CLCD_AUX_0 10 // PORTD2 BTN_EN2 Pin 5
+ #define CLCD_AUX_1 BEEPER_PIN // PORTA4 Pin 1
+
+#elif ENABLED(AO_EXP1_DEPRECATED_PINMAP)
+
+ /**
+ * This AlephObjects pinout re-purposes the UltraLCD
+ * connector EXP1 for Software SPI (rev B, obsolete)
+ */
+
+ #define CLCD_MOD_RESET LCD_PINS_D4
+ #define CLCD_SPI_CS LCD_PINS_D5
+
+ #define CLCD_AUX_0 LCD_PINS_ENABLE
+ #define CLCD_AUX_1 BTN_ENC
+ #define CLCD_AUX_2 BEEPER_PIN
+
+ #define CLCD_USE_SOFT_SPI
+ #define CLCD_SOFT_SPI_SCLK LCD_PINS_D7
+ #define CLCD_SOFT_SPI_MOSI LCD_PINS_D6
+ #define CLCD_SOFT_SPI_MISO LCD_PINS_RS
+
+#elif ENABLED(AO_EXP1_PINMAP)
+
+ /**
+ * AO_EXP1_PINMAP with TOUCH_UI_ULTIPANEL
+ *
+ * This AlephObjects mapping re-purposes the UltraLCD
+ * connector EXP1 for Software SPI for display (rev C):
+ *
+ * EXP2: FTDI: SD -or- USB [1]: ULTRA_LCD:
+ * 1 MISO MISO MISO --> BEEPER
+ * 2 SCLK SCLK SCLK --> BTN_ENC
+ * 3 PD_N - - --> LCDE
+ * 4 - CS_N CS_N --> LCDRS
+ * 5 CS_N - - --> LCD4
+ * 6 MOSI MOSI MOSI --> LCD5
+ * 7 - SD_DET INT --> LCD6
+ * 8 RESET - RESET --> LCD4
+ * 9 GND GND GND --> GND
+ * 10 5V 5V 5V --> 5V
+ *
+ * [1] At the moment, Marlin does not support SD or USB
+ * functionality over software SPI.
+ */
+
+ #define CLCD_MOD_RESET LCD_PINS_ENABLE
+ #define CLCD_SPI_CS LCD_PINS_D4
+
+ #define CLCD_USE_SOFT_SPI
+ #define CLCD_SOFT_SPI_SCLK BTN_ENC
+ #define CLCD_SOFT_SPI_MOSI LCD_PINS_D5
+ #define CLCD_SOFT_SPI_MISO BEEPER_PIN
+
+#elif ENABLED(AO_EXP2_PINMAP)
+
+ /**
+ * AO_EXP2_PINMAP with TOUCH_UI_ULTIPANEL
+ *
+ * The AlephObjects mapping for re-purposing the UltraLCD
+ * connector EXP2 for hardware SPI for display and SD card
+ * or USB (rev C):
+ *
+ * EXP2: FTDI: SD -or- USB: ULTRA_LCD:
+ * 1 MISO MISO MISO --> MISO
+ * 2 SCLK SCLK SCLK --> SCLK
+ * 3 PD_N - - --> BTN_EN2
+ * 4 - CS_N CS_N --> SD_CSEL
+ * 5 CS_N - - --> BTN_EN1
+ * 6 MOSI MOSI MOSI --> MOSI
+ * 7 - SD_DET INT --> SD_DET
+ * 8 RESET - RESET --> RESET
+ * 9 GND GND GND --> GND
+ * 10 5V 5V 5V --> KILL [3]
+ *
+ * [1] This configuration allows daisy-chaining of the
+ * display and SD/USB on EXP2, except for [2]
+ *
+ * [2] The Ultimachine Einsy boards have a level shifter
+ * on MISO enabled by SD_CSEL chip select, hence it
+ * is not possible to run both the display and the
+ * SD/USB on EXP2.
+ *
+ * [3] Archim Rambo provides 5V on this pin. On any other
+ * board, divert this wire from the ribbon cable and
+ * connect it to 5V at an endstop.
+ */
+
+ #define CLCD_SPI_CS BTN_EN1
+ #define CLCD_MOD_RESET BTN_EN2
+ #if MB(EINSY_RAMBO, EINSY_RETRO) && DISABLED(SDSUPPORT)
+ #define CLCD_SPI_EXTRA_CS SDSS
+ #endif
+
+#endif
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/about_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/about_screen.cpp
new file mode 100644
index 0000000..952f0ca
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/about_screen.cpp
@@ -0,0 +1,116 @@
+/********************
+ * about_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+#define GRID_COLS 4
+#define GRID_ROWS 7
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+void AboutScreen::onEntry() {
+ BaseScreen::onEntry();
+ sound.play(chimes, PLAY_ASYNCHRONOUS);
+}
+
+void AboutScreen::onRedraw(draw_mode_t) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+
+ #define HEADING_POS BTN_POS(1,2), BTN_SIZE(4,1)
+ #define FW_VERS_POS BTN_POS(1,3), BTN_SIZE(4,1)
+ #define FW_INFO_POS BTN_POS(1,4), BTN_SIZE(4,1)
+ #define LICENSE_POS BTN_POS(1,5), BTN_SIZE(4,2)
+ #define STATS_POS BTN_POS(1,7), BTN_SIZE(2,1)
+ #define BACK_POS BTN_POS(3,7), BTN_SIZE(2,1)
+
+ #define _INSET_POS(x,y,w,h) x + w/10, y, w - w/5, h
+ #define INSET_POS(pos) _INSET_POS(pos)
+
+ char about_str[1
+ + strlen_P(GET_TEXT(MSG_ABOUT_TOUCH_PANEL_2))
+ #ifdef TOOLHEAD_NAME
+ + strlen_P(TOOLHEAD_NAME)
+ #endif
+ ];
+ #ifdef TOOLHEAD_NAME
+ // If MSG_ABOUT_TOUCH_PANEL_2 has %s, substitute in the toolhead name.
+ // But this is optional, so squelch the compiler warning here.
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wformat-extra-args"
+ sprintf_P(about_str, GET_TEXT(MSG_ABOUT_TOUCH_PANEL_2), TOOLHEAD_NAME);
+ #pragma GCC diagnostic pop
+ #else
+ strcpy_P(about_str, GET_TEXT(MSG_ABOUT_TOUCH_PANEL_2));
+ #endif
+
+ draw_text_box(cmd, HEADING_POS,
+ #ifdef CUSTOM_MACHINE_NAME
+ F(CUSTOM_MACHINE_NAME)
+ #else
+ GET_TEXT_F(MSG_ABOUT_TOUCH_PANEL_1)
+ #endif
+ , OPT_CENTER, font_xlarge
+ );
+ cmd.tag(3);
+ draw_text_box(cmd, FW_VERS_POS,
+ #ifdef TOUCH_UI_VERSION
+ F(TOUCH_UI_VERSION)
+ #else
+ progmem_str(getFirmwareName_str())
+ #endif
+ , OPT_CENTER, font_medium);
+ cmd.tag(0);
+ draw_text_box(cmd, FW_INFO_POS, about_str, OPT_CENTER, font_medium);
+ draw_text_box(cmd, INSET_POS(LICENSE_POS), GET_TEXT_F(MSG_LICENSE), OPT_CENTER, font_tiny);
+
+ cmd.font(font_medium)
+ .colors(normal_btn)
+ .tag(2).button(STATS_POS, GET_TEXT_F(MSG_INFO_STATS_MENU))
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+}
+
+bool AboutScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ #if ENABLED(PRINTCOUNTER)
+ case 2: GOTO_SCREEN(StatisticsScreen); break;
+ #endif
+ #if ENABLED(TOUCH_UI_DEVELOPER_MENU)
+ case 3: GOTO_SCREEN(DeveloperMenu); break;
+ #endif
+ default: return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/advanced_settings_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/advanced_settings_menu.cpp
new file mode 100644
index 0000000..9036fc1
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/advanced_settings_menu.cpp
@@ -0,0 +1,156 @@
+/*****************************
+ * advance_settings_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void AdvancedSettingsMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #if EITHER(HAS_MULTI_HOTEND, SENSORLESS_HOMING)
+ #define GRID_ROWS 9
+ #else
+ #define GRID_ROWS 8
+ #endif
+ #define GRID_COLS 2
+ #define RESTORE_DEFAULTS_POS BTN_POS(1,1), BTN_SIZE(2,1)
+ #define DISPLAY_POS BTN_POS(1,2), BTN_SIZE(1,1)
+ #define INTERFACE_POS BTN_POS(2,2), BTN_SIZE(1,1)
+ #define ZPROBE_ZOFFSET_POS BTN_POS(1,3), BTN_SIZE(1,1)
+ #define STEPS_PER_MM_POS BTN_POS(2,3), BTN_SIZE(1,1)
+ #define FILAMENT_POS BTN_POS(1,4), BTN_SIZE(1,1)
+ #define VELOCITY_POS BTN_POS(2,4), BTN_SIZE(1,1)
+ #define TMC_CURRENT_POS BTN_POS(1,5), BTN_SIZE(1,1)
+ #define ACCELERATION_POS BTN_POS(2,5), BTN_SIZE(1,1)
+ #define ENDSTOPS_POS BTN_POS(1,6), BTN_SIZE(1,1)
+ #define JERK_POS BTN_POS(2,6), BTN_SIZE(1,1)
+ #define CASE_LIGHT_POS BTN_POS(1,7), BTN_SIZE(1,1)
+ #define BACKLASH_POS BTN_POS(2,7), BTN_SIZE(1,1)
+ #define OFFSETS_POS BTN_POS(1,8), BTN_SIZE(1,1)
+ #define TMC_HOMING_THRS_POS BTN_POS(2,8), BTN_SIZE(1,1)
+ #if EITHER(HAS_MULTI_HOTEND, SENSORLESS_HOMING)
+ #define BACK_POS BTN_POS(1,9), BTN_SIZE(2,1)
+ #else
+ #define BACK_POS BTN_POS(1,8), BTN_SIZE(2,1)
+ #endif
+ #else
+ #define GRID_ROWS 6
+ #define GRID_COLS 3
+ #define ZPROBE_ZOFFSET_POS BTN_POS(1,1), BTN_SIZE(1,1)
+ #define CASE_LIGHT_POS BTN_POS(1,4), BTN_SIZE(1,1)
+ #define STEPS_PER_MM_POS BTN_POS(2,1), BTN_SIZE(1,1)
+ #define TMC_CURRENT_POS BTN_POS(3,1), BTN_SIZE(1,1)
+ #define TMC_HOMING_THRS_POS BTN_POS(3,2), BTN_SIZE(1,1)
+ #define BACKLASH_POS BTN_POS(3,3), BTN_SIZE(1,1)
+ #define FILAMENT_POS BTN_POS(1,3), BTN_SIZE(1,1)
+ #define ENDSTOPS_POS BTN_POS(3,4), BTN_SIZE(1,1)
+ #define DISPLAY_POS BTN_POS(3,5), BTN_SIZE(1,1)
+ #define INTERFACE_POS BTN_POS(1,5), BTN_SIZE(2,1)
+ #define RESTORE_DEFAULTS_POS BTN_POS(1,6), BTN_SIZE(2,1)
+ #define VELOCITY_POS BTN_POS(2,2), BTN_SIZE(1,1)
+ #define ACCELERATION_POS BTN_POS(2,3), BTN_SIZE(1,1)
+ #define JERK_POS BTN_POS(2,4), BTN_SIZE(1,1)
+ #define OFFSETS_POS BTN_POS(1,2), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(3,6), BTN_SIZE(1,1)
+ #endif
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ .enabled(ENABLED(HAS_BED_PROBE))
+ .tag(2) .button(ZPROBE_ZOFFSET_POS, GET_TEXT_F(MSG_ZPROBE_ZOFFSET))
+ .enabled(ENABLED(CASE_LIGHT_ENABLE))
+ .tag(16).button(CASE_LIGHT_POS, GET_TEXT_F(MSG_CASE_LIGHT))
+ .tag(3) .button(STEPS_PER_MM_POS, GET_TEXT_F(MSG_STEPS_PER_MM))
+ .enabled(ENABLED(HAS_TRINAMIC_CONFIG))
+ .tag(13).button(TMC_CURRENT_POS, GET_TEXT_F(MSG_TMC_CURRENT))
+ .enabled(ENABLED(SENSORLESS_HOMING))
+ .tag(14).button(TMC_HOMING_THRS_POS, GET_TEXT_F(MSG_TMC_HOMING_THRS))
+ .enabled(ENABLED(HAS_MULTI_HOTEND))
+ .tag(4) .button(OFFSETS_POS, GET_TEXT_F(MSG_OFFSETS_MENU))
+ .enabled(EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR))
+ .tag(11).button(FILAMENT_POS, GET_TEXT_F(MSG_FILAMENT))
+ .tag(12).button(ENDSTOPS_POS, GET_TEXT_F(MSG_LCD_ENDSTOPS))
+ .tag(15).button(DISPLAY_POS, GET_TEXT_F(MSG_DISPLAY_MENU))
+ .tag(9) .button(INTERFACE_POS, GET_TEXT_F(MSG_INTERFACE))
+ .tag(10).button(RESTORE_DEFAULTS_POS, GET_TEXT_F(MSG_RESTORE_DEFAULTS))
+ .tag(5) .button(VELOCITY_POS, GET_TEXT_F(MSG_VELOCITY))
+ .tag(6) .button(ACCELERATION_POS, GET_TEXT_F(MSG_ACCELERATION))
+ .tag(7) .button(JERK_POS, GET_TEXT_F(TERN(HAS_JUNCTION_DEVIATION, MSG_JUNCTION_DEVIATION, MSG_JERK)))
+ .enabled(ENABLED(BACKLASH_GCODE))
+ .tag(8).button(BACKLASH_POS, GET_TEXT_F(MSG_BACKLASH))
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool AdvancedSettingsMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ #if HAS_BED_PROBE
+ case 2: GOTO_SCREEN(ZOffsetScreen); break;
+ #endif
+ case 3: GOTO_SCREEN(StepsScreen); break;
+ #if ENABLED(HAS_MULTI_HOTEND)
+ case 4: GOTO_SCREEN(NozzleOffsetScreen); break;
+ #endif
+ case 5: GOTO_SCREEN(MaxVelocityScreen); break;
+ case 6: GOTO_SCREEN(DefaultAccelerationScreen); break;
+ case 7: GOTO_SCREEN(TERN(HAS_JUNCTION_DEVIATION, JunctionDeviationScreen, JerkScreen)); break;
+ #if ENABLED(BACKLASH_GCODE)
+ case 8: GOTO_SCREEN(BacklashCompensationScreen); break;
+ #endif
+ case 9: GOTO_SCREEN(InterfaceSettingsScreen); LockScreen::check_passcode(); break;
+ case 10: GOTO_SCREEN(RestoreFailsafeDialogBox); LockScreen::check_passcode(); break;
+ #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
+ case 11: GOTO_SCREEN(FilamentMenu); break;
+ #endif
+ case 12: GOTO_SCREEN(EndstopStatesScreen); break;
+ #if HAS_TRINAMIC_CONFIG
+ case 13: GOTO_SCREEN(StepperCurrentScreen); break;
+ #endif
+ #if ENABLED(SENSORLESS_HOMING)
+ case 14: GOTO_SCREEN(StepperBumpSensitivityScreen); break;
+ #endif
+ case 15: GOTO_SCREEN(DisplayTuningScreen); break;
+ #if ENABLED(CASE_LIGHT_ENABLE)
+ case 16: GOTO_SCREEN(CaseLightScreen); break;
+ #endif
+ default: return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && !TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/alert_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/alert_dialog_box.cpp
new file mode 100644
index 0000000..d63119a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/alert_dialog_box.cpp
@@ -0,0 +1,70 @@
+/************************
+ * alert_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void AlertDialogBox::onEntry() {
+ BaseScreen::onEntry();
+ sound.play(screen_data.AlertDialog.isError ? sad_trombone : twinkle, PLAY_ASYNCHRONOUS);
+}
+
+void AlertDialogBox::onRedraw(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ drawOkayButton();
+ }
+}
+
+template<typename T>
+void AlertDialogBox::show(const T message) {
+ drawMessage(message);
+ storeBackground();
+ screen_data.AlertDialog.isError = false;
+ GOTO_SCREEN(AlertDialogBox);
+}
+
+template<typename T>
+void AlertDialogBox::showError(const T message) {
+ drawMessage(message);
+ storeBackground();
+ screen_data.AlertDialog.isError = true;
+ GOTO_SCREEN(AlertDialogBox);
+}
+
+void AlertDialogBox::hide() {
+ if (AT_SCREEN(AlertDialogBox))
+ GOTO_PREVIOUS();
+}
+
+template void AlertDialogBox::show(const char *);
+template void AlertDialogBox::show(const progmem_str);
+template void AlertDialogBox::showError(const char *);
+template void AlertDialogBox::showError(const progmem_str);
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/backlash_compensation_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/backlash_compensation_screen.cpp
new file mode 100644
index 0000000..58f4544
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/backlash_compensation_screen.cpp
@@ -0,0 +1,76 @@
+/************************************
+ * backlash_compensation_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, BACKLASH_GCODE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void BacklashCompensationScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(2).units( GET_TEXT_F(MSG_UNITS_MM));
+ w.heading( GET_TEXT_F(MSG_BACKLASH));
+ w.color(x_axis).adjuster(2, GET_TEXT_F(MSG_AXIS_X), getAxisBacklash_mm(X));
+ w.color(y_axis).adjuster(4, GET_TEXT_F(MSG_AXIS_Y), getAxisBacklash_mm(Y));
+ w.color(z_axis).adjuster(6, GET_TEXT_F(MSG_AXIS_Z), getAxisBacklash_mm(Z));
+ #if ENABLED(CALIBRATION_GCODE)
+ w.button(12, GET_TEXT_F(MSG_MEASURE_AUTOMATICALLY));
+ #endif
+ #ifdef BACKLASH_SMOOTHING_MM
+ w.color(other).adjuster(8, GET_TEXT_F(MSG_BACKLASH_SMOOTHING), getBacklashSmoothing_mm());
+ #endif
+ w.precision(0).units(GET_TEXT_F(MSG_UNITS_PERCENT))
+ .adjuster(10, GET_TEXT_F(MSG_BACKLASH_CORRECTION), getBacklashCorrection_percent());
+ w.precision(2).increments();
+}
+
+bool BacklashCompensationScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(AxisBacklash_mm, X); break;
+ case 3: UI_INCREMENT(AxisBacklash_mm, X); break;
+ case 4: UI_DECREMENT(AxisBacklash_mm, Y); break;
+ case 5: UI_INCREMENT(AxisBacklash_mm, Y); break;
+ case 6: UI_DECREMENT(AxisBacklash_mm, Z); break;
+ case 7: UI_INCREMENT(AxisBacklash_mm, Z); break;
+ #ifdef BACKLASH_SMOOTHING_MM
+ case 8: UI_DECREMENT(BacklashSmoothing_mm); break;
+ case 9: UI_INCREMENT(BacklashSmoothing_mm); break;
+ #endif
+ case 10: UI_DECREMENT_BY(BacklashCorrection_percent, increment*100); break;
+ case 11: UI_INCREMENT_BY(BacklashCorrection_percent, increment*100); break;
+ #if ENABLED(CALIBRATION_GCODE)
+ case 12: GOTO_SCREEN(ConfirmAutoCalibrationDialogBox); return true;
+ #endif
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_numeric_adjustment_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_numeric_adjustment_screen.cpp
new file mode 100644
index 0000000..5271df3
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_numeric_adjustment_screen.cpp
@@ -0,0 +1,388 @@
+/**************************************
+ * base_numeric_adjustment_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_COLS 13
+ #define GRID_ROWS 10
+ #define LAYOUT_FONT font_small
+#else
+ #define GRID_COLS 18
+ #define GRID_ROWS 7
+ #define LAYOUT_FONT font_medium
+#endif
+
+BaseNumericAdjustmentScreen::widgets_t::widgets_t(draw_mode_t what) : _what(what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .colors(normal_btn)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+ }
+
+ cmd.font(font_medium);
+ _button(cmd, 1,
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ BTN_POS(1,10), BTN_SIZE(13,1),
+ #else
+ BTN_POS(15,7), BTN_SIZE(4,1),
+ #endif
+ GET_TEXT_F(MSG_BACK), true, true
+ );
+
+ _line = 1;
+ _units = F("");
+}
+
+/**
+ * Speed optimization for changing button style.
+ */
+void BaseNumericAdjustmentScreen::widgets_t::_button_style(CommandProcessor &cmd, BaseNumericAdjustmentScreen::widgets_t::style_t style) {
+ if (_style != style) {
+ const btn_colors *old_colors = &normal_btn;
+ const btn_colors *new_colors = &normal_btn;
+
+ switch (_style) {
+ case BTN_ACTION: old_colors = &action_btn; break;
+ case BTN_TOGGLE: old_colors = &ui_toggle; break;
+ case BTN_DISABLED: old_colors = &disabled_btn; break;
+ default: break;
+ }
+ switch (style) {
+ case BTN_ACTION: new_colors = &action_btn; break;
+ case BTN_TOGGLE: new_colors = &ui_toggle; break;
+ case BTN_DISABLED: new_colors = &disabled_btn; break;
+ default: break;
+ }
+
+ const bool rgb_changed = (old_colors->rgb != new_colors->rgb) ||
+ (_style == TEXT_LABEL && style != TEXT_LABEL) ||
+ (_style != TEXT_LABEL && style == TEXT_LABEL);
+ const bool grad_changed = old_colors->grad != new_colors->grad;
+ const bool fg_changed = (old_colors->fg != new_colors->fg) || (_style == TEXT_AREA);
+ const bool bg_changed = old_colors->bg != new_colors->bg;
+
+ if (rgb_changed) cmd.cmd(COLOR_RGB(style == TEXT_LABEL ? bg_text_enabled : new_colors->rgb));
+ if (grad_changed) cmd.gradcolor(new_colors->grad);
+ if (fg_changed) cmd.fgcolor(new_colors->fg);
+ if (bg_changed) cmd.bgcolor(new_colors->bg);
+
+ _style = style;
+ }
+}
+
+/**
+ * Speed optimization for drawing buttons. Draw all unpressed buttons in the
+ * background layer and draw only the pressed button in the foreground layer.
+ */
+void BaseNumericAdjustmentScreen::widgets_t::_button(CommandProcessor &cmd, uint8_t tag, int16_t x, int16_t y, int16_t w, int16_t h, progmem_str text, bool enabled, bool highlight) {
+ if (_what & BACKGROUND) enabled = true;
+ if ((_what & BACKGROUND) || buttonIsPressed(tag) || highlight || !enabled) {
+ _button_style(cmd, (!enabled) ? BTN_DISABLED : (highlight ? BTN_ACTION : BTN_NORMAL));
+ cmd.tag(enabled ? tag : 0).button(x, y, w, h, text);
+ }
+}
+
+BaseNumericAdjustmentScreen::widgets_t &BaseNumericAdjustmentScreen::widgets_t::precision(uint8_t decimals, precision_default_t initial) {
+ _decimals = decimals;
+ if (screen_data.BaseNumericAdjustment.increment == 0) {
+ screen_data.BaseNumericAdjustment.increment = 243 + (initial - DEFAULT_LOWEST) - _decimals;
+ }
+ return *this;
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::heading(progmem_str label) {
+ if (_what & BACKGROUND) {
+ CommandProcessor cmd;
+ _button_style(cmd, TEXT_LABEL);
+ cmd.font(font_medium)
+ .tag(0)
+ .text(
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ BTN_POS(1, _line), BTN_SIZE(12,1),
+ #else
+ BTN_POS(5, _line), BTN_SIZE(8,1),
+ #endif
+ label
+ );
+ }
+
+ _line++;
+}
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #ifdef TOUCH_UI_800x480
+ #undef EDGE_R
+ #define EDGE_R 20
+ #else
+ #undef EDGE_R
+ #define EDGE_R 10
+ #endif
+#endif
+
+void BaseNumericAdjustmentScreen::widgets_t::_draw_increment_btn(CommandProcessor &cmd, uint8_t, const uint8_t tag) {
+ const char *label = PSTR("?");
+ uint8_t pos;
+ uint8_t & increment = screen_data.BaseNumericAdjustment.increment;
+
+ if (increment == 0) {
+ increment = tag; // Set the default value to be the first.
+ }
+
+ switch (tag) {
+ case 240: label = PSTR( ".001"); pos = _decimals - 3; break;
+ case 241: label = PSTR( ".01" ); pos = _decimals - 2; break;
+ case 242: label = PSTR( "0.1" ); pos = _decimals - 1; break;
+ case 243: label = PSTR( "1" ); pos = _decimals + 0; break;
+ case 244: label = PSTR( "10" ); pos = _decimals + 1; break;
+ default: label = PSTR("100" ); pos = _decimals + 2; break;
+ }
+
+ const bool highlight = (_what & FOREGROUND) && (increment == tag);
+
+ switch (pos) {
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ case 0: _button(cmd, tag, BTN_POS(5,_line), BTN_SIZE(2,1), progmem_str(label), true, highlight); break;
+ case 1: _button(cmd, tag, BTN_POS(7,_line), BTN_SIZE(2,1), progmem_str(label), true, highlight); break;
+ case 2: _button(cmd, tag, BTN_POS(9,_line), BTN_SIZE(2,1), progmem_str(label), true, highlight); break;
+ #else
+ case 0: _button(cmd, tag, BTN_POS(15,2), BTN_SIZE(4,1), progmem_str(label), true, highlight); break;
+ case 1: _button(cmd, tag, BTN_POS(15,3), BTN_SIZE(4,1), progmem_str(label), true, highlight); break;
+ case 2: _button(cmd, tag, BTN_POS(15,4), BTN_SIZE(4,1), progmem_str(label), true, highlight); break;
+ #endif
+ }
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::increments() {
+ CommandProcessor cmd;
+
+ cmd.font(LAYOUT_FONT);
+
+ if (_what & BACKGROUND) {
+ _button_style(cmd, TEXT_LABEL);
+ cmd.tag(0).text(
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ BTN_POS(1, _line), BTN_SIZE(4,1),
+ #else
+ BTN_POS(15, 1), BTN_SIZE(4,1),
+ #endif
+ GET_TEXT_F(MSG_INCREMENT)
+ );
+ }
+
+ _draw_increment_btn(cmd, _line+1, 245 - _decimals);
+ _draw_increment_btn(cmd, _line+1, 244 - _decimals);
+ _draw_increment_btn(cmd, _line+1, 243 - _decimals);
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ _line++;
+ #endif
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::adjuster_sram_val(uint8_t tag, progmem_str label, const char *value, bool is_enabled) {
+ CommandProcessor cmd;
+
+ if (_what & BACKGROUND) {
+ _button_style(cmd, TEXT_LABEL);
+ cmd.tag(0)
+ .font(font_small)
+ .text( BTN_POS(1,_line), BTN_SIZE(4,1), label);
+ _button_style(cmd, TEXT_AREA);
+ cmd.fgcolor(_color).button(BTN_POS(5,_line), BTN_SIZE(5,1), F(""), OPT_FLAT);
+ }
+
+ cmd.font(font_medium);
+ _button(cmd, tag, BTN_POS(10,_line), BTN_SIZE(2,1), F("-"), is_enabled);
+ _button(cmd, tag + 1, BTN_POS(12,_line), BTN_SIZE(2,1), F("+"), is_enabled);
+
+ if ((_what & FOREGROUND) && is_enabled) {
+ _button_style(cmd, BTN_NORMAL);
+ cmd.tag(0)
+ .font(font_small)
+ .text(BTN_POS(5,_line), BTN_SIZE(5,1), value);
+ }
+
+ _line++;
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::adjuster(uint8_t tag, progmem_str label, const char *value, bool is_enabled) {
+ if (_what & BACKGROUND) {
+ adjuster_sram_val(tag, label, nullptr);
+ }
+
+ if (_what & FOREGROUND) {
+ char b[strlen_P(value)+1];
+ strcpy_P(b,value);
+ adjuster_sram_val(tag, label, b, is_enabled);
+ }
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::adjuster(uint8_t tag, progmem_str label, float value, bool is_enabled) {
+ if (_what & BACKGROUND) {
+ adjuster_sram_val(tag, label, nullptr);
+ }
+
+ if (_what & FOREGROUND) {
+ char b[32];
+ dtostrf(value, 5, _decimals, b);
+ strcat_P(b, PSTR(" "));
+ strcat_P(b, (const char*) _units);
+ adjuster_sram_val(tag, label, b, is_enabled);
+ }
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::button(uint8_t tag, progmem_str label, bool is_enabled) {
+ CommandProcessor cmd;
+ cmd.font(LAYOUT_FONT);
+ _button(cmd, tag, BTN_POS(5,_line), BTN_SIZE(9,1), label, is_enabled);
+
+ _line++;
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::text_field(uint8_t tag, progmem_str label, const char *value, bool is_enabled) {
+ CommandProcessor cmd;
+
+ if (_what & BACKGROUND) {
+ _button_style(cmd, TEXT_LABEL);
+ cmd.enabled(1)
+ .tag(0)
+ .font(font_small)
+ .text( BTN_POS(1,_line), BTN_SIZE(4,1), label);
+ _button_style(cmd, TEXT_AREA);
+ cmd.fgcolor(_color)
+ .tag(tag)
+ .button(BTN_POS(5,_line), BTN_SIZE(9,1), F(""), OPT_FLAT);
+ }
+
+ if (_what & FOREGROUND) {
+ cmd.font(font_small).text( BTN_POS(5,_line), BTN_SIZE(9,1), is_enabled ? value : "-");
+ }
+
+ _line++;
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::two_buttons(uint8_t tag1, progmem_str label1, uint8_t tag2, progmem_str label2, bool is_enabled) {
+ CommandProcessor cmd;
+ cmd.font(LAYOUT_FONT);
+ _button(cmd, tag1, BTN_POS(5,_line), BTN_SIZE(4.5,1), label1, is_enabled);
+ _button(cmd, tag2, BTN_POS(9.5,_line), BTN_SIZE(4.5,1), label2, is_enabled);
+
+ _line++;
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::toggle(uint8_t tag, progmem_str label, bool value, bool is_enabled) {
+ CommandProcessor cmd;
+
+ if (_what & BACKGROUND) {
+ _button_style(cmd, TEXT_LABEL);
+ cmd.font(font_small)
+ .text(
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ BTN_POS(1, _line), BTN_SIZE( 8,1),
+ #else
+ BTN_POS(1, _line), BTN_SIZE(10,1),
+ #endif
+ label
+ );
+ }
+
+ if (_what & FOREGROUND) {
+ _button_style(cmd, BTN_TOGGLE);
+ cmd.tag(is_enabled ? tag : 0)
+ .enabled(is_enabled)
+ .font(font_small)
+ .toggle2(
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ BTN_POS( 9,_line), BTN_SIZE(5,1),
+ #else
+ BTN_POS(10,_line), BTN_SIZE(4,1),
+ #endif
+ GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), value
+ );
+ }
+
+ _line++;
+}
+
+void BaseNumericAdjustmentScreen::widgets_t::home_buttons(uint8_t tag) {
+ CommandProcessor cmd;
+
+ if (_what & BACKGROUND) {
+ _button_style(cmd, TEXT_LABEL);
+ cmd.font(font_small)
+ .text(BTN_POS(1, _line), BTN_SIZE(4,1), GET_TEXT_F(MSG_HOME));
+ }
+
+ cmd.font(LAYOUT_FONT);
+ _button(cmd, tag+0, BTN_POS(5,_line), BTN_SIZE(2,1), GET_TEXT_F(MSG_AXIS_X));
+ _button(cmd, tag+1, BTN_POS(7,_line), BTN_SIZE(2,1), GET_TEXT_F(MSG_AXIS_Y));
+ #if DISABLED(Z_SAFE_HOMING)
+ _button(cmd, tag+2, BTN_POS(9,_line), BTN_SIZE(2,1), GET_TEXT_F(MSG_AXIS_Z));
+ _button(cmd, tag+3, BTN_POS(11,_line), BTN_SIZE(3,1), GET_TEXT_F(MSG_AXIS_ALL));
+ #else
+ _button(cmd, tag+3, BTN_POS(9,_line), BTN_SIZE(3,1), GET_TEXT_F(MSG_AXIS_ALL));
+ #endif
+
+ _line++;
+}
+
+void BaseNumericAdjustmentScreen::onEntry() {
+ screen_data.BaseNumericAdjustment.increment = 0; // This will force the increment to be picked while drawing.
+ BaseScreen::onEntry();
+ CommandProcessor cmd;
+ cmd.set_button_style_callback(nullptr);
+}
+
+bool BaseNumericAdjustmentScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); return true;
+ case 240 ... 245: screen_data.BaseNumericAdjustment.increment = tag; break;
+ default: return current_screen.onTouchHeld(tag);
+ }
+ return true;
+}
+
+float BaseNumericAdjustmentScreen::getIncrement() {
+ switch (screen_data.BaseNumericAdjustment.increment) {
+ case 240: return 0.001;
+ case 241: return 0.01;
+ case 242: return 0.1;
+ case 243: return 1.0;
+ case 244: return 10.0;
+ case 245: return 100.0;
+ default: return 0.0;
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_screen.cpp
new file mode 100644
index 0000000..16b26e6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_screen.cpp
@@ -0,0 +1,90 @@
+/*******************
+ * base_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void BaseScreen::onEntry() {
+ CommandProcessor cmd;
+ cmd.set_button_style_callback(buttonStyleCallback);
+ reset_menu_timeout();
+ UIScreen::onEntry();
+}
+
+bool BaseScreen::buttonIsPressed(uint8_t tag) {
+ return tag != 0 && EventLoop::get_pressed_tag() == tag;
+}
+
+bool BaseScreen::buttonStyleCallback(CommandProcessor &cmd, uint8_t tag, uint8_t &style, uint16_t &options, bool post) {
+ if (post) {
+ cmd.colors(normal_btn);
+ return false;
+ }
+
+ #if LCD_TIMEOUT_TO_STATUS > 0
+ if (EventLoop::get_pressed_tag() != 0) {
+ reset_menu_timeout();
+ }
+ #endif
+
+ if (buttonIsPressed(tag)) {
+ options = OPT_FLAT;
+ }
+
+ if (style & cmd.STYLE_DISABLED) {
+ cmd.tag(0);
+ style &= ~cmd.STYLE_DISABLED;
+ cmd.colors(disabled_btn);
+ return true; // Call me again to reset the colors
+ }
+ return false;
+}
+
+void BaseScreen::onIdle() {
+ #if LCD_TIMEOUT_TO_STATUS > 0
+ if ((millis() - last_interaction) > LCD_TIMEOUT_TO_STATUS) {
+ reset_menu_timeout();
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Returning to status due to menu timeout");
+ #endif
+ GOTO_SCREEN(StatusScreen);
+ }
+ #endif
+}
+
+void BaseScreen::reset_menu_timeout() {
+ #if LCD_TIMEOUT_TO_STATUS > 0
+ last_interaction = millis();
+ #endif
+}
+
+#if LCD_TIMEOUT_TO_STATUS > 0
+ uint32_t BaseScreen::last_interaction;
+#endif
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp
new file mode 100644
index 0000000..9fb2b20
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp
@@ -0,0 +1,341 @@
+/***********************
+ * bed_mesh_screen.cpp *
+ ***********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2020 *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, HAS_MESH)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_COLS 2
+ #define GRID_ROWS 10
+
+ #define MESH_POS BTN_POS(1, 2), BTN_SIZE(2,5)
+ #define MESSAGE_POS BTN_POS(1, 7), BTN_SIZE(2,1)
+ #define Z_LABEL_POS BTN_POS(1, 8), BTN_SIZE(1,1)
+ #define Z_VALUE_POS BTN_POS(2, 8), BTN_SIZE(1,1)
+ #define OKAY_POS BTN_POS(1,10), BTN_SIZE(2,1)
+#else
+ #define GRID_COLS 5
+ #define GRID_ROWS 5
+
+ #define MESH_POS BTN_POS(1,1), BTN_SIZE(3,5)
+ #define MESSAGE_POS BTN_POS(4,1), BTN_SIZE(2,1)
+ #define Z_LABEL_POS BTN_POS(4,2), BTN_SIZE(2,1)
+ #define Z_VALUE_POS BTN_POS(4,3), BTN_SIZE(2,1)
+ #define OKAY_POS BTN_POS(4,5), BTN_SIZE(2,1)
+#endif
+
+void BedMeshScreen::drawMesh(int16_t x, int16_t y, int16_t w, int16_t h, ExtUI::bed_mesh_t data, uint8_t opts, float autoscale_max) {
+ constexpr uint8_t rows = GRID_MAX_POINTS_Y;
+ constexpr uint8_t cols = GRID_MAX_POINTS_X;
+
+ #define VALUE(X,Y) (data ? data[X][Y] : 0)
+ #define ISVAL(X,Y) (data ? !isnan(VALUE(X,Y)) : true)
+ #define HEIGHT(X,Y) (ISVAL(X,Y) ? (VALUE(X,Y) - val_min) * scale_z : 0)
+
+ // Compute the mean, min and max for the points
+
+ float val_mean = 0;
+ float val_max = -INFINITY;
+ float val_min = INFINITY;
+ uint8_t val_cnt = 0;
+
+ if (data && (opts & USE_AUTOSCALE)) {
+ for (uint8_t y = 0; y < rows; y++) {
+ for (uint8_t x = 0; x < cols; x++) {
+ if (ISVAL(x,y)) {
+ const float val = VALUE(x,y);
+ val_mean += val;
+ val_max = max(val_max, val);
+ val_min = min(val_min, val);
+ val_cnt++;
+ }
+ }
+ }
+ }
+ if (val_cnt)
+ val_mean /= val_cnt;
+ else {
+ val_mean = 0;
+ val_min = 0;
+ val_max = 0;
+ }
+
+ const float scale_z = ((val_max == val_min) ? 1 : 1/(val_max - val_min)) * autoscale_max;
+
+ /**
+ * The 3D points go through a 3D graphics pipeline to determine the final 2D point on the screen.
+ * This is written out as a stack of macros that each apply an affine transformation to the point.
+ * At compile time, the compiler should be able to reduce these expressions.
+ *
+ * The last transformation in the chain (TRANSFORM_5) is initially set to a no-op so we can measure
+ * the dimensions of the grid, but is later replaced with a scaling transform that scales the grid
+ * to fit.
+ */
+
+ #define TRANSFORM_5(X,Y,Z) (X), (Y) // No transform
+ #define TRANSFORM_4(X,Y,Z) TRANSFORM_5((X)/(Z),(Y)/-(Z), 0) // Perspective
+ #define TRANSFORM_3(X,Y,Z) TRANSFORM_4((X), (Z), (Y)) // Swap Z and Y
+ #define TRANSFORM_2(X,Y,Z) TRANSFORM_3((X), (Y) + 2.5, (Z) - 1) // Translate
+ #define TRANSFORM(X,Y,Z) TRANSFORM_2(float(X)/(cols-1) - 0.5, float(Y)/(rows-1) - 0.5, (Z)) // Normalize
+
+ // Compute the bounding box for the grid prior to scaling. Do this at compile-time by
+ // transforming the four corner points via the transformation equations and finding
+ // the min and max for each axis.
+
+ constexpr float bounds[][3] = {{TRANSFORM(0 , 0 , 0)},
+ {TRANSFORM(cols-1, 0 , 0)},
+ {TRANSFORM(0 , rows-1, 0)},
+ {TRANSFORM(cols-1, rows-1, 0)}};
+ #define APPLY(FUNC, AXIS) FUNC(FUNC(bounds[0][AXIS], bounds[1][AXIS]), FUNC(bounds[2][AXIS], bounds[3][AXIS]))
+ constexpr float grid_x = APPLY(min,0);
+ constexpr float grid_y = APPLY(min,1);
+ constexpr float grid_w = APPLY(max,0) - grid_x;
+ constexpr float grid_h = APPLY(max,1) - grid_y;
+ constexpr float grid_cx = grid_x + grid_w/2;
+ constexpr float grid_cy = grid_y + grid_h/2;
+
+ // Figure out scale and offset such that the grid fits within the rectangle given by (x,y,w,h)
+
+ const float scale_x = float(w)/grid_w;
+ const float scale_y = float(h)/grid_h;
+ const float center_x = x + w/2;
+ const float center_y = y + h/2;
+
+ // Now replace the last transformation in the chain with a scaling operation.
+
+ #undef TRANSFORM_5
+ #define TRANSFORM_6(X,Y,Z) (X)*16, (Y)*16 // Scale to 1/16 pixel units
+ #define TRANSFORM_5(X,Y,Z) TRANSFORM_6( center_x + ((X) - grid_cx) * scale_x, \
+ center_y + ((Y) - grid_cy) * scale_y, 0) // Scale to bounds
+
+ // Draw the grid
+
+ const uint16_t basePointSize = min(w,h) / max(cols,rows);
+
+ CommandProcessor cmd;
+ cmd.cmd(SAVE_CONTEXT())
+ .cmd(TAG_MASK(false))
+ .cmd(SAVE_CONTEXT());
+
+ for (uint8_t y = 0; y < rows; y++) {
+ for (uint8_t x = 0; x < cols; x++) {
+ if (ISVAL(x,y)) {
+ const bool hasLeftSegment = x < cols - 1 && ISVAL(x+1,y);
+ const bool hasRightSegment = y < rows - 1 && ISVAL(x,y+1);
+ if (hasLeftSegment || hasRightSegment) {
+ cmd.cmd(BEGIN(LINE_STRIP));
+ if (hasLeftSegment) cmd.cmd(VERTEX2F(TRANSFORM(x + 1, y , HEIGHT(x + 1, y ))));
+ cmd.cmd( VERTEX2F(TRANSFORM(x , y , HEIGHT(x , y ))));
+ if (hasRightSegment) cmd.cmd(VERTEX2F(TRANSFORM(x , y + 1, HEIGHT(x , y + 1))));
+ }
+ }
+ }
+
+ if (opts & USE_POINTS) {
+ const float sq_min = sq(val_min - val_mean);
+ const float sq_max = sq(val_max - val_mean);
+ cmd.cmd(POINT_SIZE(basePointSize * 2));
+ cmd.cmd(BEGIN(POINTS));
+ for (uint8_t x = 0; x < cols; x++) {
+ if (ISVAL(x,y)) {
+ if (opts & USE_COLORS) {
+ const float val_dev = VALUE(x, y) - val_mean;
+ const uint8_t neg_byte = sq(val_dev) / (val_dev < 0 ? sq_min : sq_max) * 0xFF;
+ const uint8_t pos_byte = 255 - neg_byte;
+ cmd.cmd(COLOR_RGB(pos_byte, pos_byte, 0xFF));
+ }
+ cmd.cmd(VERTEX2F(TRANSFORM(x, y, HEIGHT(x, y))));
+ }
+ }
+ if (opts & USE_COLORS) {
+ cmd.cmd(RESTORE_CONTEXT())
+ .cmd(SAVE_CONTEXT());
+ }
+ }
+ }
+ cmd.cmd(RESTORE_CONTEXT())
+ .cmd(TAG_MASK(true));
+
+ if (opts & USE_TAGS) {
+ cmd.cmd(COLOR_MASK(false, false, false, false))
+ .cmd(POINT_SIZE(basePointSize * 10))
+ .cmd(BEGIN(POINTS));
+ for (uint8_t y = 0; y < rows; y++) {
+ for (uint8_t x = 0; x < cols; x++) {
+ const uint8_t tag = pointToTag(x, y);
+ cmd.tag(tag).cmd(VERTEX2F(TRANSFORM(x, y, HEIGHT(x, y))));
+ }
+ }
+ cmd.cmd(COLOR_MASK(true, true, true, true));
+ }
+
+ if (opts & USE_HIGHLIGHT) {
+ const uint8_t tag = screen_data.BedMesh.highlightedTag;
+ uint8_t x, y;
+ if (tagToPoint(tag, x, y)) {
+ cmd.cmd(COLOR_A(128))
+ .cmd(POINT_SIZE(basePointSize * 6))
+ .cmd(BEGIN(POINTS))
+ .tag(tag).cmd(VERTEX2F(TRANSFORM(x, y, HEIGHT(x, y))));
+ }
+ }
+ cmd.cmd(END());
+ cmd.cmd(RESTORE_CONTEXT());
+}
+
+uint8_t BedMeshScreen::pointToTag(uint8_t x, uint8_t y) {
+ return y * (GRID_MAX_POINTS_X) + x + 10;
+}
+
+bool BedMeshScreen::tagToPoint(uint8_t tag, uint8_t &x, uint8_t &y) {
+ if (tag < 10) return false;
+ x = (tag - 10) % (GRID_MAX_POINTS_X);
+ y = (tag - 10) / (GRID_MAX_POINTS_X);
+ return true;
+}
+
+void BedMeshScreen::onEntry() {
+ screen_data.BedMesh.highlightedTag = 0;
+ screen_data.BedMesh.count = GRID_MAX_POINTS;
+ screen_data.BedMesh.message = screen_data.BedMesh.MSG_NONE;
+ BaseScreen::onEntry();
+}
+
+float BedMeshScreen::getHightlightedValue() {
+ if (screen_data.BedMesh.highlightedTag) {
+ xy_uint8_t pt;
+ tagToPoint(screen_data.BedMesh.highlightedTag, pt.x, pt.y);
+ return ExtUI::getMeshPoint(pt);
+ }
+ return NAN;
+}
+
+void BedMeshScreen::drawHighlightedPointValue() {
+ char str[16];
+ const float val = getHightlightedValue();
+ const bool isGood = !isnan(val);
+ if (isGood)
+ dtostrf(val, 5, 3, str);
+ else
+ strcpy_P(str, PSTR("-"));
+
+ CommandProcessor cmd;
+ cmd.font(Theme::font_medium)
+ .text(Z_LABEL_POS, GET_TEXT_F(MSG_MESH_EDIT_Z))
+ .text(Z_VALUE_POS, str)
+ .colors(action_btn)
+ .tag(1).button(OKAY_POS, GET_TEXT_F(MSG_BUTTON_OKAY))
+ .tag(0);
+
+ switch (screen_data.BedMesh.message) {
+ case screen_data.BedMesh.MSG_MESH_COMPLETE: cmd.text(MESSAGE_POS, GET_TEXT_F(MSG_BED_MAPPING_DONE)); break;
+ case screen_data.BedMesh.MSG_MESH_INCOMPLETE: cmd.text(MESSAGE_POS, GET_TEXT_F(MSG_BED_MAPPING_INCOMPLETE)); break;
+ default: break;
+ }
+}
+
+void BedMeshScreen::onRedraw(draw_mode_t what) {
+ #define _INSET_POS(x,y,w,h) x + min(w,h)/10, y + min(w,h)/10, w - min(w,h)/5, h - min(w,h)/5
+ #define INSET_POS(pos) _INSET_POS(pos)
+
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true));
+
+ // Draw the shadow and tags
+ cmd.cmd(COLOR_RGB(0x444444));
+ BedMeshScreen::drawMesh(INSET_POS(MESH_POS), nullptr, USE_POINTS | USE_TAGS);
+ cmd.cmd(COLOR_RGB(bg_text_enabled));
+ }
+
+ if (what & FOREGROUND) {
+ constexpr float autoscale_max_amplitude = 0.03;
+ const bool gotAllPoints = screen_data.BedMesh.count >= GRID_MAX_POINTS;
+ if (gotAllPoints) {
+ drawHighlightedPointValue();
+ }
+ const float levelingProgress = sq(float(screen_data.BedMesh.count) / GRID_MAX_POINTS);
+ BedMeshScreen::drawMesh(INSET_POS(MESH_POS), ExtUI::getMeshArray(),
+ USE_POINTS | USE_HIGHLIGHT | USE_AUTOSCALE | (gotAllPoints ? USE_COLORS : 0),
+ autoscale_max_amplitude * levelingProgress
+ );
+ }
+}
+
+bool BedMeshScreen::onTouchStart(uint8_t tag) {
+ screen_data.BedMesh.highlightedTag = tag;
+ return true;
+}
+
+bool BedMeshScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ GOTO_PREVIOUS();
+ return true;
+ default:
+ return false;
+ }
+}
+
+void BedMeshScreen::onMeshUpdate(const int8_t, const int8_t, const float) {
+ if (AT_SCREEN(BedMeshScreen))
+ onRefresh();
+}
+
+void BedMeshScreen::onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t state) {
+ switch (state) {
+ case ExtUI::MESH_START:
+ screen_data.BedMesh.count = 0;
+ screen_data.BedMesh.message = screen_data.BedMesh.MSG_NONE;
+ break;
+ case ExtUI::MESH_FINISH:
+ if (screen_data.BedMesh.count == GRID_MAX_POINTS && ExtUI::getMeshValid())
+ screen_data.BedMesh.message = screen_data.BedMesh.MSG_MESH_COMPLETE;
+ else
+ screen_data.BedMesh.message = screen_data.BedMesh.MSG_MESH_INCOMPLETE;
+ screen_data.BedMesh.count = GRID_MAX_POINTS;
+ break;
+ case ExtUI::PROBE_START:
+ screen_data.BedMesh.highlightedTag = pointToTag(x, y);
+ break;
+ case ExtUI::PROBE_FINISH:
+ screen_data.BedMesh.count++;
+ break;
+ }
+ BedMeshScreen::onMeshUpdate(x, y, 0);
+}
+
+void BedMeshScreen::startMeshProbe() {
+ GOTO_SCREEN(BedMeshScreen);
+ screen_data.BedMesh.count = 0;
+ injectCommands_P(PSTR(BED_LEVELING_COMMANDS));
+}
+
+#endif // TOUCH_UI_FTDI_EVE && HAS_MESH
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_advanced_settings.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_advanced_settings.cpp
new file mode 100644
index 0000000..cabcd5d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_advanced_settings.cpp
@@ -0,0 +1,137 @@
+/*****************************
+ * bio_advanced_settings.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void AdvancedSettingsMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ #define GRID_ROWS 9
+ #define GRID_COLS 2
+
+ .tag(2) .button(BTN_POS(1,1), BTN_SIZE(1,1), GET_TEXT_F(MSG_DISPLAY_MENU))
+ .enabled(
+ #if HAS_TRINAMIC_CONFIG
+ 1
+ #endif
+ )
+ .tag(3) .button(BTN_POS(1,2), BTN_SIZE(1,1), GET_TEXT_F(MSG_TMC_CURRENT))
+ .enabled(
+ #if HAS_TRINAMIC_CONFIG
+ 1
+ #endif
+ )
+ .tag(4) .button(BTN_POS(1,3), BTN_SIZE(1,1), GET_TEXT_F(MSG_TMC_HOMING_THRS))
+ .tag(5) .button(BTN_POS(1,4), BTN_SIZE(1,1), GET_TEXT_F(MSG_LCD_ENDSTOPS))
+ .enabled(
+ #if HAS_MULTI_HOTEND
+ 1
+ #endif
+ )
+ .tag(6) .button(BTN_POS(1,5), BTN_SIZE(1,1), GET_TEXT_F(MSG_OFFSETS_MENU))
+
+
+ .tag(7) .button(BTN_POS(2,1), BTN_SIZE(1,1), GET_TEXT_F(MSG_STEPS_PER_MM))
+ .tag(8) .button(BTN_POS(2,2), BTN_SIZE(1,1), GET_TEXT_F(MSG_VELOCITY))
+ .tag(9) .button(BTN_POS(2,3), BTN_SIZE(1,1), GET_TEXT_F(MSG_ACCELERATION))
+ #if HAS_JUNCTION_DEVIATION
+ .tag(10) .button(BTN_POS(2,4), BTN_SIZE(1,1), GET_TEXT_F(MSG_JUNCTION_DEVIATION))
+ #else
+ .tag(10) .button(BTN_POS(2,4), BTN_SIZE(1,1), GET_TEXT_F(MSG_JERK))
+ #endif
+ .enabled(
+ #if ENABLED(BACKLASH_GCODE)
+ 1
+ #endif
+ )
+ .tag(11) .button(BTN_POS(2,5), BTN_SIZE(1,1), GET_TEXT_F(MSG_BACKLASH))
+ .enabled(
+ #if ENABLED(LIN_ADVANCE)
+ 1
+ #endif
+ )
+ .tag(12) .button(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_LINEAR_ADVANCE))
+ .tag(13) .button(BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_INTERFACE))
+ .tag(14) .button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_RESTORE_DEFAULTS))
+ .colors(action_btn)
+ .tag(1). button( BTN_POS(1,9), BTN_SIZE(2,1), GET_TEXT_F(MSG_BACK));
+ #undef GRID_COLS
+ #undef GRID_ROWS
+ }
+}
+
+bool AdvancedSettingsMenu::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(DisplayTuningScreen); break;
+ #if HAS_TRINAMIC_CONFIG
+ case 3: GOTO_SCREEN(StepperCurrentScreen); break;
+ case 4: GOTO_SCREEN(StepperBumpSensitivityScreen); break;
+ #endif
+ case 5: GOTO_SCREEN(EndstopStatesScreen); break;
+ #if HAS_MULTI_HOTEND
+ case 6: GOTO_SCREEN(NozzleOffsetScreen); break;
+ #endif
+
+ case 7: GOTO_SCREEN(StepsScreen); break;
+ case 8: GOTO_SCREEN(MaxVelocityScreen); break;
+ case 9: GOTO_SCREEN(DefaultAccelerationScreen); break;
+ case 10:
+ #if HAS_JUNCTION_DEVIATION
+ GOTO_SCREEN(JunctionDeviationScreen);
+ #else
+ GOTO_SCREEN(JerkScreen);
+ #endif
+ break;
+ #if ENABLED(BACKLASH_GCODE)
+ case 11: GOTO_SCREEN(BacklashCompensationScreen); break;
+ #endif
+ #if ENABLED(LIN_ADVANCE)
+ case 12: GOTO_SCREEN(LinearAdvanceScreen); break;
+ #endif
+ case 13: GOTO_SCREEN(InterfaceSettingsScreen); break;
+ case 14: GOTO_SCREEN(RestoreFailsafeDialogBox); break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_e.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_e.cpp
new file mode 100644
index 0000000..3f6b411
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_e.cpp
@@ -0,0 +1,57 @@
+/****************************
+ * bio_confirm_home_xyz.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+using namespace FTDI;
+
+void BioConfirmHomeE::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_HOME_E_WARNING));
+ drawYesNoButtons(1);
+}
+
+bool BioConfirmHomeE::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ #if defined(AXIS_LEVELING_COMMANDS) && defined(PARK_AND_RELEASE_COMMANDS)
+ SpinnerDialogBox::enqueueAndWait_P(F(
+ "G28 E\n"
+ AXIS_LEVELING_COMMANDS "\n"
+ PARK_AND_RELEASE_COMMANDS
+ ));
+ #endif
+ current_screen.forget();
+ break;
+ case 2:
+ GOTO_SCREEN(StatusScreen);
+ break;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_xyz.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_xyz.cpp
new file mode 100644
index 0000000..f712fdf
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_xyz.cpp
@@ -0,0 +1,56 @@
+/****************************
+ * bio_confirm_home_xyz.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+using namespace FTDI;
+
+void BioConfirmHomeXYZ::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_HOME_XYZ_WARNING));
+ drawYesNoButtons(1);
+}
+
+bool BioConfirmHomeXYZ::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ #ifdef PARK_AND_RELEASE_COMMANDS
+ SpinnerDialogBox::enqueueAndWait_P(F(
+ "G28\n"
+ PARK_AND_RELEASE_COMMANDS
+ ));
+ #endif
+ current_screen.forget();
+ break;
+ case 2:
+ GOTO_SCREEN(StatusScreen);
+ break;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_main_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_main_menu.cpp
new file mode 100644
index 0000000..53203cd
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_main_menu.cpp
@@ -0,0 +1,88 @@
+/*********************
+ * bio_main_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void MainMenu::onRedraw(draw_mode_t what) {
+ #define GRID_ROWS 10
+ #define GRID_COLS 2
+
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .font(font_large).text( BTN_POS(1,1), BTN_SIZE(2,1), GET_TEXT_F(MSG_MAIN))
+ .colors(normal_btn)
+ .font(font_medium)
+ .tag(2).button(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_MOVE_TO_HOME))
+ .tag(3).button(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_RAISE_PLUNGER))
+ .tag(4).button(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_RELEASE_XY_AXIS))
+ .tag(5).button(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_AUTOLEVEL_X_AXIS))
+ .tag(6).button(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_BED_TEMPERATURE))
+ .tag(7).button(BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_INTERFACE))
+ .tag(8).button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_ADVANCED_SETTINGS))
+ .tag(9).button(BTN_POS(1,9), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_MENU))
+ .colors(action_btn)
+ .tag(1).button(BTN_POS(1,10), BTN_SIZE(2,1), GET_TEXT_F(MSG_BACK));
+ }
+
+ #undef GRID_COLS
+ #undef GRID_ROWS
+}
+
+bool MainMenu::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ const bool e_homed = isAxisPositionKnown(E0);
+
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(BioConfirmHomeXYZ); break;
+ case 3: SpinnerDialogBox::enqueueAndWait_P(e_homed ? F("G0 E0 F120") : F("G112")); break;
+ case 4: StatusScreen::unlockMotors(); break;
+ #ifdef AXIS_LEVELING_COMMANDS
+ case 5: SpinnerDialogBox::enqueueAndWait_P(F(AXIS_LEVELING_COMMANDS)); break;
+ #endif
+ case 6: GOTO_SCREEN(TemperatureScreen); break;
+ case 7: GOTO_SCREEN(InterfaceSettingsScreen); break;
+ case 8: GOTO_SCREEN(AdvancedSettingsMenu); break;
+ case 9: GOTO_SCREEN(AboutScreen); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_landscape.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_landscape.h
new file mode 100644
index 0000000..4faddc6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_landscape.h
@@ -0,0 +1,59 @@
+
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 480.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 272.000000;
+
+const PROGMEM uint16_t z_neg[] = {0x7950, 0x51EA, 0x824E, 0x51EA, 0x824E, 0x71E2, 0x86CD, 0x71E2, 0x7DCF, 0x81DF, 0x74D1, 0x71E2, 0x7950, 0x71E2, 0x7950, 0x51EA};
+const PROGMEM uint16_t z_pos[] = {0x7950, 0x41EE, 0x824E, 0x41EE, 0x824E, 0x21F5, 0x86CD, 0x21F5, 0x7DCF, 0x11F9, 0x74D0, 0x21F5, 0x7950, 0x21F5, 0x7950, 0x41EE};
+const PROGMEM uint16_t y_neg[] = {0x3479, 0x56CF, 0x3EC6, 0x56CF, 0x3747, 0x7281, 0x3C6D, 0x7281, 0x2E61, 0x8059, 0x27D4, 0x7281, 0x2CFA, 0x7281, 0x3479, 0x56CF};
+const PROGMEM uint16_t y_pos[] = {0x3BF9, 0x3B1D, 0x4645, 0x3B1D, 0x4DC4, 0x1F6B, 0x52EB, 0x1F6B, 0x4C5E, 0x1192, 0x3E52, 0x1F6B, 0x4378, 0x1F6B, 0x3BF9, 0x3B1D};
+const PROGMEM uint16_t x_neg[] = {0x350E, 0x4209, 0x314E, 0x4FE2, 0x1CB5, 0x4FE2, 0x1AD6, 0x56CF, 0x1449, 0x48F6, 0x2255, 0x3B1D, 0x2075, 0x4209, 0x350E, 0x4209};
+const PROGMEM uint16_t x_pos[] = {0x498C, 0x4209, 0x45CC, 0x4FE2, 0x5A65, 0x4FE2, 0x5885, 0x56CF, 0x6691, 0x48F6, 0x6004, 0x3B1D, 0x5E25, 0x4209, 0x498C, 0x4209};
+const PROGMEM uint16_t syringe_fluid[] = {0xB4E9, 0x78BE, 0xBB12, 0x7C44, 0xBDE3, 0x7C44, 0xC426, 0x78BE, 0xC426, 0x250D, 0xB4E9, 0x250D, 0xB4E9, 0x78BE};
+const PROGMEM uint16_t syringe[] = {0xB8AD, 0x6BB1, 0xB8AD, 0x6E0C, 0xBE02, 0x6E0C, 0xBE02, 0x6BB1, 0xFFFF, 0xB8AD, 0x6248, 0xB8AD, 0x64A2, 0xBE02, 0x64A2, 0xBE02, 0x6248, 0xFFFF, 0xB8AD, 0x58DF, 0xB8AD, 0x5B39, 0xBE02, 0x5B39, 0xBE02, 0x58DF, 0xFFFF, 0xB8AD, 0x4F75, 0xB8AD, 0x51D0, 0xBE02, 0x51D0, 0xBE02, 0x4F75, 0xFFFF, 0xB8AD, 0x460C, 0xB8AD, 0x4866, 0xBE02, 0x4866, 0xBE02, 0x460C, 0xFFFF, 0xB8AD, 0x3CA3, 0xB8AD, 0x3EFD, 0xBE02, 0x3EFD, 0xBE02, 0x3CA3, 0xFFFF, 0xB8AD, 0x3339, 0xB8AD, 0x3594, 0xBE02, 0x3594, 0xBE02, 0x3339, 0xFFFF, 0xB396, 0x110A, 0xB396, 0x1818, 0xB995, 0x1818, 0xB995, 0x22AD, 0xB396, 0x22AD, 0xB396, 0x7ADA, 0xB995, 0x7E61, 0xB995, 0x88F5, 0xBB95, 0x88F5, 0xBB95, 0xA8B4, 0xBD94, 0xAC3B, 0xBD94, 0x88F5, 0xBF94, 0x88F5, 0xBF94, 0x7E61, 0xC593, 0x7ADA, 0xC593, 0x22AD, 0xBF94, 0x22AD, 0xBF94, 0x1818, 0xC593, 0x1818, 0xC593, 0x110A, 0xFFFF, 0xBB95, 0x1818, 0xBD94, 0x1818, 0xBD94, 0x22AD, 0xBB95, 0x22AD, 0xBB95, 0x1818, 0xFFFF, 0xB596, 0x2634, 0xC393, 0x2634, 0xC393, 0x7753, 0xBD94, 0x7ADA, 0xBB95, 0x7ADA, 0xB596, 0x7753, 0xB596, 0x2634};
+const PROGMEM uint16_t syringe_outline[] = {0xB396, 0x110A, 0xB396, 0x1818, 0xB995, 0x1818, 0xB995, 0x22AD, 0xB396, 0x22AD, 0xB396, 0x7ADA, 0xB995, 0x7E61, 0xB995, 0x88F5, 0xBB95, 0x88F5, 0xBB95, 0xA8B4, 0xBD94, 0xAC3B, 0xBD94, 0x88F5, 0xBF94, 0x88F5, 0xBF94, 0x7E61, 0xC593, 0x7ADA, 0xC593, 0x22AD, 0xBF94, 0x22AD, 0xBF94, 0x1818, 0xC593, 0x1818, 0xC593, 0x110A, 0xB396, 0x110A};
+const PROGMEM uint16_t padlock[] = {0x3FE3, 0x2A04, 0x3D34, 0x2AF9, 0x3AFF, 0x2D93, 0x397D, 0x316D, 0x38E8, 0x3626, 0x38E8, 0x3A14, 0x39B3, 0x3C8F, 0x3B50, 0x3C8F, 0x3C1C, 0x3A14, 0x3C1C, 0x363C, 0x3C6B, 0x33A9, 0x3D3A, 0x3193, 0x3E6C, 0x302D, 0x3FE3, 0x2FAA, 0x415A, 0x302D, 0x428C, 0x3192, 0x435B, 0x33A8, 0x43AB, 0x363C, 0x43AB, 0x4492, 0x38C3, 0x4492, 0x3741, 0x45AC, 0x36A1, 0x4856, 0x36A1, 0x5C41, 0x3741, 0x5EEC, 0x38C3, 0x6005, 0x4703, 0x6005, 0x4886, 0x5EEC, 0x4925, 0x5C41, 0x4925, 0x4856, 0x4886, 0x45AC, 0x4703, 0x4492, 0x46DE, 0x362B, 0x4649, 0x316D, 0x44C7, 0x2D92, 0x4292, 0x2AF9};
+const PROGMEM uint16_t home_z[] = {0x80BB, 0x2B43, 0x712C, 0x46B9, 0x750F, 0x46B9, 0x750F, 0x622F, 0x7CD7, 0x622F, 0x7CD7, 0x5474, 0x849F, 0x5474, 0x849F, 0x622F, 0x8C67, 0x622F, 0x8C67, 0x46B9, 0x904B, 0x46B9, 0x8A48, 0x3C1D, 0x8A48, 0x2ECD, 0x8664, 0x2ECD, 0x8664, 0x3540};
+const PROGMEM uint16_t usb_btn[] = {0x0558, 0xC0D6, 0x3BDB, 0xC0D6, 0x3BDB, 0xF431, 0x0558, 0xF431, 0x0558, 0xC0D6};
+const PROGMEM uint16_t menu_btn[] = {0x416B, 0xC0D6, 0x77EE, 0xC0D6, 0x77EE, 0xF431, 0x416B, 0xF431, 0x416B, 0xC0D6};
+const PROGMEM uint16_t e_pos[] = {0xE04E, 0x5E7B, 0xE94C, 0x5E7B, 0xE94C, 0x7E74, 0xEDCB, 0x7E74, 0xE4CD, 0x8E70, 0xDBCF, 0x7E74, 0xE04E, 0x7E74, 0xE04E, 0x5E7B};
+const PROGMEM uint16_t e_neg[] = {0xE04E, 0x4E7F, 0xE94C, 0x4E7F, 0xE94C, 0x2E87, 0xEDCB, 0x2E87, 0xE4CD, 0x1E8A, 0xDBCF, 0x2E87, 0xE04E, 0x2E87, 0xE04E, 0x4E7F};
+const PROGMEM uint16_t home_e[] = {0xD705, 0x3885, 0xC775, 0x53FB, 0xCB59, 0x53FB, 0xCB59, 0x6F71, 0xD321, 0x6F71, 0xD321, 0x61B6, 0xDAE9, 0x61B6, 0xDAE9, 0x6F71, 0xE2B1, 0x6F71, 0xE2B1, 0x53FB, 0xE695, 0x53FB, 0xE092, 0x495F, 0xE092, 0x3C0E, 0xDCAE, 0x3C0E, 0xDCAE, 0x4281};
+const PROGMEM uint16_t fine_label[] = {0x0D92, 0x9444, 0x5211, 0x9444, 0x5211, 0xA9EA, 0x0D92, 0xA9EA};
+const PROGMEM uint16_t fine_toggle[] = {0x56E7, 0x9444, 0x8007, 0x9444, 0x8007, 0xA9EA, 0x56E7, 0xA9EA};
+const PROGMEM uint16_t h1_temp[] = {0x9C2B, 0xDD3B, 0xBBDE, 0xDD3B, 0xBBDE, 0xFA57, 0x9C2B, 0xFA57};
+const PROGMEM uint16_t h1_label[] = {0x9C2B, 0xBE8F, 0xBBDC, 0xBE8F, 0xBBDC, 0xDBAA, 0x9C2B, 0xDBAA};
+const PROGMEM uint16_t h0_temp[] = {0x7BD0, 0xDD3B, 0x9B83, 0xDD3B, 0x9B83, 0xFA57, 0x7BD0, 0xFA57};
+const PROGMEM uint16_t h0_label[] = {0x7BD0, 0xBE8F, 0x9B83, 0xBE8F, 0x9B83, 0xDBAA, 0x7BD0, 0xDBAA};
+const PROGMEM uint16_t h2_temp[] = {0xBC86, 0xDD3B, 0xDC39, 0xDD3B, 0xDC39, 0xFA57, 0xBC86, 0xFA57};
+const PROGMEM uint16_t h2_label[] = {0xBC86, 0xBE8F, 0xDC37, 0xBE8F, 0xDC37, 0xDBAA, 0xBC86, 0xDBAA};
+const PROGMEM uint16_t h3_temp[] = {0xDCE2, 0xDD0D, 0xFC95, 0xDD0D, 0xFC95, 0xFA28, 0xDCE2, 0xFA28};
+const PROGMEM uint16_t h3_label[] = {0xDCE2, 0xBE60, 0xFC92, 0xBE60, 0xFC92, 0xDB7C, 0xDCE2, 0xDB7C};
+const PROGMEM uint16_t actual_temp[] = {0xCDF6, 0xD037, 0xF7CA, 0xD037, 0xF7CA, 0xF424, 0xCDF6, 0xF424};
+const PROGMEM uint16_t bed_icon[] = {0xCDF6, 0xA5CC, 0xF7CA, 0xA5CC, 0xF7CA, 0xC9B9, 0xCDF6, 0xC9B9};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_portrait.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_portrait.h
new file mode 100644
index 0000000..50fc5ab
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_portrait.h
@@ -0,0 +1,52 @@
+
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 272.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 480.000000;
+
+const PROGMEM uint16_t z_neg[] = {0xC9B1, 0x96B3, 0xD990, 0x96B3, 0xD990, 0xA8D0, 0xE17F, 0xA8D0, 0xD1A0, 0xB1DF, 0xC1C2, 0xA8D0, 0xC9B1, 0xA8D0, 0xC9B1, 0x96B3};
+const PROGMEM uint16_t z_pos[] = {0xC9B1, 0x8DA4, 0xD990, 0x8DA4, 0xD990, 0x7B86, 0xE17F, 0x7B86, 0xD1A0, 0x7277, 0xC1C2, 0x7B86, 0xC9B1, 0x7B86, 0xC9B1, 0x8DA4};
+const PROGMEM uint16_t y_neg[] = {0x5037, 0x9979, 0x6264, 0x9979, 0x5529, 0xA92A, 0x5E3F, 0xA92A, 0x4575, 0xB103, 0x39E6, 0xA92A, 0x42FC, 0xA92A, 0x5037, 0x9979};
+const PROGMEM uint16_t y_pos[] = {0x5D72, 0x89C7, 0x6F9F, 0x89C7, 0x7CDA, 0x7A15, 0x85F0, 0x7A15, 0x7A61, 0x723D, 0x6197, 0x7A15, 0x6AAD, 0x7A15, 0x5D72, 0x89C7};
+const PROGMEM uint16_t x_neg[] = {0x513D, 0x8DB3, 0x4AA0, 0x958C, 0x2647, 0x958C, 0x22F8, 0x9979, 0x1769, 0x91A0, 0x3033, 0x89C7, 0x2CE4, 0x8DB3, 0x513D, 0x8DB3};
+const PROGMEM uint16_t x_pos[] = {0x7566, 0x8DB3, 0x6EC9, 0x958C, 0x9322, 0x958C, 0x8FD4, 0x9979, 0xA89E, 0x91A0, 0x9D0E, 0x89C7, 0x99C0, 0x8DB3, 0x7566, 0x8DB3};
+const PROGMEM uint16_t syringe_fluid[] = {0x7D1D, 0x4A0F, 0x87FC, 0x4C0E, 0x8CF4, 0x4C0E, 0x9801, 0x4A0F, 0x9801, 0x1AA2, 0x7D1D, 0x1AA2, 0x7D1D, 0x4A0F};
+const PROGMEM uint16_t syringe[] = {0x83C2, 0x42AA, 0x83C2, 0x43FF, 0x8D2C, 0x43FF, 0x8D2C, 0x42AA, 0xFFFF, 0x83C2, 0x3D54, 0x83C2, 0x3EAA, 0x8D2C, 0x3EAA, 0x8D2C, 0x3D54, 0xFFFF, 0x83C2, 0x37FF, 0x83C2, 0x3954, 0x8D2C, 0x3954, 0x8D2C, 0x37FF, 0xFFFF, 0x83C2, 0x32AA, 0x83C2, 0x33FF, 0x8D2C, 0x33FF, 0x8D2C, 0x32AA, 0xFFFF, 0x83C2, 0x2D54, 0x83C2, 0x2EAA, 0x8D2C, 0x2EAA, 0x8D2C, 0x2D54, 0xFFFF, 0x83C2, 0x27FF, 0x83C2, 0x2955, 0x8D2C, 0x2955, 0x8D2C, 0x27FF, 0xFFFF, 0x83C2, 0x22AA, 0x83C2, 0x23FF, 0x8D2C, 0x23FF, 0x8D2C, 0x22AA, 0xFFFF, 0x7AC7, 0x0F4B, 0x7AC7, 0x134A, 0x855B, 0x134A, 0x855B, 0x1949, 0x7AC7, 0x1949, 0x7AC7, 0x4B40, 0x855B, 0x4D40, 0x855B, 0x533F, 0x88E2, 0x533F, 0x88E2, 0x653C, 0x8C69, 0x673C, 0x8C69, 0x533F, 0x8FF0, 0x533F, 0x8FF0, 0x4D40, 0x9A85, 0x4B40, 0x9A85, 0x1949, 0x8FF0, 0x1949, 0x8FF0, 0x134A, 0x9A85, 0x134A, 0x9A85, 0x0F4B, 0xFFFF, 0x88E2, 0x134A, 0x8C69, 0x134A, 0x8C69, 0x1949, 0x88E2, 0x1949, 0x88E2, 0x134A, 0xFFFF, 0x7E4D, 0x1B49, 0x96FE, 0x1B49, 0x96FE, 0x4941, 0x8C69, 0x4B40, 0x88E2, 0x4B40, 0x7E4D, 0x4941, 0x7E4D, 0x1B49};
+const PROGMEM uint16_t syringe_outline[] = {0x7AC7, 0x0F4B, 0x7AC7, 0x134A, 0x855B, 0x134A, 0x855B, 0x1949, 0x7AC7, 0x1949, 0x7AC7, 0x4B40, 0x855B, 0x4D40, 0x855B, 0x533F, 0x88E2, 0x533F, 0x88E2, 0x653C, 0x8C69, 0x673C, 0x8C69, 0x533F, 0x8FF0, 0x533F, 0x8FF0, 0x4D40, 0x9A85, 0x4B40, 0x9A85, 0x1949, 0x8FF0, 0x1949, 0x8FF0, 0x134A, 0x9A85, 0x134A, 0x9A85, 0x0F4B, 0x7AC7, 0x0F4B};
+const PROGMEM uint16_t padlock[] = {0x645A, 0x8017, 0x5F9E, 0x80A1, 0x5BBA, 0x821B, 0x5911, 0x844A, 0x580A, 0x86F7, 0x580A, 0x8931, 0x5970, 0x8A98, 0x5C49, 0x8A98, 0x5DB0, 0x8931, 0x5DB0, 0x8703, 0x5E3C, 0x858E, 0x5FAA, 0x845F, 0x61C5, 0x8394, 0x645A, 0x834A, 0x66F0, 0x8394, 0x690C, 0x845F, 0x6A7A, 0x858D, 0x6B07, 0x8703, 0x6B07, 0x8F23, 0x57C8, 0x8F23, 0x551E, 0x8FC3, 0x5404, 0x9145, 0x5404, 0x9C8F, 0x551E, 0x9E11, 0x57C8, 0x9EB1, 0x70EE, 0x9EB1, 0x7398, 0x9E11, 0x74B2, 0x9C8F, 0x74B2, 0x9145, 0x7398, 0x8FC3, 0x70EE, 0x8F23, 0x70AC, 0x86FA, 0x6FA5, 0x844A, 0x6CFD, 0x821B, 0x6917, 0x80A1};
+const PROGMEM uint16_t home_z[] = {0xD6C9, 0x80CC, 0xBB53, 0x905B, 0xC231, 0x905B, 0xC231, 0x9FEB, 0xCFEC, 0x9FEB, 0xCFEC, 0x9823, 0xDDA7, 0x9823, 0xDDA7, 0x9FEB, 0xEB62, 0x9FEB, 0xEB62, 0x905B, 0xF240, 0x905B, 0xE7A3, 0x8A58, 0xE7A3, 0x82CD, 0xE0C6, 0x82CD, 0xE0C6, 0x8674};
+const PROGMEM uint16_t home_e[] = {0xB94F, 0x25AA, 0x9DD8, 0x353A, 0xA4B6, 0x353A, 0xA4B6, 0x44C9, 0xB271, 0x44C9, 0xB271, 0x3D02, 0xC02C, 0x3D02, 0xC02C, 0x44C9, 0xCDE7, 0x44C9, 0xCDE7, 0x353A, 0xD4C5, 0x353A, 0xCA28, 0x2F36, 0xCA28, 0x27AB, 0xC34B, 0x27AB, 0xC34B, 0x2B53};
+const PROGMEM uint16_t bed_icon[] = {0x1764, 0x2C4C, 0x6135, 0x2C4C, 0x6135, 0x40A8, 0x1764, 0x40A8};
+const PROGMEM uint16_t actual_temp[] = {0x1764, 0x466F, 0x6135, 0x466F, 0x6135, 0x5ACB, 0x1764, 0x5ACB};
+const PROGMEM uint16_t target_temp[] = {0x1764, 0x1228, 0x6135, 0x1228, 0x6135, 0x2684, 0x1764, 0x2684};
+const PROGMEM uint16_t fine_label[] = {0x1AA7, 0xC6D2, 0x9387, 0xC6D2, 0x9387, 0xD316, 0x1AA7, 0xD316};
+const PROGMEM uint16_t fine_toggle[] = {0x9C10, 0xC6D2, 0xE4A3, 0xC6D2, 0xE4A3, 0xD316, 0x9C10, 0xD316};
+const PROGMEM uint16_t usb_btn[] = {0x0B68, 0xE880, 0x7B1A, 0xE880, 0x7B1A, 0xF94B, 0x0B68, 0xF94B, 0x0B68, 0xE880};
+const PROGMEM uint16_t menu_btn[] = {0x84E3, 0xE880, 0xF495, 0xE880, 0xF495, 0xF94B, 0x84E3, 0xF94B, 0x84E3, 0xE880};
+const PROGMEM uint16_t e_pos[] = {0xC9B1, 0x3B2D, 0xD990, 0x3B2D, 0xD990, 0x4D4B, 0xE17F, 0x4D4B, 0xD1A0, 0x565A, 0xC1C2, 0x4D4B, 0xC9B1, 0x4D4B, 0xC9B1, 0x3B2D};
+const PROGMEM uint16_t e_neg[] = {0xC9B1, 0x321E, 0xD990, 0x321E, 0xD990, 0x2000, 0xE17F, 0x2000, 0xD1A0, 0x16F1, 0xC1C2, 0x2000, 0xC9B1, 0x2000, 0xC9B1, 0x321E};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printing_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printing_dialog_box.cpp
new file mode 100644
index 0000000..65b996d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printing_dialog_box.cpp
@@ -0,0 +1,151 @@
+/*******************************
+ * bio_printing_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+#include "../ftdi_eve_lib/extras/circular_progress.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 9
+
+void BioPrintingDialogBox::draw_status_message(draw_mode_t what, const char* message) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+ draw_text_box(cmd, BTN_POS(1,2), BTN_SIZE(2,2), message, OPT_CENTER, font_large);
+ }
+}
+
+void BioPrintingDialogBox::draw_progress(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.font(font_large)
+ .text(BTN_POS(1,1), BTN_SIZE(2,2), isPrinting() ? F("Printing...") : F("Finished."))
+ .tag(1)
+ .font(font_xlarge);
+
+ draw_circular_progress(cmd, BTN_POS(1,4), BTN_SIZE(2,3), getProgress_percent(), theme_dark, theme_darkest);
+ }
+}
+
+void BioPrintingDialogBox::draw_time_remaining(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ const uint32_t elapsed = getProgress_seconds_elapsed();
+ const uint8_t hrs = elapsed/3600;
+ const uint8_t min = (elapsed/60)%60;
+
+ char time_str[10];
+ sprintf_P(time_str, PSTR("%02dh %02dm"), hrs, min);
+
+ CommandProcessor cmd;
+ cmd.font(font_large)
+ .text(BTN_POS(1,7), BTN_SIZE(2,2), time_str);
+ }
+}
+
+void BioPrintingDialogBox::draw_interaction_buttons(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .colors(isPrinting() ? action_btn : normal_btn)
+ .tag(2).button(BTN_POS(1,9), BTN_SIZE(1,1), F("Menu"))
+ .enabled(isPrinting() ? TERN0(SDSUPPORT, isPrintingFromMedia()) : 1)
+ .tag(3)
+ .colors(isPrinting() ? normal_btn : action_btn)
+ .button(BTN_POS(2,9), BTN_SIZE(1,1), isPrinting() ? F("Cancel") : F("Back"));
+ }
+}
+
+void BioPrintingDialogBox::onRedraw(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ draw_progress(FOREGROUND);
+ draw_time_remaining(FOREGROUND);
+ draw_interaction_buttons(FOREGROUND);
+ }
+}
+
+bool BioPrintingDialogBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_SCREEN(FeedratePercentScreen); break;
+ case 2: GOTO_SCREEN(TuneMenu); break;
+ case 3:
+ if (isPrinting())
+ GOTO_SCREEN(ConfirmAbortPrintDialogBox);
+ else
+ GOTO_SCREEN(StatusScreen);
+ break;
+ default: return false;
+ }
+ return true;
+}
+
+void BioPrintingDialogBox::setStatusMessage(progmem_str message) {
+ char buff[strlen_P((const char*)message)+1];
+ strcpy_P(buff, (const char*) message);
+ setStatusMessage(buff);
+}
+
+void BioPrintingDialogBox::setStatusMessage(const char* message) {
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true));
+
+ draw_status_message(BACKGROUND, message);
+ draw_progress(BACKGROUND);
+ draw_time_remaining(BACKGROUND);
+ draw_interaction_buttons(BACKGROUND);
+ storeBackground();
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOLNPAIR("New status message: ", message);
+ #endif
+
+ if (AT_SCREEN(BioPrintingDialogBox))
+ current_screen.onRefresh();
+}
+
+void BioPrintingDialogBox::onIdle() {
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+
+void BioPrintingDialogBox::show() {
+ GOTO_SCREEN(BioPrintingDialogBox);
+}
+
+#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_status_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_status_screen.cpp
new file mode 100644
index 0000000..90d8d62
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_status_screen.cpp
@@ -0,0 +1,379 @@
+/*************************
+ * bio_status_screen.cpp *
+ *************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+#include "../ftdi_eve_lib/extras/poly_ui.h"
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #include "bio_printer_ui_portrait.h"
+#else
+ #include "bio_printer_ui_landscape.h"
+#endif
+
+#define GRID_COLS 2
+#define GRID_ROWS 9
+
+#define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0]))
+
+const uint8_t shadow_depth = 5;
+const float max_speed = 1.00;
+const float min_speed = 0.02;
+const float emax_speed = 2.00;
+const float emin_speed = 0.70;
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+float StatusScreen::increment;
+bool StatusScreen::jog_xy;
+bool StatusScreen::fine_motion;
+
+void StatusScreen::unlockMotors() {
+ injectCommands_P(PSTR("M84 XY"));
+ jog_xy = false;
+}
+
+void StatusScreen::draw_temperature(draw_mode_t what) {
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ int16_t x, y, h, v;
+
+ cmd.tag(15);
+
+ if (what & BACKGROUND) {
+ cmd.cmd(COLOR_RGB(bg_color));
+
+ // The LulzBot Bio shows the temperature for
+ // the bed.
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ // Draw touch surfaces
+ ui.bounds(POLY(target_temp), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+ ui.bounds(POLY(actual_temp), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+ #else
+ ui.bounds(POLY(bed_temp), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+ #endif
+ ui.bounds(POLY(bed_icon), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+
+ // Draw bed icon
+ cmd.cmd(BITMAP_SOURCE(Bed_Heat_Icon_Info))
+ .cmd(BITMAP_LAYOUT(Bed_Heat_Icon_Info))
+ .cmd(BITMAP_SIZE (Bed_Heat_Icon_Info))
+ .cmd(COLOR_RGB(shadow_rgb))
+ .icon (x + 2, y + 2, h, v, Bed_Heat_Icon_Info, icon_scale * 2)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .icon (x, y, h, v, Bed_Heat_Icon_Info, icon_scale * 2);
+
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd); // Restore font bitmap handles
+ #endif
+ }
+
+ if (what & FOREGROUND) {
+ char str[15];
+ cmd.cmd(COLOR_RGB(bg_text_enabled));
+ cmd.font(font_medium);
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ if (!isHeaterIdle(BED) && getTargetTemp_celsius(BED) > 0)
+ format_temp(str, getTargetTemp_celsius(BED));
+ else
+ strcpy_P(str, GET_TEXT(MSG_BED));
+
+ ui.bounds(POLY(target_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ format_temp(str, getActualTemp_celsius(BED));
+ ui.bounds(POLY(actual_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ #else
+ if (!isHeaterIdle(BED) && getTargetTemp_celsius(BED) > 0)
+ format_temp_and_temp(str, getActualTemp_celsius(BED), getTargetTemp_celsius(BED));
+ else
+ format_temp_and_idle(str, getActualTemp_celsius(BED));
+
+ ui.bounds(POLY(bed_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ #endif
+ }
+}
+
+void StatusScreen::draw_syringe(draw_mode_t what) {
+ int16_t x, y, h, v;
+ const float fill_level = (
+ #ifdef E_MAX_POS
+ 1.0 - min(1.0, max(0.0, getAxisPosition_mm(E0) / E_MAX_POS))
+ #else
+ 0.75
+ #endif
+ );
+ const bool e_homed = TERN1(TOUCH_UI_LULZBOT_BIO, isAxisPositionKnown(E0));
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ if (what & BACKGROUND) {
+ // Paint the shadow for the syringe
+ ui.color(shadow_rgb);
+ ui.shadow(POLY(syringe_outline), shadow_depth);
+ }
+
+ if (what & FOREGROUND && e_homed) {
+ // Paint the syringe icon
+ ui.color(syringe_rgb);
+ ui.fill(POLY(syringe_outline));
+
+ ui.color(fluid_rgb);
+ ui.bounds(POLY(syringe_fluid), x, y, h, v);
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(SCISSOR_XY(x,y + v * (1.0 - fill_level)));
+ cmd.cmd(SCISSOR_SIZE(h, v * fill_level));
+ ui.fill(POLY(syringe_fluid), false);
+ cmd.cmd(RESTORE_CONTEXT());
+
+ ui.color(stroke_rgb);
+ ui.fill(POLY(syringe));
+ }
+}
+
+void StatusScreen::draw_arrows(draw_mode_t what) {
+ const bool e_homed = TERN1(TOUCH_UI_LULZBOT_BIO, isAxisPositionKnown(E0)),
+ z_homed = isAxisPositionKnown(Z);
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ ui.button_fill (fill_rgb);
+ ui.button_stroke(stroke_rgb, 28);
+ ui.button_shadow(shadow_rgb, shadow_depth);
+
+ constexpr uint8_t style = PolyUI::REGULAR;
+
+ if ((what & BACKGROUND) || jog_xy) {
+ ui.button(1, POLY(x_neg), style);
+ ui.button(2, POLY(x_pos), style);
+ ui.button(3, POLY(y_neg), style);
+ ui.button(4, POLY(y_pos), style);
+ }
+
+ if ((what & BACKGROUND) || z_homed) {
+ ui.button(5, POLY(z_neg), style);
+ ui.button(6, POLY(z_pos), style);
+ }
+
+ if ((what & BACKGROUND) || e_homed) {
+ ui.button(7, POLY(e_neg), style);
+ ui.button(8, POLY(e_pos), style);
+ }
+}
+
+void StatusScreen::draw_fine_motion(draw_mode_t what) {
+ int16_t x, y, h, v;
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ cmd.font(
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ font_medium
+ #else
+ font_small
+ #endif
+ )
+ .tag(16);
+
+ if (what & BACKGROUND) {
+ ui.bounds(POLY(fine_label), x, y, h, v);
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .text(x, y, h, v, GET_TEXT_F(MSG_FINE_MOTION));
+ }
+
+ if (what & FOREGROUND) {
+ ui.bounds(POLY(fine_toggle), x, y, h, v);
+ cmd.colors(ui_toggle)
+ .toggle2(x, y, h, v, GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), fine_motion);
+ }
+}
+
+void StatusScreen::draw_overlay_icons(draw_mode_t what) {
+ const bool e_homed = TERN1(TOUCH_UI_LULZBOT_BIO, isAxisPositionKnown(E0)),
+ z_homed = isAxisPositionKnown(Z);
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ if (what & FOREGROUND) {
+ ui.button_fill (fill_rgb);
+ ui.button_stroke(stroke_rgb, 28);
+ ui.button_shadow(shadow_rgb, shadow_depth);
+
+ constexpr uint8_t style = PolyUI::REGULAR;
+ if (!jog_xy) ui.button(12, POLY(padlock), style);
+ if (!e_homed) ui.button(13, POLY(home_e), style);
+ if (!z_homed) ui.button(14, POLY(home_z), style);
+ }
+}
+
+void StatusScreen::draw_buttons(draw_mode_t what) {
+ int16_t x, y, h, v;
+
+ const bool has_media = isMediaInserted() && !isPrintingFromMedia();
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ ui.bounds(POLY(usb_btn), x, y, h, v);
+ cmd.font(font_medium)
+ .colors(normal_btn)
+ .enabled(has_media)
+ .colors(has_media ? action_btn : normal_btn)
+ .tag(9).button(x, y, h, v,
+ isPrintingFromMedia() ?
+ GET_TEXT_F(MSG_PRINTING) :
+ GET_TEXT_F(MSG_BUTTON_MEDIA)
+ );
+
+ ui.bounds(POLY(menu_btn), x, y, h, v);
+ cmd.colors(!has_media ? action_btn : normal_btn).tag(10).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_MENU));
+}
+
+void StatusScreen::loadBitmaps() {
+ // Load the bitmaps for the status screen
+ constexpr uint32_t base = ftdi_memory_map::RAM_G;
+ CLCD::mem_write_pgm(base + Bed_Heat_Icon_Info.RAMG_offset, Bed_Heat_Icon, sizeof(Bed_Heat_Icon));
+
+ // Load fonts for internationalization
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_data(base + UTF8_FONT_OFFSET);
+ #endif
+}
+
+void StatusScreen::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ draw_syringe(what);
+ draw_temperature(what);
+ draw_arrows(what);
+ draw_overlay_icons(what);
+ draw_buttons(what);
+ draw_fine_motion(what);
+}
+
+bool StatusScreen::onTouchStart(uint8_t) {
+ increment = 0;
+ return true;
+}
+
+bool StatusScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 12:
+ if (!jog_xy) {
+ jog_xy = true;
+ injectCommands_P(PSTR("M17"));
+ }
+ jog({ 0, 0, 0 });
+ break;
+ case 5:
+ case 6:
+ jog({ 0, 0, 0 });
+ break;
+ case 9: GOTO_SCREEN(FilesScreen); break;
+ case 10: GOTO_SCREEN(MainMenu); break;
+ case 13: GOTO_SCREEN(BioConfirmHomeE); break;
+ case 14: SpinnerDialogBox::enqueueAndWait_P(F("G28Z")); break;
+ case 15: GOTO_SCREEN(TemperatureScreen); break;
+ case 16: fine_motion = !fine_motion; break;
+ default: return false;
+ }
+ // If a passcode is enabled, the LockScreen will prevent the
+ // user from proceeding.
+ LockScreen::check_passcode();
+ return true;
+}
+
+bool StatusScreen::onTouchHeld(uint8_t tag) {
+ if (tag >= 1 && tag <= 4 && !jog_xy) return false;
+ const float s = min_speed + (fine_motion ? 0 : (max_speed - min_speed) * sq(increment));
+ switch (tag) {
+ case 1: jog({-s, 0, 0}); break;
+ case 2: jog({ s, 0, 0}); break;
+ case 4: jog({ 0, -s, 0}); break; // NOTE: Y directions inverted because bed rather than needle moves
+ case 3: jog({ 0, s, 0}); break;
+ case 5: jog({ 0, 0, -s}); break;
+ case 6: jog({ 0, 0, s}); break;
+ case 7: case 8:
+ {
+ if (ExtUI::isMoving()) return false;
+ const feedRate_t feedrate = emin_speed + (fine_motion ? 0 : (emax_speed - emin_speed) * sq(increment));
+ const float increment = 0.25 * feedrate * (tag == 7 ? -1 : 1);
+ MoveAxisScreen::setManualFeedrate(E0, feedrate);
+ UI_INCREMENT(AxisPosition_mm, E0);
+ current_screen.onRefresh();
+ break;
+ }
+ default:
+ return false;
+ }
+ increment = min(1.0f, increment + 0.1f);
+ return false;
+}
+
+void StatusScreen::setStatusMessage(progmem_str pstr) {
+ BioPrintingDialogBox::setStatusMessage(pstr);
+}
+
+void StatusScreen::setStatusMessage(const char * const str) {
+ BioPrintingDialogBox::setStatusMessage(str);
+}
+
+void StatusScreen::onIdle() {
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ if (!EventLoop::is_touch_held())
+ onRefresh();
+ if (isPrintingFromMedia())
+ BioPrintingDialogBox::show();
+ refresh_timer.start();
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_tune_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_tune_menu.cpp
new file mode 100644
index 0000000..dacc1cb
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_tune_menu.cpp
@@ -0,0 +1,79 @@
+/*********************
+ * bio_tune_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+void TuneMenu::onRedraw(draw_mode_t what) {
+ #define GRID_ROWS 8
+ #define GRID_COLS 2
+
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+ .font(font_large)
+ .text( BTN_POS(1,1), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_MENU));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .enabled( isPrinting()).tag(2).button(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_SPEED))
+ .tag(3).button(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_BED_TEMPERATURE))
+ .enabled(TERN_(BABYSTEPPING, true))
+ .tag(4).button(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_NUDGE_NOZZLE))
+ .enabled(!isPrinting()).tag(5).button(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_MOVE_TO_HOME))
+ .enabled(!isPrinting()).tag(6).button(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_RAISE_PLUNGER))
+ .enabled(!isPrinting()).tag(7).button(BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_RELEASE_XY_AXIS))
+ .colors(action_btn) .tag(1).button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_BACK));
+ }
+ #undef GRID_COLS
+ #undef GRID_ROWS
+}
+
+bool TuneMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2: GOTO_SCREEN(FeedratePercentScreen); break;
+ case 3: GOTO_SCREEN(TemperatureScreen); break;
+ case 4: GOTO_SCREEN(NudgeNozzleScreen); break;
+ case 5: GOTO_SCREEN(BioConfirmHomeXYZ); break;
+ case 6: SpinnerDialogBox::enqueueAndWait_P(F("G0 E0 F120")); break;
+ case 7: StatusScreen::unlockMotors(); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/boot_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/boot_screen.cpp
new file mode 100644
index 0000000..a6a8705
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/boot_screen.cpp
@@ -0,0 +1,130 @@
+/*******************
+ * boot_screen.cpp *
+ *******************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+#include "../ftdi_eve_lib/extras/poly_ui.h"
+#include "../archim2-flash/flash_storage.h"
+
+#if ENABLED(SHOW_CUSTOM_BOOTSCREEN)
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #include "../theme/bootscreen_logo_portrait.h"
+ #else
+ #include "../theme/_bootscreen_landscape.h"
+ #endif
+#else
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #include "../theme/marlin_bootscreen_portrait.h"
+ #else
+ #include "../theme/marlin_bootscreen_landscape.h"
+ #endif
+#endif
+
+using namespace FTDI;
+using namespace Theme;
+
+void BootScreen::onRedraw(draw_mode_t) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(0x000000));
+ cmd.cmd(CLEAR(true,true,true));
+
+ CLCD::turn_on_backlight();
+ SoundPlayer::set_volume(255);
+}
+
+void BootScreen::onIdle() {
+ if (CLCD::is_touching()) {
+ // If the user is touching the screen at startup, then
+ // assume the user wants to re-calibrate the screen.
+ // This gives the user the ability to recover a
+ // miscalibration that has been stored to EEPROM.
+
+ // Also reset display parameters to defaults, just
+ // in case the display is borked.
+ InterfaceSettingsScreen::failSafeSettings();
+
+ StatusScreen::loadBitmaps();
+ StatusScreen::setStatusMessage(GET_TEXT_F(WELCOME_MSG));
+ GOTO_SCREEN(TouchCalibrationScreen);
+ current_screen.forget();
+ PUSH_SCREEN(StatusScreen);
+ }
+ else {
+ if (!UIFlashStorage::is_valid()) {
+ StatusScreen::loadBitmaps();
+ SpinnerDialogBox::show(GET_TEXT_F(MSG_PLEASE_WAIT));
+ UIFlashStorage::format_flash();
+ SpinnerDialogBox::hide();
+ }
+
+ #if DISABLED(TOUCH_UI_NO_BOOTSCREEN)
+ if (UIData::animations_enabled()) {
+ // If there is a startup video in the flash SPI, play
+ // that, otherwise show a static splash screen.
+ if (!MediaPlayerScreen::playBootMedia())
+ showSplashScreen();
+ }
+ #endif
+
+ StatusScreen::loadBitmaps();
+
+ #if ENABLED(TOUCH_UI_LULZBOT_BIO)
+ GOTO_SCREEN(BioConfirmHomeXYZ);
+ current_screen.forget();
+ PUSH_SCREEN(StatusScreen);
+ PUSH_SCREEN(BioConfirmHomeE);
+ #elif NUM_LANGUAGES > 1
+ StatusScreen::setStatusMessage(GET_TEXT_F(WELCOME_MSG));
+ GOTO_SCREEN(LanguageMenu);
+ #else
+ StatusScreen::setStatusMessage(GET_TEXT_F(WELCOME_MSG));
+ GOTO_SCREEN(StatusScreen);
+ #endif
+ }
+}
+
+void BootScreen::showSplashScreen() {
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART);
+ cmd.cmd(CLEAR_COLOR_RGB(LOGO_BACKGROUND));
+ cmd.cmd(CLEAR(true,true,true));
+
+ #define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0]))
+ #define LOGO_PAINT_PATH(rgb, path) cmd.cmd(COLOR_RGB(rgb)); ui.fill(POLY(path));
+
+ PolyUI ui(cmd);
+
+ LOGO_PAINT_PATHS
+
+ cmd.cmd(DL::DL_DISPLAY);
+ cmd.cmd(CMD_SWAP);
+ cmd.execute();
+
+ ExtUI::delay_ms(2500);
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/case_light_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/case_light_screen.cpp
new file mode 100644
index 0000000..5b2b7d4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/case_light_screen.cpp
@@ -0,0 +1,62 @@
+/*************************
+ * case_light_screen.cpp *
+ *************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, CASE_LIGHT_ENABLE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void CaseLightScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.heading( GET_TEXT_F(MSG_CASE_LIGHT));
+ w.toggle( 2, GET_TEXT_F(MSG_LEDS), getCaseLightState());
+ #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS)
+ w.precision(0).units(GET_TEXT_F(MSG_UNITS_PERCENT))
+ .adjuster(10, GET_TEXT_F(MSG_CASE_LIGHT_BRIGHTNESS), getCaseLightBrightness_percent());
+ w.precision(0).increments();
+ #endif
+}
+
+bool CaseLightScreen::onTouchHeld(uint8_t tag) {
+ using namespace ExtUI;
+ #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS)
+ const float increment = getIncrement();
+ #endif
+ switch (tag) {
+ case 2: setCaseLightState(!getCaseLightState()); break;
+ #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS)
+ case 10: UI_DECREMENT(CaseLightBrightness_percent); break;
+ case 11: UI_INCREMENT(CaseLightBrightness_percent); break;
+ #endif
+ default:
+ return false;
+ }
+
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/change_filament_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/change_filament_screen.cpp
new file mode 100644
index 0000000..624bb26
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/change_filament_screen.cpp
@@ -0,0 +1,330 @@
+/******************************
+ * change_filament_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace ExtUI;
+using namespace FTDI;
+using namespace Theme;
+
+#ifdef TOUCH_UI_PORTRAIT
+ #define GRID_COLS 2
+ #define GRID_ROWS 11
+ #define E_TEMP_POS BTN_POS(2,7), BTN_SIZE(1,1)
+ #define E_TEMP_LBL_POS BTN_POS(1,7), BTN_SIZE(1,1)
+ #define UNLD_LABL_POS BTN_POS(1,8), BTN_SIZE(1,1)
+ #define LOAD_LABL_POS BTN_POS(2,8), BTN_SIZE(1,1)
+ #define UNLD_MOMN_POS BTN_POS(1,9), BTN_SIZE(1,1)
+ #define LOAD_MOMN_POS BTN_POS(2,9), BTN_SIZE(1,1)
+ #define UNLD_CONT_POS BTN_POS(1,10), BTN_SIZE(1,1)
+ #define LOAD_CONT_POS BTN_POS(2,10), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(1,11), BTN_SIZE(2,1)
+#else
+ #define GRID_COLS 4
+ #define GRID_ROWS 6
+ #define E_TEMP_POS BTN_POS(3,2), BTN_SIZE(2,1)
+ #define E_TEMP_LBL_POS BTN_POS(3,1), BTN_SIZE(2,1)
+ #define UNLD_LABL_POS BTN_POS(3,3), BTN_SIZE(1,1)
+ #define LOAD_LABL_POS BTN_POS(4,3), BTN_SIZE(1,1)
+ #define UNLD_MOMN_POS BTN_POS(3,4), BTN_SIZE(1,1)
+ #define LOAD_MOMN_POS BTN_POS(4,4), BTN_SIZE(1,1)
+ #define UNLD_CONT_POS BTN_POS(3,5), BTN_SIZE(1,1)
+ #define LOAD_CONT_POS BTN_POS(4,5), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(3,6), BTN_SIZE(2,1)
+#endif
+#define REMOVAL_TEMP_LBL_POS BTN_POS(1,3), BTN_SIZE(2,1)
+#define GRADIENT_POS BTN_POS(1,4), BTN_SIZE(1,3)
+#define LOW_TEMP_POS BTN_POS(2,6), BTN_SIZE(1,1)
+#define MED_TEMP_POS BTN_POS(2,5), BTN_SIZE(1,1)
+#define HIG_TEMP_POS BTN_POS(2,4), BTN_SIZE(1,1)
+#define HEATING_LBL_POS BTN_POS(1,6), BTN_SIZE(1,1)
+#define CAUTION_LBL_POS BTN_POS(1,4), BTN_SIZE(1,1)
+#define HOT_LBL_POS BTN_POS(1,6), BTN_SIZE(1,1)
+#define E_SEL_LBL_POS BTN_POS(1,1), BTN_SIZE(2,1)
+#define E1_SEL_POS BTN_POS(1,2), BTN_SIZE(1,1)
+#define E2_SEL_POS BTN_POS(2,2), BTN_SIZE(1,1)
+
+#define COOL_TEMP 40
+#define LOW_TEMP 180
+#define MED_TEMP 200
+#define HIGH_TEMP 220
+
+/****************** COLOR SCALE ***********************/
+
+uint32_t getWarmColor(uint16_t temp, uint16_t cool, uint16_t low, uint16_t med, uint16_t high) {
+ rgb_t R0, R1, mix;
+
+ float t;
+ if (temp < cool) {
+ R0 = cool_rgb;
+ R1 = low_rgb;
+ t = 0;
+ }
+ else if (temp < low) {
+ R0 = cool_rgb;
+ R1 = low_rgb;
+ t = (float(temp)-cool)/(low-cool);
+ }
+ else if (temp < med) {
+ R0 = low_rgb;
+ R1 = med_rgb;
+ t = (float(temp)-low)/(med-low);
+ }
+ else if (temp < high) {
+ R0 = med_rgb;
+ R1 = high_rgb;
+ t = (float(temp)-med)/(high-med);
+ }
+ else if (temp >= high) {
+ R0 = med_rgb;
+ R1 = high_rgb;
+ t = 1;
+ }
+ rgb_t::lerp(t, R0, R1, mix);
+ return mix;
+}
+
+void ChangeFilamentScreen::drawTempGradient(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
+ CommandProcessor cmd;
+ cmd.cmd(SCISSOR_XY (x, y))
+ .cmd(SCISSOR_SIZE (w, h/2))
+ .gradient (x, y, high_rgb, x, y+h/2, med_rgb)
+ .cmd(SCISSOR_XY (x, y+h/2))
+ .cmd(SCISSOR_SIZE (w, h/2))
+ .gradient (x, y+h/2, med_rgb, x, y+h, low_rgb)
+ .cmd(SCISSOR_XY ())
+ .cmd(SCISSOR_SIZE ());
+}
+
+void ChangeFilamentScreen::onEntry() {
+ BaseScreen::onEntry();
+ screen_data.ChangeFilament.e_tag = ExtUI::getActiveTool() + 10;
+ screen_data.ChangeFilament.t_tag = 0;
+ screen_data.ChangeFilament.repeat_tag = 0;
+ screen_data.ChangeFilament.saved_extruder = getActiveTool();
+ #if FILAMENT_UNLOAD_PURGE_LENGTH > 0
+ screen_data.ChangeFilament.need_purge = true;
+ #endif
+}
+
+void ChangeFilamentScreen::onExit() {
+ setActiveTool(screen_data.ChangeFilament.saved_extruder, true);
+}
+
+void ChangeFilamentScreen::onRedraw(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+ .font(TERN(TOUCH_UI_PORTRAIT, font_large, font_medium))
+ .text(E_SEL_LBL_POS, GET_TEXT_F(MSG_EXTRUDER_SELECTION))
+ .text(E_TEMP_LBL_POS, GET_TEXT_F(MSG_CURRENT_TEMPERATURE))
+ .text(REMOVAL_TEMP_LBL_POS, GET_TEXT_F(MSG_REMOVAL_TEMPERATURE));
+ drawTempGradient(GRADIENT_POS);
+ }
+
+ if (what & FOREGROUND) {
+ char str[15];
+ const extruder_t e = getExtruder();
+
+ if (isHeaterIdle(e))
+ format_temp_and_idle(str, getActualTemp_celsius(e));
+ else
+ format_temp_and_temp(str, getActualTemp_celsius(e), getTargetTemp_celsius(e));
+
+ const rgb_t tcol = getWarmColor(getActualTemp_celsius(e), COOL_TEMP, LOW_TEMP, MED_TEMP, HIGH_TEMP);
+ cmd.cmd(COLOR_RGB(tcol))
+ .tag(15)
+ .rectangle(E_TEMP_POS)
+ .cmd(COLOR_RGB(tcol.luminance() > 128 ? 0x000000 : 0xFFFFFF))
+ .font(font_medium)
+ .text(E_TEMP_POS, str)
+ .colors(normal_btn);
+
+ const bool t_ok = getActualTemp_celsius(e) > getSoftenTemp() - 10;
+
+ if (screen_data.ChangeFilament.t_tag && !t_ok) {
+ cmd.text(HEATING_LBL_POS, GET_TEXT_F(MSG_HEATING));
+ } else if (getActualTemp_celsius(e) > 100) {
+ cmd.cmd(COLOR_RGB(0xFF0000))
+ .text(CAUTION_LBL_POS, GET_TEXT_F(MSG_CAUTION))
+ .colors(normal_btn)
+ .text(HOT_LBL_POS, GET_TEXT_F(MSG_HOT));
+ }
+
+ #define TOG_STYLE(A) colors(A ? action_btn : normal_btn)
+
+ const bool tog2 = screen_data.ChangeFilament.t_tag == 2;
+ const bool tog3 = screen_data.ChangeFilament.t_tag == 3;
+ const bool tog4 = screen_data.ChangeFilament.t_tag == 4;
+ const bool tog10 = screen_data.ChangeFilament.e_tag == 10;
+ #if HAS_MULTI_HOTEND
+ const bool tog11 = screen_data.ChangeFilament.e_tag == 11;
+ #endif
+
+ cmd.TOG_STYLE(tog10)
+ .tag(10).button (E1_SEL_POS, F("1"))
+ #if HOTENDS < 2
+ .enabled(false)
+ #else
+ .TOG_STYLE(tog11)
+ #endif
+ .tag(11).button (E2_SEL_POS, F("2"));
+
+ if (!t_ok) reset_menu_timeout();
+
+ const bool tog7 = screen_data.ChangeFilament.repeat_tag == 7;
+ const bool tog8 = screen_data.ChangeFilament.repeat_tag == 8;
+
+ {
+ char str[30];
+ format_temp(str, LOW_TEMP);
+ cmd.tag(2) .TOG_STYLE(tog2).button (LOW_TEMP_POS, str);
+
+ format_temp(str, MED_TEMP);
+ cmd.tag(3) .TOG_STYLE(tog3).button (MED_TEMP_POS, str);
+
+ format_temp(str, HIGH_TEMP);
+ cmd.tag(4) .TOG_STYLE(tog4).button (HIG_TEMP_POS, str);
+ }
+
+ cmd.cmd(COLOR_RGB(t_ok ? bg_text_enabled : bg_text_disabled))
+ .tag(0) .text (UNLD_LABL_POS, GET_TEXT_F(MSG_UNLOAD_FILAMENT))
+ .text (LOAD_LABL_POS, GET_TEXT_F(MSG_LOAD_FILAMENT))
+ .colors(normal_btn)
+ .tag(5) .enabled(t_ok).button (UNLD_MOMN_POS, GET_TEXT_F(MSG_MOMENTARY))
+ .tag(6) .enabled(t_ok).button (LOAD_MOMN_POS, GET_TEXT_F(MSG_MOMENTARY))
+ .tag(7).TOG_STYLE(tog7).enabled(t_ok).button (UNLD_CONT_POS, GET_TEXT_F(MSG_CONTINUOUS))
+ .tag(8).TOG_STYLE(tog8).enabled(t_ok).button (LOAD_CONT_POS, GET_TEXT_F(MSG_CONTINUOUS))
+ .tag(1).colors(action_btn) .button (BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+uint8_t ChangeFilamentScreen::getSoftenTemp() {
+ switch (screen_data.ChangeFilament.t_tag) {
+ case 2: return LOW_TEMP;
+ case 3: return MED_TEMP;
+ case 4: return HIGH_TEMP;
+ default: return EXTRUDE_MINTEMP;
+ }
+}
+
+ExtUI::extruder_t ChangeFilamentScreen::getExtruder() {
+ switch (screen_data.ChangeFilament.e_tag) {
+ case 13: return ExtUI::E3;
+ case 12: return ExtUI::E2;
+ case 11: return ExtUI::E1;
+ default: return ExtUI::E0;
+ }
+}
+
+void ChangeFilamentScreen::doPurge() {
+ #if FILAMENT_UNLOAD_PURGE_LENGTH > 0
+ constexpr float purge_distance_mm = FILAMENT_UNLOAD_PURGE_LENGTH;
+ if (screen_data.ChangeFilament.need_purge) {
+ screen_data.ChangeFilament.need_purge = false;
+ MoveAxisScreen::setManualFeedrate(getExtruder(), purge_distance_mm);
+ ExtUI::setAxisPosition_mm(ExtUI::getAxisPosition_mm(getExtruder()) + purge_distance_mm, getExtruder());
+ }
+ #endif
+}
+
+bool ChangeFilamentScreen::onTouchStart(uint8_t tag) {
+ // Make the Momentary and Continuous buttons slightly more responsive
+ switch (tag) {
+ case 5: case 6: case 7: case 8:
+ #if FILAMENT_UNLOAD_PURGE_LENGTH > 0
+ if (tag == 5 || tag == 7) doPurge();
+ #endif
+ return ChangeFilamentScreen::onTouchHeld(tag);
+ default:
+ return false;
+ }
+}
+
+bool ChangeFilamentScreen::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2:
+ case 3:
+ case 4:
+ // Change temperature
+ screen_data.ChangeFilament.t_tag = tag;
+ setTargetTemp_celsius(getSoftenTemp(), getExtruder());
+ break;
+ case 7:
+ screen_data.ChangeFilament.repeat_tag = (screen_data.ChangeFilament.repeat_tag == 7) ? 0 : 7;
+ break;
+ case 8:
+ screen_data.ChangeFilament.repeat_tag = (screen_data.ChangeFilament.repeat_tag == 8) ? 0 : 8;
+ break;
+ case 10:
+ case 11:
+ // Change extruder
+ screen_data.ChangeFilament.e_tag = tag;
+ screen_data.ChangeFilament.t_tag = 0;
+ screen_data.ChangeFilament.repeat_tag = 0;
+ #if FILAMENT_UNLOAD_PURGE_LENGTH > 0
+ screen_data.ChangeFilament.need_purge = true;
+ #endif
+ setActiveTool(getExtruder(), true);
+ break;
+ case 15: GOTO_SCREEN(TemperatureScreen); break;
+ }
+ return true;
+}
+
+bool ChangeFilamentScreen::onTouchHeld(uint8_t tag) {
+ if (ExtUI::isMoving()) return false; // Don't allow moves to accumulate
+ constexpr float increment = 1;
+ #define UI_INCREMENT_AXIS(axis) UI_INCREMENT(AxisPosition_mm, axis);
+ #define UI_DECREMENT_AXIS(axis) UI_DECREMENT(AxisPosition_mm, axis);
+ switch (tag) {
+ case 5: case 7: UI_DECREMENT_AXIS(getExtruder()); break;
+ case 6: case 8: UI_INCREMENT_AXIS(getExtruder()); break;
+ default: return false;
+ }
+ #undef UI_DECREMENT_AXIS
+ #undef UI_INCREMENT_AXIS
+ return false;
+}
+
+void ChangeFilamentScreen::onIdle() {
+ reset_menu_timeout();
+ if (screen_data.ChangeFilament.repeat_tag) onTouchHeld(screen_data.ChangeFilament.repeat_tag);
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_advanced_settings_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_advanced_settings_menu.cpp
new file mode 100644
index 0000000..656bf1d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_advanced_settings_menu.cpp
@@ -0,0 +1,102 @@
+/*****************************************
+ * cocoa_press_advance_settings_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_ROWS 4
+#define GRID_COLS 3
+#define STEPS_PER_MM_POS BTN_POS(1,1), BTN_SIZE(1,1)
+#define TMC_CURRENT_POS BTN_POS(2,1), BTN_SIZE(1,1)
+#define LIN_ADVANCE_POS BTN_POS(3,1), BTN_SIZE(1,1)
+#define VELOCITY_POS BTN_POS(1,2), BTN_SIZE(1,1)
+#define ACCELERATION_POS BTN_POS(2,2), BTN_SIZE(1,1)
+#define JERK_POS BTN_POS(3,2), BTN_SIZE(1,1)
+#define DISPLAY_POS BTN_POS(1,3), BTN_SIZE(1,1)
+#define INTERFACE_POS BTN_POS(2,3), BTN_SIZE(1,1)
+#define ENDSTOPS_POS BTN_POS(3,3), BTN_SIZE(1,1)
+#define CASE_LIGHT_POS BTN_POS(1,4), BTN_SIZE(1,1)
+#define RESTORE_DEFAULTS_POS BTN_POS(2,4), BTN_SIZE(1,1)
+#define BACK_POS BTN_POS(3,4), BTN_SIZE(1,1)
+
+void AdvancedSettingsMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ .tag(2) .button(STEPS_PER_MM_POS, GET_TEXT_F(MSG_STEPS_PER_MM))
+ .enabled(ENABLED(HAS_TRINAMIC_CONFIG))
+ .tag(3) .button(TMC_CURRENT_POS, GET_TEXT_F(MSG_TMC_CURRENT))
+ .enabled(ENABLED(LIN_ADVANCE))
+ .tag(4) .button(LIN_ADVANCE_POS, GET_TEXT_F(MSG_LINEAR_ADVANCE))
+ .tag(5) .button(VELOCITY_POS, GET_TEXT_F(MSG_VELOCITY))
+ .tag(6) .button(ACCELERATION_POS, GET_TEXT_F(MSG_ACCELERATION))
+ .tag(7) .button(JERK_POS, GET_TEXT_F(TERN(HAS_JUNCTION_DEVIATION, MSG_JUNCTION_DEVIATION, MSG_JERK)))
+ .tag(8) .button(ENDSTOPS_POS, GET_TEXT_F(MSG_LCD_ENDSTOPS))
+ .tag(9) .button(INTERFACE_POS, GET_TEXT_F(MSG_INTERFACE))
+ .tag(10).button(DISPLAY_POS, GET_TEXT_F(MSG_DISPLAY_MENU))
+ .enabled(ENABLED(CASE_LIGHT_ENABLE))
+ .tag(11).button(CASE_LIGHT_POS, GET_TEXT_F(MSG_CASE_LIGHT))
+ .tag(12).button(RESTORE_DEFAULTS_POS, GET_TEXT_F(MSG_RESTORE_DEFAULTS))
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool AdvancedSettingsMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(StepsScreen); break;
+ #if HAS_TRINAMIC_CONFIG
+ case 3: GOTO_SCREEN(StepperCurrentScreen); break;
+ #endif
+ #if ENABLED(LIN_ADVANCE)
+ case 4: GOTO_SCREEN(LinearAdvanceScreen); break;
+ #endif
+ case 5: GOTO_SCREEN(MaxVelocityScreen); break;
+ case 6: GOTO_SCREEN(DefaultAccelerationScreen); break;
+ case 7: GOTO_SCREEN(TERN(HAS_JUNCTION_DEVIATION, JunctionDeviationScreen, JerkScreen)); break;
+ case 8: GOTO_SCREEN(EndstopStatesScreen); break;
+ case 9: GOTO_SCREEN(InterfaceSettingsScreen); LockScreen::check_passcode(); break;
+ case 10: GOTO_SCREEN(DisplayTuningScreen); break;
+ #if ENABLED(CASE_LIGHT_ENABLE)
+ case 11: GOTO_SCREEN(CaseLightScreen); break;
+ #endif
+ case 12: GOTO_SCREEN(RestoreFailsafeDialogBox); LockScreen::check_passcode(); break;
+ default: return false;
+ }
+ return true;
+}
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_load_chocolate.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_load_chocolate.cpp
new file mode 100644
index 0000000..36dc340
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_load_chocolate.cpp
@@ -0,0 +1,101 @@
+/************************************
+ * cocoa_press_unload_cartridge.cpp *
+ ************************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2020 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && ENABLED(TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace ExtUI;
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 6
+
+#define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1)
+#define DESCRIPTION_POS BTN_POS(1,2), BTN_SIZE(2,3)
+#define CARTRIDGE_OUT_BTN_POS BTN_POS(1,5), BTN_SIZE(1,1)
+#define CARTRIDGE_IN_BTN_POS BTN_POS(2,5), BTN_SIZE(1,1)
+#define BACK_BTN_POS BTN_POS(1,6), BTN_SIZE(2,1)
+
+void LoadChocolateScreen::onRedraw(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+ .font(font_large)
+ .text(TITLE_POS, GET_TEXT_F(MSG_LOAD_CHOCOLATE));
+ draw_text_box(cmd, DESCRIPTION_POS, F(
+ "Drop your chocolate refill into the cartridge. "
+ "Press and hold the Cartridge Out button until "
+ "the plunger adapter is visible at the bottom of "
+ "the extruder. Securely attach a red plunger to "
+ "the plunger adapter and load the cartridge onto "
+ "the plunger. Press and hold Cartridge In button "
+ "until cartridge is fully loaded into the extruder, "
+ "and use the buttons to help follow the locking path "
+ "to lock"),
+ OPT_CENTERY, font_medium);
+ }
+
+ if (what & FOREGROUND) {
+ cmd.font(font_medium)
+ .colors(normal_btn)
+ .tag(2).button(CARTRIDGE_OUT_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_OUT))
+ .tag(3).button(CARTRIDGE_IN_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_IN))
+ .colors(action_btn)
+ .tag(1).button(BACK_BTN_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool LoadChocolateScreen::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ }
+ return true;
+}
+
+bool LoadChocolateScreen::onTouchHeld(uint8_t tag) {
+ if (ExtUI::isMoving()) return false; // Don't allow moves to accumulate
+ constexpr float increment = 0.25;
+ MoveAxisScreen::setManualFeedrate(E0, increment);
+ #define UI_INCREMENT_AXIS(axis) UI_INCREMENT(AxisPosition_mm, axis);
+ #define UI_DECREMENT_AXIS(axis) UI_DECREMENT(AxisPosition_mm, axis);
+ switch (tag) {
+ case 2: UI_DECREMENT_AXIS(E0); break;
+ case 3: UI_INCREMENT_AXIS(E0); break;
+ default: return false;
+ }
+ #undef UI_DECREMENT_AXIS
+ #undef UI_INCREMENT_AXIS
+ return false;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_main_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_main_menu.cpp
new file mode 100644
index 0000000..9c8ad06
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_main_menu.cpp
@@ -0,0 +1,89 @@
+/*****************************
+ * cocoa_press_main_menu.cpp *
+ *****************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_ROWS 4
+#define GRID_COLS 2
+
+#define MOVE_XYZ_POS BTN_POS(1,1), BTN_SIZE(1,1)
+#define TEMPERATURE_POS BTN_POS(2,1), BTN_SIZE(1,1)
+#define ZPROBE_ZOFFSET_POS BTN_POS(1,2), BTN_SIZE(1,1)
+#define MOVE_E_POS BTN_POS(2,2), BTN_SIZE(1,1)
+#define SPEED_POS BTN_POS(1,3), BTN_SIZE(1,1)
+#define ADVANCED_SETTINGS_POS BTN_POS(2,3), BTN_SIZE(1,1)
+#define ABOUT_PRINTER_POS BTN_POS(1,4), BTN_SIZE(1,1)
+#define BACK_POS BTN_POS(2,4), BTN_SIZE(1,1)
+
+void MainMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ .tag(2).button(MOVE_XYZ_POS, GET_TEXT_F(MSG_XYZ_MOVE))
+ .tag(3).button(TEMPERATURE_POS, GET_TEXT_F(MSG_TEMPERATURE))
+ .enabled(BOTH(HAS_LEVELING, HAS_BED_PROBE))
+ .tag(4).button(ZPROBE_ZOFFSET_POS, GET_TEXT_F(MSG_ZPROBE_ZOFFSET))
+ .tag(5).button(MOVE_E_POS, GET_TEXT_F(MSG_E_MOVE))
+ .tag(6).button(SPEED_POS, GET_TEXT_F(MSG_PRINT_SPEED))
+ .tag(7).button(ADVANCED_SETTINGS_POS, GET_TEXT_F(MSG_ADVANCED_SETTINGS))
+ .tag(8).button(ABOUT_PRINTER_POS, GET_TEXT_F(MSG_INFO_MENU))
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool MainMenu::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(MoveXYZScreen); break;
+ case 3: GOTO_SCREEN(TemperatureScreen); break;
+ #if BOTH(HAS_LEVELING, HAS_BED_PROBE)
+ case 4: GOTO_SCREEN(ZOffsetScreen); break;
+ #endif
+ case 5: GOTO_SCREEN(MoveEScreen); break;
+ case 6: GOTO_SCREEN(FeedratePercentScreen); break;
+ case 7: GOTO_SCREEN(AdvancedSettingsMenu); break;
+ case 8: GOTO_SCREEN(AboutScreen); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_e_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_e_screen.cpp
new file mode 100644
index 0000000..61411af
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_e_screen.cpp
@@ -0,0 +1,62 @@
+/*********************************
+ * cocoa_press_move_e_screen.cpp *
+ *********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+
+void MoveEScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(1);
+ w.units(GET_TEXT_F(MSG_UNITS_MM));
+ w.heading( GET_TEXT_F(MSG_E_MOVE));
+ w.color(Theme::e_axis);
+ #if EXTRUDERS == 1
+ w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E), screen_data.MoveAxis.e_rel[0], canMove(E0));
+ #elif HAS_MULTI_EXTRUDER
+ w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E1), screen_data.MoveAxis.e_rel[0], canMove(E0));
+ w.adjuster( 10, GET_TEXT_F(MSG_AXIS_E2), screen_data.MoveAxis.e_rel[1], canMove(E1));
+ #if EXTRUDERS > 2
+ w.adjuster( 12, GET_TEXT_F(MSG_AXIS_E3), screen_data.MoveAxis.e_rel[2], canMove(E2));
+ #endif
+ #if EXTRUDERS > 3
+ w.adjuster( 14, GET_TEXT_F(MSG_AXIS_E4), screen_data.MoveAxis.e_rel[3], canMove(E3));
+ #endif
+ #endif
+ w.increments();
+}
+
+void MoveEScreen::onIdle() {
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_xyz_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_xyz_screen.cpp
new file mode 100644
index 0000000..52a7044
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_xyz_screen.cpp
@@ -0,0 +1,53 @@
+/************************************
+ * cocoa_press_move_xyz_screen.cpp *
+ ************************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+
+void MoveXYZScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(1);
+ w.units(GET_TEXT_F(MSG_UNITS_MM));
+ w.heading( GET_TEXT_F(MSG_XYZ_MOVE));
+ w.home_buttons(20);
+ w.color(Theme::x_axis).adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisPosition_mm(X), canMove(X));
+ w.color(Theme::y_axis).adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getAxisPosition_mm(Y), canMove(Y));
+ w.color(Theme::z_axis).adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getAxisPosition_mm(Z), canMove(Z));
+ w.increments();
+}
+
+void MoveXYZScreen::onIdle() {
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_menu.cpp
new file mode 100644
index 0000000..99c0c1b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_menu.cpp
@@ -0,0 +1,113 @@
+/********************************
+ * cocoa_press_preheat_menu.cpp *
+ ********************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2020 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_ROWS 5
+#define GRID_COLS 2
+
+void PreheatMenu::onRedraw(draw_mode_t what) {
+ const int16_t w = has_extra_heater() ? BTN_W(1) : BTN_W(2);
+ const int16_t h = BTN_H(1);
+
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .font(Theme::font_medium)
+ .text ( BTN_POS(1,1), w, h, GET_TEXT_F(MSG_INTERNAL));
+ if (has_extra_heater()) {
+ cmd.text( BTN_POS(2,1), w, h, GET_TEXT_F(MSG_EXTERNAL));
+ }
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.font(Theme::font_medium)
+ .colors(normal_btn)
+ .tag(2).button(BTN_POS(1,2), w, h, F("Dark Chocolate"))
+ .tag(3).button(BTN_POS(1,3), w, h, F("Milk Chocolate"))
+ .tag(4).button(BTN_POS(1,4), w, h, F("White Chocolate"));
+ if (has_extra_heater()) {
+ cmd.tag(5).button(BTN_POS(2,2), w, h, F("Dark Chocolate"))
+ .tag(6).button(BTN_POS(2,3), w, h, F("Milk Chocolate"))
+ .tag(7).button(BTN_POS(2,4), w, h, F("White Chocolate"));
+ }
+ cmd.colors(action_btn)
+ .tag(1) .button(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool PreheatMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2:
+ #ifdef COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_INT_SCRIPT
+ injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_INT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 3:
+ #ifdef COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_INT_SCRIPT
+ injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_INT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 4:
+ #ifdef COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_INT_SCRIPT
+ injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_INT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 5:
+ #ifdef COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_EXT_SCRIPT
+ injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_EXT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 6:
+ #ifdef COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_EXT_SCRIPT
+ injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_EXT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 7:
+ #ifdef COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_EXT_SCRIPT
+ injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_EXT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ default: return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_screen.cpp
new file mode 100644
index 0000000..c9caef6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_screen.cpp
@@ -0,0 +1,172 @@
+/****************************
+ * preheat_timer_screen.cpp *
+ ****************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+#include "screen_data.h"
+
+#include "../ftdi_eve_lib/extras/circular_progress.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 8
+
+#define HEADER_POS BTN_POS(2,1), BTN_SIZE(1,2)
+#define NOZZLE_ADJ_POS BTN_POS(2,3), BTN_SIZE(1,2)
+#define BODY_ADJ_POS BTN_POS(2,5), BTN_SIZE(1,2)
+#define CHAMBER_ADJ_POS BTN_POS(2,7), BTN_SIZE(1,2)
+#define PROGRESS_POS BTN_POS(1,1), BTN_SIZE(1,7)
+#define BACK_POS BTN_POS(1,8), BTN_SIZE(1,1)
+
+void PreheatTimerScreen::draw_message(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+ draw_text_box(cmd, HEADER_POS, GET_TEXT_F(MSG_HEATING), OPT_CENTER, font_large);
+ }
+}
+
+uint16_t PreheatTimerScreen::secondsRemaining() {
+ const uint32_t elapsed_sec = (millis() - screen_data.PreheatTimer.start_ms) / 1000;
+ return (COCOA_PRESS_PREHEAT_SECONDS > elapsed_sec) ? COCOA_PRESS_PREHEAT_SECONDS - elapsed_sec : 0;
+}
+
+void PreheatTimerScreen::draw_time_remaining(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ const uint16_t elapsed_sec = secondsRemaining();
+ const uint8_t min = elapsed_sec / 60,
+ sec = elapsed_sec % 60;
+
+ char str[10];
+ sprintf_P(str, PSTR("%02d:%02d"), min, sec);
+
+ CommandProcessor cmd;
+ cmd.font(font_xlarge);
+ draw_circular_progress(cmd, PROGRESS_POS, float(secondsRemaining()) * 100 / COCOA_PRESS_PREHEAT_SECONDS, str, theme_dark, theme_darkest);
+ }
+}
+
+void PreheatTimerScreen::draw_interaction_buttons(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+void PreheatTimerScreen::draw_adjuster(draw_mode_t what, uint8_t tag, progmem_str label, float value, int16_t x, int16_t y, int16_t w, int16_t h) {
+ #define SUB_COLS 9
+ #define SUB_ROWS 2
+ #define SUB_GRID_W(W) ((W)*w/SUB_COLS)
+ #define SUB_GRID_H(H) ((H)*h/SUB_ROWS)
+ #define SUB_GRID_X(X) (SUB_GRID_W((X)-1) + x)
+ #define SUB_GRID_Y(Y) (SUB_GRID_H((Y)-1) + y)
+ #define SUB_X(X) (SUB_GRID_X(X) + MARGIN_L)
+ #define SUB_Y(Y) (SUB_GRID_Y(Y) + MARGIN_T)
+ #define SUB_W(W) (SUB_GRID_W(W) - MARGIN_L - MARGIN_R)
+ #define SUB_H(H) (SUB_GRID_H(H) - MARGIN_T - MARGIN_B)
+ #define SUB_POS(X,Y) SUB_X(X), SUB_Y(Y)
+ #define SUB_SIZE(W,H) SUB_W(W), SUB_H(H)
+
+ CommandProcessor cmd;
+ cmd.tag(0)
+ .font(font_small);
+ if (what & BACKGROUND) {
+ cmd.text( SUB_POS(1,1), SUB_SIZE(9,1), label)
+ .button(SUB_POS(1,2), SUB_SIZE(5,1), F(""), OPT_FLAT);
+ }
+
+ if (what & FOREGROUND) {
+ char str[32];
+ dtostrf(value, 5, 1, str);
+ strcat_P(str, PSTR(" "));
+ strcat_P(str, (const char*) GET_TEXT_F(MSG_UNITS_C));
+
+ cmd.text(SUB_POS(1,2), SUB_SIZE(5,1), str)
+ .font(font_medium)
+ .tag(tag ).button(SUB_POS(6,2), SUB_SIZE(2,1), F("-"))
+ .tag(tag+1).button(SUB_POS(8,2), SUB_SIZE(2,1), F("+"));
+ }
+}
+
+void PreheatTimerScreen::onEntry() {
+ screen_data.PreheatTimer.start_ms = millis();
+}
+
+void PreheatTimerScreen::onRedraw(draw_mode_t what) {
+ draw_message(what);
+ draw_time_remaining(what);
+ draw_interaction_buttons(what);
+ draw_adjuster(what, 1, GET_TEXT_F(MSG_NOZZLE), getTargetTemp_celsius(E0), NOZZLE_ADJ_POS);
+ draw_adjuster(what, 3, GET_TEXT_F(MSG_BODY), getTargetTemp_celsius(E1), BODY_ADJ_POS);
+ draw_adjuster(what, 5, GET_TEXT_F(MSG_CHAMBER), getTargetTemp_celsius(CHAMBER), CHAMBER_ADJ_POS);
+}
+
+bool PreheatTimerScreen::onTouchHeld(uint8_t tag) {
+ const float increment = (tag == 5 || tag == 6) ? 1 : 0.1;
+ switch (tag) {
+ case 1: UI_DECREMENT(TargetTemp_celsius, E0); break;
+ case 2: UI_INCREMENT(TargetTemp_celsius, E0); break;
+ case 3: UI_DECREMENT(TargetTemp_celsius, E1); break;
+ case 4: UI_INCREMENT(TargetTemp_celsius, E1); break;
+ case 5: UI_DECREMENT(TargetTemp_celsius, CHAMBER); break;
+ case 6: UI_INCREMENT(TargetTemp_celsius, CHAMBER); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool PreheatTimerScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); return true;
+ default: break;
+ }
+ return false;
+}
+
+void PreheatTimerScreen::onIdle() {
+ if (secondsRemaining() == 0) {
+ AlertDialogBox::show(GET_TEXT_F(MSG_PREHEAT_FINISHED));
+ // Remove SaveSettingsDialogBox from the stack
+ // so the alert box doesn't return to me.
+ current_screen.forget();
+ }
+
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_status_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_status_screen.cpp
new file mode 100644
index 0000000..d9881d7
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_status_screen.cpp
@@ -0,0 +1,307 @@
+/*********************************
+ * cocoa_press_status_screen.cpp *
+ *********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+
+#include "../ftdi_eve_lib/extras/poly_ui.h"
+
+#include "cocoa_press_ui.h"
+
+#define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0]))
+
+const uint8_t shadow_depth = 5;
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+float StatusScreen::increment;
+
+void StatusScreen::loadBitmaps() {
+ constexpr uint32_t base = ftdi_memory_map::RAM_G;
+
+ // Load fonts for internationalization
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_data(base + UTF8_FONT_OFFSET);
+ #endif
+}
+
+void StatusScreen::draw_progress(draw_mode_t what) {
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ int16_t x, y, h, v;
+
+ cmd.cmd(COLOR_RGB(accent_color_1));
+ cmd.font(font_medium);
+
+ if (what & BACKGROUND) {
+ ui.bounds(POLY(print_time_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_ELAPSED_PRINT));
+ }
+
+ if (what & FOREGROUND) {
+ const uint32_t elapsed = getProgress_seconds_elapsed();
+ const uint8_t hrs = elapsed/3600;
+ const uint8_t min = (elapsed/60)%60;
+
+ char str[10];
+ sprintf_P(str, PSTR(" %02d : %02d"), hrs, min);
+ ui.bounds(POLY(print_time_hms), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ sprintf_P(str, PSTR("%-3d%%"), getProgress_percent() );
+ ui.bounds(POLY(print_time_percent), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ }
+}
+
+void StatusScreen::draw_temperature(draw_mode_t what) {
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ int16_t x, y, h, v;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(COLOR_RGB(bg_color));
+
+ cmd.cmd(COLOR_RGB(fluid_rgb));
+ cmd.font(font_medium);
+
+ ui.bounds(POLY(chocolate_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_CHOCOLATE));
+
+ ui.bounds(POLY(h0_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_NOZZLE));
+
+ ui.bounds(POLY(h1_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_BODY));
+
+ #if ENABLED(COCOA_PRESS_EXTRA_HEATER)
+ if (has_extra_heater()) {
+ ui.bounds(POLY(h2_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_EXTERNAL));
+ }
+ #endif
+
+ ui.bounds(POLY(h3_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_CHAMBER));
+
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd); // Restore font bitmap handles
+ #endif
+ }
+
+ if (what & FOREGROUND) {
+ char str[15];
+ cmd.cmd(COLOR_RGB(fluid_rgb));
+
+ cmd.font(font_large);
+
+ format_temp(str, getActualTemp_celsius(E0));
+ ui.bounds(POLY(h0_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ format_temp(str, getActualTemp_celsius(E1));
+ ui.bounds(POLY(h1_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ #if ENABLED(COCOA_PRESS_EXTRA_HEATER)
+ if (has_extra_heater()) {
+ format_temp(str, getActualTemp_celsius(E2));
+ ui.bounds(POLY(h2_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ }
+ #endif
+
+ format_temp(str, getActualTemp_celsius(CHAMBER));
+ ui.bounds(POLY(h3_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ }
+}
+
+void StatusScreen::draw_syringe(draw_mode_t what) {
+ #if NUM_SERVOS < 2
+ // Note, this requires a new pin 108 to be added to to access ADC9
+ // "ArduinoAddons/arduino-1.8.5/packages/ultimachine/hardware/sam/1.6.9-b/variants/archim/variant.cpp"
+ const int val = analogRead(108);
+ const float fill_level = float(val) / 1024;
+ #else
+ constexpr float fill_level = 1.0f;
+ #endif
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ if (what & BACKGROUND) {
+ // Paint the shadow for the syringe
+ ui.color(shadow_rgb);
+ ui.shadow(POLY(syringe_outline), shadow_depth);
+ }
+
+ if (what & FOREGROUND) {
+ int16_t x, y, h, v;
+
+ // Paint the syringe icon
+ ui.color(syringe_rgb);
+ ui.fill(POLY(syringe_outline));
+
+ ui.color(fluid_rgb);
+ ui.bounds(POLY(syringe_fluid), x, y, h, v);
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(SCISSOR_XY(x,y + v * (1.0 - fill_level)));
+ cmd.cmd(SCISSOR_SIZE(h, v * fill_level));
+ ui.fill(POLY(syringe_fluid), false);
+ cmd.cmd(RESTORE_CONTEXT());
+
+ ui.color(stroke_rgb);
+ ui.fill(POLY(syringe));
+ }
+}
+
+void StatusScreen::draw_buttons(draw_mode_t what) {
+ int16_t x, y, h, v;
+
+ const bool can_print = isMediaInserted() && !isPrintingFromMedia();
+ const bool sdOrHostPrinting = ExtUI::isPrinting();
+ const bool sdOrHostPaused = ExtUI::isPrintingPaused();
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ ui.bounds(POLY(unload_cartridge_btn), x, y, h, v);
+
+ cmd.font(font_medium).colors(normal_btn);
+
+ ui.bounds(POLY(unload_cartridge_btn), x, y, h, v);
+ cmd.tag(1).button(x, y, h, v, GET_TEXT_F(MSG_UNLOAD_CARTRIDGE));
+
+ ui.bounds(POLY(load_chocolate_btn), x, y, h, v);
+ cmd.tag(2).button(x, y, h, v, GET_TEXT_F(MSG_LOAD_CHOCOLATE));
+
+ ui.bounds(POLY(preheat_chocolate_btn), x, y, h, v);
+ cmd.tag(3).button(x, y, h, v, GET_TEXT_F(MSG_PREHEAT_CHOCOLATE));
+
+ ui.bounds(POLY(menu_btn), x, y, h, v);
+ cmd.tag(4).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_MENU));
+
+ ui.bounds(POLY(pause_btn), x, y, h, v);
+ cmd.tag(sdOrHostPaused ? 6 : 5).enabled(sdOrHostPrinting).button(x, y, h, v, sdOrHostPaused ? GET_TEXT_F(MSG_BUTTON_RESUME) : GET_TEXT_F(MSG_BUTTON_PAUSE));
+
+ ui.bounds(POLY(stop_btn), x, y, h, v);
+ cmd.tag(7).enabled(sdOrHostPrinting).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_STOP));
+
+ ui.bounds(POLY(extrude_btn), x, y, h, v);
+ cmd.tag(8).button(x, y, h, v, GET_TEXT_F(MSG_EXTRUDE));
+
+ ui.bounds(POLY(print_btn), x, y, h, v);
+ cmd.tag(9).colors(action_btn).enabled(can_print).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_PRINT));
+}
+
+void StatusScreen::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ draw_progress(what);
+ draw_syringe(what);
+ draw_temperature(what);
+ draw_buttons(what);
+}
+
+bool StatusScreen::onTouchStart(uint8_t) {
+ increment = 0;
+ return true;
+}
+
+bool StatusScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_SCREEN(UnloadCartridgeScreen); break;
+ case 2: GOTO_SCREEN(LoadChocolateScreen); break;
+ case 3: GOTO_SCREEN(PreheatMenu); break;
+ case 4: GOTO_SCREEN(MainMenu); break;
+ case 5:
+ sound.play(twinkle, PLAY_ASYNCHRONOUS);
+ if (ExtUI::isPrintingFromMedia())
+ ExtUI::pausePrint();
+ #ifdef ACTION_ON_PAUSE
+ else host_action_pause();
+ #endif
+ GOTO_SCREEN(StatusScreen);
+ break;
+ case 6:
+ sound.play(twinkle, PLAY_ASYNCHRONOUS);
+ if (ExtUI::isPrintingFromMedia())
+ ExtUI::resumePrint();
+ #ifdef ACTION_ON_RESUME
+ else host_action_resume();
+ #endif
+ GOTO_SCREEN(StatusScreen);
+ break;
+ case 7:
+ GOTO_SCREEN(ConfirmAbortPrintDialogBox);
+ current_screen.forget();
+ PUSH_SCREEN(StatusScreen);
+ break;
+ case 9: GOTO_SCREEN(FilesScreen); break;
+ default: return false;
+ }
+ // If a passcode is enabled, the LockScreen will prevent the
+ // user from proceeding.
+ LockScreen::check_passcode();
+ return true;
+}
+
+bool StatusScreen::onTouchHeld(uint8_t tag) {
+ if (tag == 8 && !ExtUI::isMoving()) {
+ increment = 0.05;
+ MoveAxisScreen::setManualFeedrate(E0, increment);
+ UI_INCREMENT(AxisPosition_mm, E0);
+ current_screen.onRefresh();
+ }
+ return false;
+}
+
+void StatusScreen::setStatusMessage(progmem_str) {
+}
+
+void StatusScreen::setStatusMessage(const char * const) {
+}
+
+void StatusScreen::onIdle() {
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ if (!EventLoop::is_touch_held())
+ onRefresh();
+ refresh_timer.start();
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_ui.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_ui.h
new file mode 100644
index 0000000..5cbaced
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_ui.h
@@ -0,0 +1,54 @@
+
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 480.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 272.000000;
+
+const PROGMEM uint16_t syringe_outline[] = {0xED96, 0x14F0, 0xE65D, 0x10E9, 0xDED2, 0x0F9C, 0xD74B, 0x110E, 0xD01B, 0x1543, 0xCE80, 0x1836, 0xCE0A, 0x1C3A, 0xCE0F, 0x27AD, 0xCF0A, 0x2BD3, 0xD127, 0x2E5B, 0xD2A1, 0x2FF0, 0xD2A2, 0x9FC9, 0xD407, 0xA97A, 0xD7B9, 0xB10C, 0xD7BF, 0xBB58, 0xD978, 0xC2BE, 0xDD55, 0xC6EB, 0xDD58, 0xD159, 0xDE3B, 0xD3A8, 0xDFCF, 0xD3AF, 0xE0B8, 0xD04C, 0xE0B8, 0xC6EB, 0xE4A7, 0xC299, 0xE652, 0xBAF6, 0xE652, 0xB10C, 0xEA2E, 0xA8EA, 0xEB6C, 0x9E86, 0xEB6C, 0x2F58, 0xEF3C, 0x2B4E, 0xF003, 0x2583, 0xEFFD, 0x1AC2, 0xED96, 0x14F0, 0xED96, 0x14F0};
+const PROGMEM uint16_t syringe_fluid[] = {0xDE73, 0x2512, 0xDA0C, 0x261D, 0xD5B8, 0x29A0, 0xD4AE, 0x2D87, 0xD4AE, 0x9F60, 0xD585, 0xA63B, 0xDE44, 0xA9DE, 0xE32A, 0xA942, 0xE7E3, 0xA6A5, 0xE930, 0xA342, 0xE95D, 0x9C1D, 0xE95B, 0x31B8, 0xE955, 0x2B63, 0xE867, 0x2A67, 0xE790, 0x28DE, 0xE342, 0x25CB, 0xDE73, 0x2512};
+const PROGMEM uint16_t syringe[] = {0xED91, 0x1502, 0xE658, 0x10FB, 0xDECE, 0x0FAE, 0xD746, 0x1120, 0xD016, 0x1555, 0xCE7B, 0x1848, 0xCE05, 0x1C4D, 0xCE0A, 0x27BF, 0xCF05, 0x2BE5, 0xD122, 0x2E6E, 0xD29C, 0x3002, 0xD29D, 0x9FDB, 0xD402, 0xA98C, 0xD7B4, 0xB11F, 0xD7BA, 0xBB6A, 0xD973, 0xC2D1, 0xDD50, 0xC6FD, 0xDD53, 0xD16C, 0xDE36, 0xD3BA, 0xDFCA, 0xD3C2, 0xE0B3, 0xD05E, 0xE0B3, 0xC6FD, 0xE4A2, 0xC2AB, 0xE64D, 0xBB09, 0xE64D, 0xB11F, 0xEA29, 0xA8FC, 0xEB67, 0x9E98, 0xEB67, 0x2F6B, 0xEF37, 0x2B60, 0xEFFE, 0x2595, 0xEFF8, 0x1AD5, 0xED91, 0x1502, 0xED91, 0x1502, 0xFFFF, 0xD1CF, 0x1A7E, 0xD84F, 0x16DB, 0xDF19, 0x15A9, 0xE5E0, 0x16EA, 0xEC5B, 0x1AA4, 0xEC9D, 0x1D34, 0xEC9D, 0x20CC, 0xE5F1, 0x1D41, 0xDF02, 0x1C12, 0xD812, 0x1D41, 0xD166, 0x20CC, 0xD16C, 0x1B45, 0xD1CF, 0x1A7E, 0xFFFF, 0xE3BD, 0xACFD, 0xDE8E, 0xAF4F, 0xD988, 0xAC0F, 0xD7CC, 0xA8CD, 0xDD1C, 0xAAA9, 0xE287, 0xAA5B, 0xE655, 0xA8BE, 0xE3BD, 0xACFD, 0xFFFF, 0xE802, 0x2DC5, 0xE809, 0x343C, 0xE808, 0x9FC8, 0xE7E3, 0xA296, 0xE70D, 0xA4B1, 0xE2C9, 0xA70E, 0xDE4E, 0xA790, 0xD6A1, 0xA457, 0xD5FF, 0x9F2B, 0xD5FF, 0x2DFD, 0xD6B2, 0x2B72, 0xDA78, 0x2861, 0xDE9D, 0x276F, 0xE300, 0x2824, 0xE70D, 0x2B13, 0xE7FF, 0x2DB6, 0xE800, 0x2DC5, 0xE802, 0x2DC5, 0xFFFF, 0xE2ED, 0xBA8B, 0xE1CC, 0xBF52, 0xDF1C, 0xC165, 0xDC64, 0xBF99, 0xDB1B, 0xBAFF, 0xDB19, 0xB433, 0xDF04, 0xB552, 0xE2EF, 0xB438, 0xE2ED, 0xBA8B, 0xFFFF, 0xEC09, 0x2893, 0xE925, 0x2A08, 0xE57D, 0x261D, 0xE149, 0x246F, 0xDBDE, 0x24A0, 0xD6BC, 0x2795, 0xD484, 0x2A46, 0xD1C0, 0x2853, 0xD166, 0x251E, 0xD80D, 0x2151, 0xDF02, 0x200C, 0xE5F6, 0x2151, 0xEC9D, 0x251E, 0xEC09, 0x2893};
+const PROGMEM uint16_t unload_cartridge_btn[] = {0x0AAA, 0x0E1E, 0x57FF, 0x0E1E, 0x57FF, 0x33C3, 0x0AAA, 0x33C3, 0x0AAA, 0x0E1E};
+const PROGMEM uint16_t pause_btn[] = {0x47FF, 0xCA58, 0x7FFF, 0xCA58, 0x7FFF, 0xEFFE, 0x47FF, 0xEFFE, 0x47FF, 0xCA58};
+const PROGMEM uint16_t load_chocolate_btn[] = {0x0AAA, 0x3D2C, 0x57FF, 0x3D2C, 0x57FF, 0x62D2, 0x0AAA, 0x62D2, 0x0AAA, 0x3D2C};
+const PROGMEM uint16_t preheat_chocolate_btn[] = {0x0AAA, 0x6C3B, 0x57FF, 0x6C3B, 0x57FF, 0x91E0, 0x0AAA, 0x91E0, 0x0AAA, 0x6C3B};
+const PROGMEM uint16_t menu_btn[] = {0x0AAA, 0x9B4A, 0x57FF, 0x9B4A, 0x57FF, 0xC0EF, 0x0AAA, 0xC0EF, 0x0AAA, 0x9B4A};
+const PROGMEM uint16_t print_btn[] = {0x0AAA, 0xCA58, 0x42AA, 0xCA58, 0x42AA, 0xEFFE, 0x0AAA, 0xEFFE, 0x0AAA, 0xCA58};
+const PROGMEM uint16_t stop_btn[] = {0x8554, 0xCA58, 0xBD53, 0xCA58, 0xBD53, 0xEFFE, 0x8554, 0xEFFE, 0x8554, 0xCA58};
+const PROGMEM uint16_t print_time_hms[] = {0x62A9, 0xA968, 0x8FFE, 0xA968, 0x8FFE, 0xC0EF, 0x62A9, 0xC0EF, 0x62A9, 0xA968};
+const PROGMEM uint16_t print_time_percent[] = {0x8FFE, 0xA968, 0xBD53, 0xA968, 0xBD53, 0xC0EF, 0x8FFE, 0xC0EF, 0x8FFE, 0xA968};
+const PROGMEM uint16_t print_time_label[] = {0x62A9, 0x91E0, 0xBD53, 0x91E0, 0xBD53, 0xA986, 0x62A9, 0xA986, 0x62A9, 0x91E0};
+const PROGMEM uint16_t h3_temp[] = {0x62A9, 0x75A4, 0x8FFE, 0x75A4, 0x8FFE, 0x8D2C, 0x62A9, 0x8D2C, 0x62A9, 0x75A4};
+const PROGMEM uint16_t h3_label[] = {0x62A9, 0x5E1D, 0x8FFE, 0x5E1D, 0x8FFE, 0x75A4, 0x62A9, 0x75A4, 0x62A9, 0x5E1D};
+const PROGMEM uint16_t chocolate_label[] = {0x62A9, 0x12D2, 0xBD53, 0x12D2, 0xBD53, 0x2A5A, 0x62A9, 0x2A5A, 0x62A9, 0x12D2};
+const PROGMEM uint16_t h0_label[] = {0x62A9, 0x2A5A, 0x8FFE, 0x2A5A, 0x8FFE, 0x41E1, 0x62A9, 0x41E1, 0x62A9, 0x2A5A};
+const PROGMEM uint16_t h0_temp[] = {0x62A9, 0x41E1, 0x8FFE, 0x41E1, 0x8FFE, 0x5968, 0x62A9, 0x5968, 0x62A9, 0x41E1};
+const PROGMEM uint16_t h1_label[] = {0x8FFE, 0x2A5A, 0xBD53, 0x2A5A, 0xBD53, 0x41E1, 0x8FFE, 0x41E1, 0x8FFE, 0x2A5A};
+const PROGMEM uint16_t h1_temp[] = {0x8FFE, 0x41E1, 0xBD53, 0x41E1, 0xBD53, 0x5968, 0x8FFE, 0x5968, 0x8FFE, 0x41E1};
+const PROGMEM uint16_t extrude_btn[] = {0xC859, 0xDD2B, 0xF5AE, 0xDD2B, 0xF5AE, 0xEFFE, 0xC859, 0xEFFE, 0xC859, 0xDD2B};
+const PROGMEM uint16_t h2_label[] = {0x8FFE, 0x5E1D, 0xBD53, 0x5E1D, 0xBD53, 0x75A4, 0x8FFE, 0x75A4, 0x8FFE, 0x5E1D};
+const PROGMEM uint16_t h2_temp[] = {0x8FFE, 0x75A4, 0xBD53, 0x75A4, 0xBD53, 0x8D2C, 0x8FFE, 0x8D2C, 0x8FFE, 0x75A4};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_unload_cartridge.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_unload_cartridge.cpp
new file mode 100644
index 0000000..2e71093
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_unload_cartridge.cpp
@@ -0,0 +1,101 @@
+/************************************
+ * cocoa_press_unload_cartridge.cpp *
+ ************************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2020 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && ENABLED(TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace ExtUI;
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 6
+
+#define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1)
+#define DESCRIPTION_POS BTN_POS(1,2), BTN_SIZE(2,3)
+#define CARTRIDGE_OUT_BTN_POS BTN_POS(1,5), BTN_SIZE(1,1)
+#define CARTRIDGE_IN_BTN_POS BTN_POS(2,5), BTN_SIZE(1,1)
+#define BACK_BTN_POS BTN_POS(1,6), BTN_SIZE(2,1)
+
+void UnloadCartridgeScreen::onRedraw(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+ .font(font_large)
+ .text(TITLE_POS, GET_TEXT_F(MSG_UNLOAD_CARTRIDGE));
+ draw_text_box(cmd, DESCRIPTION_POS, F(
+ "Press and hold the buttons below to help "
+ "you unlock the cartridge. After unlocking, "
+ "press and hold the Cartridge Out button "
+ "until the cartridge is sticking out of the "
+ "extruder enough to grip and remove. After "
+ "removing the cartridge, continue holding the "
+ "Cartridge Out button until the plunger adapter is "
+ "visible at the bottom of the extruder."
+ ),
+ OPT_CENTERY, font_medium);
+ }
+
+ if (what & FOREGROUND) {
+ cmd.font(font_medium)
+ .colors(normal_btn)
+ .tag(2).button(CARTRIDGE_OUT_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_OUT))
+ .tag(3).button(CARTRIDGE_IN_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_IN))
+ .colors(action_btn)
+ .tag(1).button(BACK_BTN_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool UnloadCartridgeScreen::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ }
+ return true;
+}
+
+bool UnloadCartridgeScreen::onTouchHeld(uint8_t tag) {
+ if (ExtUI::isMoving()) return false; // Don't allow moves to accumulate
+ constexpr float increment = 0.25;
+ MoveAxisScreen::setManualFeedrate(E0, increment);
+ #define UI_INCREMENT_AXIS(axis) UI_INCREMENT(AxisPosition_mm, axis);
+ #define UI_DECREMENT_AXIS(axis) UI_DECREMENT(AxisPosition_mm, axis);
+ switch (tag) {
+ case 2: UI_DECREMENT_AXIS(E0); break;
+ case 3: UI_INCREMENT_AXIS(E0); break;
+ default: return false;
+ }
+ #undef UI_DECREMENT_AXIS
+ #undef UI_INCREMENT_AXIS
+ return false;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_abort_print_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_abort_print_dialog_box.cpp
new file mode 100644
index 0000000..528d93d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_abort_print_dialog_box.cpp
@@ -0,0 +1,53 @@
+/**************************************
+ * confirm_abort_print_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+#include "../../../../../feature/host_actions.h"
+
+using namespace ExtUI;
+
+void ConfirmAbortPrintDialogBox::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_ABORT_WARNING));
+ drawYesNoButtons();
+}
+
+bool ConfirmAbortPrintDialogBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ GOTO_PREVIOUS();
+ if (ExtUI::isPrintingFromMedia())
+ ExtUI::stopPrint();
+ #ifdef ACTION_ON_CANCEL
+ else host_action_cancel();
+ #endif
+ return true;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_auto_calibration_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_auto_calibration_dialog_box.cpp
new file mode 100644
index 0000000..f7c8567
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_auto_calibration_dialog_box.cpp
@@ -0,0 +1,48 @@
+/*******************************************
+ * confirm_auto_calibration_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, CALIBRATION_GCODE)
+
+#include "screens.h"
+
+using namespace ExtUI;
+using namespace Theme;
+
+void ConfirmAutoCalibrationDialogBox::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_CALIBRATION_WARNING));
+ drawYesNoButtons();
+}
+
+bool ConfirmAutoCalibrationDialogBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ GOTO_SCREEN(StatusScreen);
+ injectCommands_P(PSTR("G425"));
+ return true;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_erase_flash_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_erase_flash_dialog_box.cpp
new file mode 100644
index 0000000..baf5959
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_erase_flash_dialog_box.cpp
@@ -0,0 +1,54 @@
+/**************************************
+ * confirm_erase_flash_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU)
+
+#include "screens.h"
+
+#include "../archim2-flash/flash_storage.h"
+
+using namespace FTDI;
+
+void ConfirmEraseFlashDialogBox::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_ERASE_FLASH_WARNING));
+ drawYesNoButtons();
+}
+
+bool ConfirmEraseFlashDialogBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ SpinnerDialogBox::show(GET_TEXT_F(MSG_ERASING));
+ UIFlashStorage::format_flash();
+ SpinnerDialogBox::hide();
+ AlertDialogBox::show(GET_TEXT_F(MSG_ERASED));
+ // Remove ConfirmEraseFlashDialogBox from the stack
+ // so the alert box doesn't return to me.
+ current_screen.forget();
+ return true;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_start_print_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_start_print_dialog_box.cpp
new file mode 100644
index 0000000..eeca88f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_start_print_dialog_box.cpp
@@ -0,0 +1,65 @@
+/**************************************
+ * confirm_start_print_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+void ConfirmStartPrintDialogBox::onRedraw(draw_mode_t) {
+ const char *filename = getLongFilename();
+ char buffer[strlen_P(GET_TEXT(MSG_START_PRINT_CONFIRMATION)) + strlen(filename) + 1];
+ sprintf_P(buffer, GET_TEXT(MSG_START_PRINT_CONFIRMATION), filename);
+ drawMessage((const char *)buffer);
+ drawYesNoButtons(1);
+}
+
+bool ConfirmStartPrintDialogBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ printFile(getShortFilename());
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PRINT_STARTING));
+ GOTO_SCREEN(StatusScreen);
+ return true;
+ case 2: GOTO_PREVIOUS(); return true;
+ default: return false;
+ }
+}
+
+const char *ConfirmStartPrintDialogBox::getFilename(bool longName) {
+ FileList files;
+ files.seek(screen_data.ConfirmStartPrintDialog.file_index, true);
+ return longName ? files.longFilename() : files.shortFilename();
+}
+
+void ConfirmStartPrintDialogBox::show(uint8_t file_index) {
+ screen_data.ConfirmStartPrintDialog.file_index = file_index;
+ GOTO_SCREEN(ConfirmStartPrintDialogBox);
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_user_request_alert_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_user_request_alert_box.cpp
new file mode 100644
index 0000000..59e1c82
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_user_request_alert_box.cpp
@@ -0,0 +1,66 @@
+/**************************************
+ * confirm_user_request_alert_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+
+void ConfirmUserRequestAlertBox::onRedraw(draw_mode_t mode) {
+ AlertDialogBox::onRedraw(mode); // Required for the GOTO_SCREEN function to work
+}
+
+bool ConfirmUserRequestAlertBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ if (ExtUI::isPrintingPaused()) {
+ // The TuneMenu will call ExtUI::setUserConfirmed()
+ GOTO_SCREEN(TuneMenu);
+ current_screen.forget();
+ }
+ else {
+ ExtUI::setUserConfirmed();
+ GOTO_PREVIOUS();
+ }
+ return true;
+ case 2: GOTO_PREVIOUS(); return true;
+ default: return false;
+ }
+}
+
+void ConfirmUserRequestAlertBox::show(const char* msg) {
+ drawMessage(msg);
+ storeBackground();
+ screen_data.AlertDialog.isError = false;
+ GOTO_SCREEN(ConfirmUserRequestAlertBox);
+}
+
+void ConfirmUserRequestAlertBox::hide() {
+ if (AT_SCREEN(ConfirmUserRequestAlertBox))
+ GOTO_PREVIOUS();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/custom_user_menus.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/custom_user_menus.cpp
new file mode 100644
index 0000000..20f90d5
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/custom_user_menus.cpp
@@ -0,0 +1,215 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, CUSTOM_USER_MENUS) && NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define _ITEM_TAG(N) (10+N)
+#define _USER_DESC(N) USER_DESC_##N
+#define _USER_GCODE(N) USER_GCODE_##N
+#define _USER_ITEM(N) .tag(_ITEM_TAG(N)).button(USER_ITEM_POS(N), _USER_DESC(N))
+#define _USER_ACTION(N) case _ITEM_TAG(N): injectCommands_P(PSTR(_USER_GCODE(N))); TERN_(USER_SCRIPT_RETURN, GOTO_SCREEN(StatusScreen)); break;
+
+#define _HAS_1(N) (defined(USER_DESC_##N) && defined(USER_GCODE_##N))
+#define HAS_USER_ITEM(V...) DO(HAS,||,V)
+
+void CustomUserMenus::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true, true, true));
+ }
+
+ #if HAS_USER_ITEM(16, 17, 18, 19, 20)
+ #define _MORE_THAN_FIFTEEN 1
+ #else
+ #define _MORE_THAN_FIFTEEN 0
+ #endif
+ #if _MORE_THAN_FIFTEEN || HAS_USER_ITEM(11, 12, 13, 14, 15)
+ #define _MORE_THAN_TEN 1
+ #else
+ #define _MORE_THAN_TEN 0
+ #endif
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 11
+ #define GRID_COLS (1 + _MORE_THAN_TEN)
+ #define USER_ITEM_POS(N) BTN_POS((1+((N-1)/10)), ((N-1) % 10 + 1)), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(1,11), BTN_SIZE(1,1)
+ #else
+ #if _MORE_THAN_TEN || HAS_USER_ITEM(6, 7, 8, 9, 10)
+ #define _MORE_THAN_FIVE 1
+ #else
+ #define _MORE_THAN_FIVE 0
+ #endif
+ #define GRID_ROWS 6
+ #define GRID_COLS (1 + _MORE_THAN_FIVE + _MORE_THAN_TEN + _MORE_THAN_FIFTEEN)
+ #define USER_ITEM_POS(N) BTN_POS((1+((N-1)/5)), ((N-1) % 5 + 1)), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(1,6), BTN_SIZE(GRID_COLS,1)
+ #endif
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ #if HAS_USER_ITEM(1)
+ _USER_ITEM(1)
+ #endif
+ #if HAS_USER_ITEM(2)
+ _USER_ITEM(2)
+ #endif
+ #if HAS_USER_ITEM(3)
+ _USER_ITEM(3)
+ #endif
+ #if HAS_USER_ITEM(4)
+ _USER_ITEM(4)
+ #endif
+ #if HAS_USER_ITEM(5)
+ _USER_ITEM(5)
+ #endif
+ #if HAS_USER_ITEM(6)
+ _USER_ITEM(6)
+ #endif
+ #if HAS_USER_ITEM(7)
+ _USER_ITEM(7)
+ #endif
+ #if HAS_USER_ITEM(8)
+ _USER_ITEM(8)
+ #endif
+ #if HAS_USER_ITEM(9)
+ _USER_ITEM(9)
+ #endif
+ #if HAS_USER_ITEM(10)
+ _USER_ITEM(10)
+ #endif
+ #if HAS_USER_ITEM(11)
+ _USER_ITEM(11)
+ #endif
+ #if HAS_USER_ITEM(12)
+ _USER_ITEM(12)
+ #endif
+ #if HAS_USER_ITEM(13)
+ _USER_ITEM(13)
+ #endif
+ #if HAS_USER_ITEM(14)
+ _USER_ITEM(14)
+ #endif
+ #if HAS_USER_ITEM(15)
+ _USER_ITEM(15)
+ #endif
+ #if HAS_USER_ITEM(16)
+ _USER_ITEM(16)
+ #endif
+ #if HAS_USER_ITEM(17)
+ _USER_ITEM(17)
+ #endif
+ #if HAS_USER_ITEM(18)
+ _USER_ITEM(18)
+ #endif
+ #if HAS_USER_ITEM(19)
+ _USER_ITEM(19)
+ #endif
+ #if HAS_USER_ITEM(20)
+ _USER_ITEM(20)
+ #endif
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool CustomUserMenus::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ #if HAS_USER_ITEM(1)
+ _USER_ACTION(1)
+ #endif
+ #if HAS_USER_ITEM(2)
+ _USER_ACTION(2)
+ #endif
+ #if HAS_USER_ITEM(3)
+ _USER_ACTION(3)
+ #endif
+ #if HAS_USER_ITEM(4)
+ _USER_ACTION(4)
+ #endif
+ #if HAS_USER_ITEM(5)
+ _USER_ACTION(5)
+ #endif
+ #if HAS_USER_ITEM(6)
+ _USER_ACTION(6)
+ #endif
+ #if HAS_USER_ITEM(7)
+ _USER_ACTION(7)
+ #endif
+ #if HAS_USER_ITEM(8)
+ _USER_ACTION(8)
+ #endif
+ #if HAS_USER_ITEM(9)
+ _USER_ACTION(9)
+ #endif
+ #if HAS_USER_ITEM(10)
+ _USER_ACTION(10)
+ #endif
+ #if HAS_USER_ITEM(11)
+ _USER_ACTION(11)
+ #endif
+ #if HAS_USER_ITEM(12)
+ _USER_ACTION(12)
+ #endif
+ #if HAS_USER_ITEM(13)
+ _USER_ACTION(13)
+ #endif
+ #if HAS_USER_ITEM(14)
+ _USER_ACTION(14)
+ #endif
+ #if HAS_USER_ITEM(15)
+ _USER_ACTION(15)
+ #endif
+ #if HAS_USER_ITEM(16)
+ _USER_ACTION(16)
+ #endif
+ #if HAS_USER_ITEM(17)
+ _USER_ACTION(17)
+ #endif
+ #if HAS_USER_ITEM(18)
+ _USER_ACTION(18)
+ #endif
+ #if HAS_USER_ITEM(19)
+ _USER_ACTION(19)
+ #endif
+ #if HAS_USER_ITEM(20)
+ _USER_ACTION(20)
+ #endif
+
+ case 1: GOTO_PREVIOUS(); break;
+ default: return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && CUSTOM_USER_MENUS && !TOUCH_UI_LULZBOT_BIO && !TOUCH_UI_COCOA_PRESS
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/default_acceleration_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/default_acceleration_screen.cpp
new file mode 100644
index 0000000..de617d4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/default_acceleration_screen.cpp
@@ -0,0 +1,63 @@
+/***********************************
+ * default_acceleration_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void DefaultAccelerationScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(0);
+ w.units(GET_TEXT_F(MSG_UNITS_MM_S2));
+ w.heading( GET_TEXT_F(MSG_ACCELERATION));
+ w.color(other);
+ w.adjuster( 2, GET_TEXT_F(MSG_ACCEL_PRINTING), getPrintingAcceleration_mm_s2() );
+ w.adjuster( 4, GET_TEXT_F(MSG_ACCEL_TRAVEL), getTravelAcceleration_mm_s2() );
+ w.adjuster( 6, GET_TEXT_F(MSG_ACCEL_RETRACT), getRetractAcceleration_mm_s2() );
+ w.increments();
+ w.button( 8, GET_TEXT_F(MSG_SET_MAXIMUM));
+}
+
+bool DefaultAccelerationScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(PrintingAcceleration_mm_s2); break;
+ case 3: UI_INCREMENT(PrintingAcceleration_mm_s2); break;
+ case 4: UI_DECREMENT(TravelAcceleration_mm_s2); break;
+ case 5: UI_INCREMENT(TravelAcceleration_mm_s2); break;
+ case 6: UI_DECREMENT(RetractAcceleration_mm_s2); break;
+ case 7: UI_INCREMENT(RetractAcceleration_mm_s2); break;
+ case 8: GOTO_SCREEN(MaxAccelerationScreen); break;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/developer_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/developer_menu.cpp
new file mode 100644
index 0000000..9df060a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/developer_menu.cpp
@@ -0,0 +1,150 @@
+/**********************
+ * developer_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU)
+
+#include "screens.h"
+
+#include "../archim2-flash/flash_storage.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void DeveloperMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .font(font_medium)
+ .tag(0);
+
+ #ifdef SPI_FLASH_SS
+ constexpr bool has_flash = true;
+ #else
+ constexpr bool has_flash = false;
+ #endif
+
+ #if ENABLED(SDSUPPORT)
+ constexpr bool has_media = true;
+ #else
+ constexpr bool has_media = false;
+ #endif
+
+ cmd.cmd(COLOR_RGB(bg_text_enabled));
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 10
+ #define GRID_COLS 1
+ cmd.font(font_large) .text ( BTN_POS(1,1), BTN_SIZE(1,1), F("Developer Menu"))
+ .colors(normal_btn)
+ .tag(2).font(font_medium) .button(BTN_POS(1,2), BTN_SIZE(1,1), F("Show All Widgets"))
+ .tag(3) .button(BTN_POS(1,3), BTN_SIZE(1,1), F("Stress Test"))
+ .tag(4) .button(BTN_POS(1,4), BTN_SIZE(1,1), F("Show Touch Registers"))
+ .tag(5) .button(BTN_POS(1,5), BTN_SIZE(1,1), F("Play Song"))
+ .tag(6).enabled(has_media).button(BTN_POS(1,6), BTN_SIZE(1,1), F("Play Video from Media"))
+ .tag(7).enabled(has_flash).button(BTN_POS(1,7), BTN_SIZE(1,1), F("Play Video from SPI Flash"))
+ .tag(8).enabled(has_flash).button(BTN_POS(1,8), BTN_SIZE(1,1), F("Load Video to SPI Flash"))
+ .tag(9).enabled(has_flash).button(BTN_POS(1,9), BTN_SIZE(1,1), F("Erase SPI Flash"))
+
+ .tag(1).colors(action_btn)
+ .button(BTN_POS(1,10), BTN_SIZE(1,1), F("Back"));
+ #else
+ #define GRID_ROWS 6
+ #define GRID_COLS 2
+ cmd.font(font_medium) .text ( BTN_POS(1,1), BTN_SIZE(2,1), F("Developer Menu"))
+ .colors(normal_btn)
+ .tag(2).font(font_small) .button(BTN_POS(1,2), BTN_SIZE(1,1), F("Show All Widgets"))
+ .tag(3) .button(BTN_POS(1,3), BTN_SIZE(1,1), F("Show Touch Registers"))
+ .tag(9) .button(BTN_POS(1,4), BTN_SIZE(1,1), F("Show Pin States"))
+ .tag(4) .button(BTN_POS(1,5), BTN_SIZE(1,1), F("Play Song"))
+ .tag(5).enabled(has_media).button(BTN_POS(2,2), BTN_SIZE(1,1), F("Play Video from Media"))
+ .tag(6).enabled(has_flash).button(BTN_POS(2,3), BTN_SIZE(1,1), F("Play Video from SPI Flash"))
+ .tag(7).enabled(has_flash).button(BTN_POS(2,4), BTN_SIZE(1,1), F("Load Video to SPI Flash"))
+ .tag(8).enabled(has_flash).button(BTN_POS(2,5), BTN_SIZE(1,1), F("Erase SPI Flash"))
+ .tag(1).colors(action_btn)
+ .button(BTN_POS(1,6), BTN_SIZE(2,1), F("Back"));
+ #endif
+ }
+}
+
+bool DeveloperMenu::onTouchEnd(uint8_t tag) {
+ using namespace Theme;
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2: GOTO_SCREEN(WidgetsScreen); break;
+ case 3:
+ PUSH_SCREEN(StressTestScreen);
+ AlertDialogBox::show(F("Please do not run this test unattended as it may cause your printer to malfunction."));
+ current_screen.forget();
+ break;
+ case 4: GOTO_SCREEN(TouchRegistersScreen); break;
+ case 5: sound.play(js_bach_joy, PLAY_ASYNCHRONOUS); break;
+ #if ENABLED(SDSUPPORT)
+ case 6:
+ if (!MediaPlayerScreen::playCardMedia())
+ AlertDialogBox::showError(F("Cannot open STARTUP.AVI"));
+ break;
+ #endif
+ #ifdef SPI_FLASH_SS
+ case 7:
+ if (!MediaPlayerScreen::playBootMedia())
+ AlertDialogBox::showError(F("No boot media available"));
+ break;
+ case 8:
+ {
+ SpinnerDialogBox::show(F("Saving..."));
+ UIFlashStorage::error_t res = UIFlashStorage::write_media_file(F("STARTUP.AVI"));
+ SpinnerDialogBox::hide();
+ reset_menu_timeout();
+ switch (res) {
+ case UIFlashStorage::SUCCESS:
+ AlertDialogBox::show(F("File copied!"));
+ break;
+
+ case UIFlashStorage::READ_ERROR:
+ AlertDialogBox::showError(F("Failed to read file"));
+ break;
+
+ case UIFlashStorage::VERIFY_ERROR:
+ AlertDialogBox::showError(F("Failed to verify file"));
+ break;
+
+ case UIFlashStorage::FILE_NOT_FOUND:
+ AlertDialogBox::showError(F("Cannot open STARTUP.AVI"));
+ break;
+
+ case UIFlashStorage::WOULD_OVERWRITE:
+ AlertDialogBox::showError(F("Cannot overwrite existing media."));
+ break;
+ }
+ break;
+ }
+ case 9: GOTO_SCREEN(ConfirmEraseFlashDialogBox); break;
+ #endif
+ case 10: GOTO_SCREEN(EndstopStatesScreen); break;
+ default: return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/dialog_box_base_class.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/dialog_box_base_class.cpp
new file mode 100644
index 0000000..6fe7be4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/dialog_box_base_class.cpp
@@ -0,0 +1,87 @@
+/*****************************
+ * dialog_box_base_class.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 8
+
+template<typename T>
+void DialogBoxBaseClass::drawMessage(const T message, int16_t font) {
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+ draw_text_box(cmd, BTN_POS(1,1), BTN_SIZE(2,3), message, OPT_CENTER, font ? font : font_large);
+ cmd.colors(normal_btn);
+}
+
+template void DialogBoxBaseClass::drawMessage(const char *, int16_t font);
+template void DialogBoxBaseClass::drawMessage(progmem_str, int16_t font);
+
+void DialogBoxBaseClass::drawYesNoButtons(uint8_t default_btn) {
+ CommandProcessor cmd;
+ cmd.font(font_medium)
+ .colors(default_btn == 1 ? action_btn : normal_btn).tag(1).button(BTN_POS(1,8), BTN_SIZE(1,1), GET_TEXT_F(MSG_YES))
+ .colors(default_btn == 2 ? action_btn : normal_btn).tag(2).button(BTN_POS(2,8), BTN_SIZE(1,1), GET_TEXT_F(MSG_NO));
+}
+
+void DialogBoxBaseClass::drawOkayButton() {
+ CommandProcessor cmd;
+ cmd.font(font_medium)
+ .tag(1).button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_BUTTON_OKAY));
+}
+
+void DialogBoxBaseClass::drawButton(const progmem_str label) {
+ CommandProcessor cmd;
+ cmd.font(font_medium)
+ .tag(1).button(BTN_POS(1,8), BTN_SIZE(2,1), label);
+}
+
+void DialogBoxBaseClass::drawSpinner() {
+ CommandProcessor cmd;
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .spinner(BTN_POS(1,4), BTN_SIZE(2,3)).execute();
+}
+
+bool DialogBoxBaseClass::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); return true;
+ case 2: GOTO_PREVIOUS(); return true;
+ default: return false;
+ }
+}
+
+void DialogBoxBaseClass::onIdle() {
+ reset_menu_timeout();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/display_tuning_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/display_tuning_screen.cpp
new file mode 100644
index 0000000..1a4d9fd
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/display_tuning_screen.cpp
@@ -0,0 +1,61 @@
+/*****************************
+ * display_tuning_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void DisplayTuningScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(0, BaseNumericAdjustmentScreen::DEFAULT_LOWEST);
+ w.units(F(""));
+ w.heading(GET_TEXT_F(MSG_DISPLAY_MENU));
+ w.color(other);
+ w.adjuster( 2, GET_TEXT_F(MSG_H_OFFSET), CLCD::mem_read_16(CLCD::REG::HOFFSET) );
+ w.adjuster( 4, GET_TEXT_F(MSG_V_OFFSET), CLCD::mem_read_16(CLCD::REG::VOFFSET) );
+ w.increments();
+ w.heading( GET_TEXT_F(MSG_TOUCH_SCREEN));
+ w.button(6, GET_TEXT_F(MSG_CALIBRATE));
+}
+
+bool DisplayTuningScreen::onTouchHeld(uint8_t tag) {
+ #define REG_INCREMENT(a,i) CLCD::mem_write_16(CLCD::REG::a, CLCD::mem_read_16(CLCD::REG::a) + i)
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: REG_INCREMENT(HOFFSET, -increment); break;
+ case 3: REG_INCREMENT(HOFFSET, increment); break;
+ case 4: REG_INCREMENT(VOFFSET, -increment); break;
+ case 5: REG_INCREMENT(VOFFSET, increment); break;
+ case 6: GOTO_SCREEN(TouchCalibrationScreen); break;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/endstop_state_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/endstop_state_screen.cpp
new file mode 100644
index 0000000..a091197
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/endstop_state_screen.cpp
@@ -0,0 +1,152 @@
+/****************************
+ * endstop_state_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+void EndstopStatesScreen::onEntry() {
+ BaseScreen::onEntry();
+}
+
+void EndstopStatesScreen::onExit() {
+ BaseScreen::onExit();
+}
+
+void EndstopStatesScreen::onRedraw(draw_mode_t) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+
+ #define GRID_ROWS 7
+ #define GRID_COLS 6
+
+ #define PIN_BTN(X,Y,PIN,LABEL) button(BTN_POS(X,Y), BTN_SIZE(2,1), LABEL)
+ #define PIN_ENABLED(X,Y,LABEL,PIN,INV) cmd.enabled(1).colors(READ(PIN##_PIN) != INV ? action_btn : normal_btn).PIN_BTN(X,Y,PIN,LABEL);
+ #define PIN_DISABLED(X,Y,LABEL,PIN) cmd.enabled(0).PIN_BTN(X,Y,PIN,LABEL);
+
+ cmd.font(
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ font_large
+ #else
+ font_medium
+ #endif
+ )
+ .text(BTN_POS(1,1), BTN_SIZE(6,1), GET_TEXT_F(MSG_LCD_ENDSTOPS))
+ .font(font_tiny);
+ #if PIN_EXISTS(X_MAX)
+ PIN_ENABLED (1, 2, PSTR(STR_X_MAX), X_MAX, X_MAX_ENDSTOP_INVERTING)
+ #else
+ PIN_DISABLED(1, 2, PSTR(STR_X_MAX), X_MAX)
+ #endif
+ #if PIN_EXISTS(Y_MAX)
+ PIN_ENABLED (3, 2, PSTR(STR_Y_MAX), Y_MAX, Y_MAX_ENDSTOP_INVERTING)
+ #else
+ PIN_DISABLED(3, 2, PSTR(STR_Y_MAX), Y_MAX)
+ #endif
+ #if PIN_EXISTS(Z_MAX)
+ PIN_ENABLED (5, 2, PSTR(STR_Z_MAX), Z_MAX, Z_MAX_ENDSTOP_INVERTING)
+ #else
+ PIN_DISABLED(5, 2, PSTR(STR_Z_MAX), Z_MAX)
+ #endif
+ #if PIN_EXISTS(X_MIN)
+ PIN_ENABLED (1, 3, PSTR(STR_X_MIN), X_MIN, X_MIN_ENDSTOP_INVERTING)
+ #else
+ PIN_DISABLED(1, 3, PSTR(STR_X_MIN), X_MIN)
+ #endif
+ #if PIN_EXISTS(Y_MIN)
+ PIN_ENABLED (3, 3, PSTR(STR_Y_MIN), Y_MIN, Y_MIN_ENDSTOP_INVERTING)
+ #else
+ PIN_DISABLED(3, 3, PSTR(STR_Y_MIN), Y_MIN)
+ #endif
+ #if PIN_EXISTS(Z_MIN)
+ PIN_ENABLED (5, 3, PSTR(STR_Z_MIN), Z_MIN, Z_MIN_ENDSTOP_INVERTING)
+ #else
+ PIN_DISABLED(5, 3, PSTR(STR_Z_MIN), Z_MIN)
+ #endif
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR) && PIN_EXISTS(FIL_RUNOUT)
+ PIN_ENABLED (1, 4, GET_TEXT_F(MSG_RUNOUT_1), FIL_RUNOUT, FIL_RUNOUT1_STATE)
+ #else
+ PIN_DISABLED(1, 4, GET_TEXT_F(MSG_RUNOUT_1), FIL_RUNOUT)
+ #endif
+ #if BOTH(HAS_MULTI_EXTRUDER, FILAMENT_RUNOUT_SENSOR) && PIN_EXISTS(FIL_RUNOUT2)
+ PIN_ENABLED (3, 4, GET_TEXT_F(MSG_RUNOUT_2), FIL_RUNOUT2, FIL_RUNOUT2_STATE)
+ #else
+ PIN_DISABLED(3, 4, GET_TEXT_F(MSG_RUNOUT_2), FIL_RUNOUT2)
+ #endif
+ #if PIN_EXISTS(Z_MIN_PROBE)
+ PIN_ENABLED (5, 4, PSTR(STR_Z_PROBE), Z_MIN_PROBE, Z_MIN_PROBE_ENDSTOP_INVERTING)
+ #else
+ PIN_DISABLED(5, 4, PSTR(STR_Z_PROBE), Z_MIN_PROBE)
+ #endif
+
+ #if HAS_SOFTWARE_ENDSTOPS
+ #undef EDGE_R
+ #define EDGE_R 30
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .font(font_small)
+ .text (BTN_POS(1,5), BTN_SIZE(3,1), GET_TEXT_F(MSG_LCD_SOFT_ENDSTOPS), OPT_RIGHTX | OPT_CENTERY)
+ .colors(ui_toggle)
+ .tag(2).toggle2(BTN_POS(4,5), BTN_SIZE(3,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), getSoftEndstopState());
+ #undef EDGE_R
+ #define EDGE_R 0
+ #endif
+
+ cmd.font(font_medium)
+ .colors(action_btn)
+ .tag(1).button(BTN_POS(1,7), BTN_SIZE(6,1), GET_TEXT_F(MSG_BACK));
+ #undef GRID_COLS
+ #undef GRID_ROWS
+}
+
+bool EndstopStatesScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ #if HAS_SOFTWARE_ENDSTOPS
+ case 2: setSoftEndstopState(!getSoftEndstopState());
+ #endif
+ default:
+ return false;
+ }
+ return true;
+}
+
+void EndstopStatesScreen::onIdle() {
+ constexpr uint32_t DIAGNOSTICS_UPDATE_INTERVAL = 100;
+
+ if (refresh_timer.elapsed(DIAGNOSTICS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ reset_menu_timeout();
+ }
+ BaseScreen::onIdle();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/feedrate_percent_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/feedrate_percent_screen.cpp
new file mode 100644
index 0000000..28f0e6a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/feedrate_percent_screen.cpp
@@ -0,0 +1,52 @@
+/*******************************
+ * feedrate_percent_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+
+void FeedratePercentScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(0).units(GET_TEXT_F(MSG_UNITS_PERCENT));
+
+ w.heading(GET_TEXT_F(MSG_PRINT_SPEED));
+ w.adjuster(4, GET_TEXT_F(MSG_SPEED), getFeedrate_percent());
+ w.increments();
+}
+
+bool FeedratePercentScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 4: UI_DECREMENT(Feedrate_percent); break;
+ case 5: UI_INCREMENT(Feedrate_percent); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_menu.cpp
new file mode 100644
index 0000000..f63fc41
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_menu.cpp
@@ -0,0 +1,85 @@
+/*********************
+ * filament_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && ANY(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 9
+ #define GRID_COLS 2
+ #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1)
+ #define RUNOUT_SENSOR_POS BTN_POS(1,2), BTN_SIZE(2,1)
+ #define LIN_ADVANCE_POS BTN_POS(1,3), BTN_SIZE(2,1)
+ #define BACK_POS BTN_POS(1,9), BTN_SIZE(2,1)
+#else
+ #define GRID_ROWS 6
+ #define GRID_COLS 2
+ #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1)
+ #define RUNOUT_SENSOR_POS BTN_POS(1,2), BTN_SIZE(2,1)
+ #define LIN_ADVANCE_POS BTN_POS(1,3), BTN_SIZE(2,1)
+ #define BACK_POS BTN_POS(1,6), BTN_SIZE(2,1)
+#endif
+
+void FilamentMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.font(font_large)
+ .text(TITLE_POS, GET_TEXT_F(MSG_FILAMENT))
+ .font(font_medium).colors(normal_btn)
+ .enabled(ENABLED(FILAMENT_RUNOUT_SENSOR))
+ .tag(2).button(RUNOUT_SENSOR_POS, GET_TEXT_F(MSG_RUNOUT_SENSOR))
+ .enabled(ENABLED(LIN_ADVANCE))
+ .tag(3).button(LIN_ADVANCE_POS, GET_TEXT_F(MSG_LINEAR_ADVANCE))
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool FilamentMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ case 2: GOTO_SCREEN(FilamentRunoutScreen); break;
+ #endif
+ #if ENABLED(LIN_ADVANCE)
+ case 3: GOTO_SCREEN(LinearAdvanceScreen); break;
+ #endif
+ default: return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp
new file mode 100644
index 0000000..41e3be2
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp
@@ -0,0 +1,65 @@
+/******************************
+ * filament_runout_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, FILAMENT_RUNOUT_SENSOR)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void FilamentRunoutScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.heading( GET_TEXT_F(MSG_FILAMENT));
+ w.toggle( 2, GET_TEXT_F(MSG_RUNOUT_SENSOR), getFilamentRunoutEnabled());
+
+ #if HAS_FILAMENT_RUNOUT_DISTANCE
+ w.heading(GET_TEXT_F(MSG_RUNOUT_DISTANCE_MM));
+ w.units(GET_TEXT_F(MSG_UNITS_MM));
+ w.precision(0);
+ w.color(e_axis);
+ w.adjuster( 10, progmem_str(NUL_STR), getFilamentRunoutDistance_mm(), getFilamentRunoutEnabled());
+ w.increments();
+ #endif
+}
+
+bool FilamentRunoutScreen::onTouchHeld(uint8_t tag) {
+ using namespace ExtUI;
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: setFilamentRunoutEnabled(!getFilamentRunoutEnabled()); break;
+ #if HAS_FILAMENT_RUNOUT_DISTANCE
+ case 10: UI_DECREMENT(FilamentRunoutDistance_mm); break;
+ case 11: UI_INCREMENT(FilamentRunoutDistance_mm); break;
+ #endif
+ default:
+ return false;
+ }
+
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp
new file mode 100644
index 0000000..cadc582
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp
@@ -0,0 +1,264 @@
+/********************
+ * files_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, SDSUPPORT)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void FilesScreen::onEntry() {
+ screen_data.Files.cur_page = 0;
+ screen_data.Files.selected_tag = 0xFF;
+ #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810)
+ CLCD::mem_write_32(CLCD::REG::MACRO_0,DL::NOP);
+ #endif
+ gotoPage(0);
+ BaseScreen::onEntry();
+}
+
+const char *FilesScreen::getSelectedFilename(bool longName) {
+ FileList files;
+ files.seek(getSelectedFileIndex(), true);
+ return longName ? files.longFilename() : files.shortFilename();
+}
+
+void FilesScreen::drawSelectedFile() {
+ FileList files;
+ files.seek(getSelectedFileIndex(), true);
+ screen_data.Files.flags.is_dir = files.isDir();
+ drawFileButton(
+ files.filename(),
+ screen_data.Files.selected_tag,
+ screen_data.Files.flags.is_dir,
+ true
+ );
+}
+
+uint16_t FilesScreen::getSelectedFileIndex() {
+ return getFileForTag(screen_data.Files.selected_tag);
+}
+
+uint16_t FilesScreen::getFileForTag(uint8_t tag) {
+ return screen_data.Files.cur_page * files_per_page + tag - 2;
+}
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_COLS 6
+ #define GRID_ROWS (files_per_page + header_h + footer_h)
+#else
+ #define GRID_COLS 6
+ #define GRID_ROWS (files_per_page + header_h + footer_h)
+#endif
+
+void FilesScreen::drawFileButton(const char* filename, uint8_t tag, bool is_dir, bool is_highlighted) {
+ const uint8_t line = getLineForTag(tag)+1;
+ CommandProcessor cmd;
+ cmd.tag(tag);
+ cmd.cmd(COLOR_RGB(is_highlighted ? fg_action : bg_color));
+ cmd.font(font_medium)
+ .rectangle( 0, BTN_Y(header_h+line), display_width, BTN_H(1));
+ cmd.cmd(COLOR_RGB(is_highlighted ? normal_btn.rgb : bg_text_enabled));
+ constexpr uint16_t dim[2] = {BTN_SIZE(6,1)};
+ #define POS_AND_SHORTEN(SHORTEN) BTN_POS(1,header_h+line), dim[0] - (SHORTEN), dim[1]
+ #define POS_AND_SIZE POS_AND_SHORTEN(0)
+ #if ENABLED(SCROLL_LONG_FILENAMES)
+ if (is_highlighted) {
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(MACRO(0));
+ cmd.text(POS_AND_SIZE, filename, OPT_CENTERY | OPT_NOFIT);
+ } else
+ #endif
+ draw_text_with_ellipsis(cmd, POS_AND_SHORTEN(is_dir ? 20 : 0), filename, OPT_CENTERY, font_medium);
+ if (is_dir && !is_highlighted) {
+ cmd.text(POS_AND_SIZE, F("> "), OPT_CENTERY | OPT_RIGHTX);
+ }
+ #if ENABLED(SCROLL_LONG_FILENAMES)
+ if (is_highlighted) {
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+ #endif
+}
+
+void FilesScreen::drawFileList() {
+ FileList files;
+ screen_data.Files.num_page = max(1,ceil(float(files.count()) / files_per_page));
+ screen_data.Files.cur_page = min(screen_data.Files.cur_page, screen_data.Files.num_page-1);
+ screen_data.Files.flags.is_root = files.isAtRootDir();
+
+ #undef MARGIN_T
+ #undef MARGIN_B
+ #define MARGIN_T 0
+ #define MARGIN_B 0
+ uint16_t fileIndex = screen_data.Files.cur_page * files_per_page;
+ for (uint8_t i = 0; i < files_per_page; i++, fileIndex++) {
+ if (files.seek(fileIndex)) {
+ drawFileButton(files.filename(), getTagForLine(i), files.isDir(), false);
+ }
+ else {
+ break;
+ }
+ }
+}
+
+void FilesScreen::drawHeader() {
+ const bool prev_enabled = screen_data.Files.cur_page > 0;
+ const bool next_enabled = screen_data.Files.cur_page < (screen_data.Files.num_page - 1);
+
+ #undef MARGIN_T
+ #undef MARGIN_B
+ #define MARGIN_T 0
+ #define MARGIN_B 2
+
+ char str[16];
+ sprintf_P(str, PSTR("Page %d of %d"),
+ screen_data.Files.cur_page + 1, screen_data.Files.num_page);
+
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_small)
+ .tag(0).button(BTN_POS(2,1), BTN_SIZE(4,header_h), str, OPT_CENTER | OPT_FLAT)
+ .font(font_medium)
+ .colors(action_btn)
+ .tag(241).enabled(prev_enabled).button(BTN_POS(1,1), BTN_SIZE(1,header_h), F("<"))
+ .tag(242).enabled(next_enabled).button(BTN_POS(6,1), BTN_SIZE(1,header_h), F(">"));
+}
+
+void FilesScreen::drawFooter() {
+ #undef MARGIN_T
+ #undef MARGIN_B
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define MARGIN_T 15
+ #define MARGIN_B 5
+ #else
+ #define MARGIN_T 5
+ #define MARGIN_B 5
+ #endif
+ const bool has_selection = screen_data.Files.selected_tag != 0xFF;
+ const uint8_t back_tag = screen_data.Files.flags.is_root ? 240 : 245;
+ const uint8_t y = GRID_ROWS - footer_h + 1;
+ const uint8_t h = footer_h;
+
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .colors(has_selection ? normal_btn : action_btn)
+ .tag(back_tag).button(BTN_POS(4,y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BACK))
+ .enabled(has_selection)
+ .colors(has_selection ? action_btn : normal_btn);
+
+ if (screen_data.Files.flags.is_dir)
+ cmd.tag(244).button(BTN_POS(1, y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BUTTON_OPEN));
+ else
+ cmd.tag(243).button(BTN_POS(1, y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BUTTON_PRINT));
+}
+
+void FilesScreen::onRedraw(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ drawHeader();
+ drawSelectedFile();
+ drawFooter();
+ }
+}
+
+void FilesScreen::gotoPage(uint8_t page) {
+ screen_data.Files.selected_tag = 0xFF;
+ screen_data.Files.cur_page = page;
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .colors(normal_btn);
+ drawFileList();
+ storeBackground();
+}
+
+bool FilesScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 240: GOTO_PREVIOUS(); return true;
+ case 241:
+ if (screen_data.Files.cur_page > 0) {
+ gotoPage(screen_data.Files.cur_page-1);
+ }
+ break;
+ case 242:
+ if (screen_data.Files.cur_page < (screen_data.Files.num_page-1)) {
+ gotoPage(screen_data.Files.cur_page+1);
+ }
+ break;
+ case 243:
+ ConfirmStartPrintDialogBox::show(getSelectedFileIndex());
+ return true;
+ case 244:
+ {
+ FileList files;
+ files.changeDir(getSelectedShortFilename());
+ gotoPage(0);
+ }
+ break;
+ case 245:
+ {
+ FileList files;
+ files.upDir();
+ gotoPage(0);
+ }
+ break;
+ default:
+ if (tag < 240) {
+ screen_data.Files.selected_tag = tag;
+ #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810)
+ if (FTDI::ftdi_chip >= 810) {
+ const char *longFilename = getSelectedLongFilename();
+ if (longFilename[0]) {
+ CommandProcessor cmd;
+ uint16_t text_width = cmd.font(font_medium).text_width(longFilename);
+ screen_data.Files.scroll_pos = 0;
+ if (text_width > display_width)
+ screen_data.Files.scroll_max = text_width - display_width + MARGIN_L + MARGIN_R;
+ else
+ screen_data.Files.scroll_max = 0;
+ }
+ }
+ #endif
+ }
+ break;
+ }
+ return true;
+}
+
+void FilesScreen::onIdle() {
+ #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810)
+ if (FTDI::ftdi_chip >= 810) {
+ CLCD::mem_write_32(CLCD::REG::MACRO_0,
+ VERTEX_TRANSLATE_X(-int32_t(screen_data.Files.scroll_pos)));
+ if (screen_data.Files.scroll_pos < screen_data.Files.scroll_max * 16)
+ screen_data.Files.scroll_pos++;
+ }
+ #endif
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_settings_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_settings_screen.cpp
new file mode 100644
index 0000000..3d50b61
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_settings_screen.cpp
@@ -0,0 +1,291 @@
+/*********************************
+ * interface_settings_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+#include "../archim2-flash/flash_storage.h"
+
+#include "../../../../../module/settings.h"
+
+#if ENABLED(LULZBOT_PRINTCOUNTER)
+ #include "../../../../../module/printcounter.h"
+#endif
+
+bool restoreEEPROM();
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+constexpr bool PERSISTENT_STORE_SUCCESS = false; // persistentStore uses true for error
+
+void InterfaceSettingsScreen::onStartup() {
+}
+
+void InterfaceSettingsScreen::onEntry() {
+ screen_data.InterfaceSettings.brightness = CLCD::get_brightness();
+ screen_data.InterfaceSettings.volume = SoundPlayer::get_volume();
+ BaseScreen::onEntry();
+}
+
+void InterfaceSettingsScreen::onRedraw(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+
+ #define GRID_COLS 4
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 7
+ #else
+ #define GRID_ROWS 6
+ #endif
+
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+ .font(font_medium)
+ .text(BTN_POS(1,1), BTN_SIZE(4,1), GET_TEXT_F(MSG_INTERFACE))
+ #undef EDGE_R
+ #define EDGE_R 30
+ .font(font_small)
+ .tag(0)
+ #if DISABLED(LCD_FYSETC_TFT81050)
+ .text(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_LCD_BRIGHTNESS), OPT_RIGHTX | OPT_CENTERY)
+ #endif
+ .text(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_SOUND_VOLUME), OPT_RIGHTX | OPT_CENTERY)
+ .text(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_SCREEN_LOCK), OPT_RIGHTX | OPT_CENTERY);
+ #if DISABLED(TOUCH_UI_NO_BOOTSCREEN)
+ cmd.text(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_BOOT_SCREEN), OPT_RIGHTX | OPT_CENTERY);
+ #endif
+ #undef EDGE_R
+ }
+
+ if (what & FOREGROUND) {
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ constexpr uint8_t w = 2;
+ #else
+ constexpr uint8_t w = 1;
+ #endif
+
+ cmd.font(font_medium)
+ #define EDGE_R 30
+ .colors(ui_slider)
+ #if DISABLED(LCD_FYSETC_TFT81050)
+ .tag(2).slider(BTN_POS(3,2), BTN_SIZE(2,1), screen_data.InterfaceSettings.brightness, 128)
+ #endif
+ .tag(3).slider(BTN_POS(3,3), BTN_SIZE(2,1), screen_data.InterfaceSettings.volume, 0xFF)
+ .colors(ui_toggle)
+ .tag(4).toggle2(BTN_POS(3,4), BTN_SIZE(w,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), LockScreen::is_enabled())
+ #if DISABLED(TOUCH_UI_NO_BOOTSCREEN)
+ .tag(5).toggle2(BTN_POS(3,5), BTN_SIZE(w,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), UIData::animations_enabled())
+ #endif
+ #undef EDGE_R
+ #define EDGE_R 0
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ .colors(normal_btn)
+ .tag(6).button (BTN_POS(1,6), BTN_SIZE(4,1), GET_TEXT_F(MSG_SOUNDS))
+ .colors(action_btn)
+ .tag(1).button (BTN_POS(1,7), BTN_SIZE(4,1), GET_TEXT_F(MSG_BACK));
+ #else
+ .tag(6).button (BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_SOUNDS))
+ .colors(action_btn)
+ .tag(1).button (BTN_POS(3,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_BACK));
+ #endif
+ }
+}
+
+bool InterfaceSettingsScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); return true;
+ case 4:
+ if (!LockScreen::is_enabled())
+ LockScreen::enable();
+ else
+ LockScreen::disable();
+ break;
+ case 5: UIData::enable_animations(!UIData::animations_enabled());; break;
+ case 6: GOTO_SCREEN(InterfaceSoundsScreen); return true;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+bool InterfaceSettingsScreen::onTouchStart(uint8_t tag) {
+ #undef EDGE_R
+ #define EDGE_R 30
+ CommandProcessor cmd;
+ switch (tag) {
+ case 2: cmd.track_linear(BTN_POS(3,3), BTN_SIZE(2,1), 2).execute(); break;
+ case 3: cmd.track_linear(BTN_POS(3,4), BTN_SIZE(2,1), 3).execute(); break;
+ default: break;
+ }
+ #undef EDGE_R
+ #define EDGE_R 0
+ #undef GRID_COLS
+ #undef GRID_ROWS
+ return true;
+}
+
+void InterfaceSettingsScreen::onIdle() {
+ if (refresh_timer.elapsed(TOUCH_UPDATE_INTERVAL)) {
+ refresh_timer.start();
+
+ uint16_t value;
+ CommandProcessor cmd;
+ switch (cmd.track_tag(value)) {
+ case 2:
+ screen_data.InterfaceSettings.brightness = max(11, (value * 128UL) / 0xFFFF);
+ CLCD::set_brightness(screen_data.InterfaceSettings.brightness);
+ SaveSettingsDialogBox::settingsChanged();
+ break;
+ case 3:
+ screen_data.InterfaceSettings.volume = value >> 8;
+ SoundPlayer::set_volume(screen_data.InterfaceSettings.volume);
+ SaveSettingsDialogBox::settingsChanged();
+ break;
+ default:
+ return;
+ }
+ onRefresh();
+ }
+ BaseScreen::onIdle();
+}
+
+void InterfaceSettingsScreen::failSafeSettings() {
+ // Reset settings that may make the printer interface
+ // unusable.
+ CLCD::mem_write_32(CLCD::REG::ROTATE, 0);
+ CLCD::default_touch_transform();
+ CLCD::default_display_orientation();
+ CLCD::set_brightness(255);
+ UIData::reset_persistent_data();
+ CLCD::mem_write_16(CLCD::REG::HOFFSET, FTDI::Hoffset);
+ CLCD::mem_write_16(CLCD::REG::VOFFSET, FTDI::Voffset);
+}
+
+void InterfaceSettingsScreen::defaultSettings() {
+ LockScreen::passcode = 0;
+ SoundPlayer::set_volume(255);
+ CLCD::set_brightness(255);
+ UIData::reset_persistent_data();
+ InterfaceSoundsScreen::defaultSettings();
+ CLCD::mem_write_16(CLCD::REG::HOFFSET, FTDI::Hoffset);
+ CLCD::mem_write_16(CLCD::REG::VOFFSET, FTDI::Voffset);
+}
+
+void InterfaceSettingsScreen::saveSettings(char *buff) {
+ static_assert(
+ ExtUI::eeprom_data_size >= sizeof(persistent_data_t),
+ "Insufficient space in EEPROM for UI parameters"
+ );
+
+ SERIAL_ECHOLNPGM("Writing setting to EEPROM");
+
+ persistent_data_t eeprom;
+
+ eeprom.passcode = LockScreen::passcode;
+ eeprom.sound_volume = SoundPlayer::get_volume();
+ eeprom.display_brightness = CLCD::get_brightness();
+ eeprom.bit_flags = UIData::get_persistent_data();
+ eeprom.touch_transform_a = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_A);
+ eeprom.touch_transform_b = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_B);
+ eeprom.touch_transform_c = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_C);
+ eeprom.touch_transform_d = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_D);
+ eeprom.touch_transform_e = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_E);
+ eeprom.touch_transform_f = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_F);
+ eeprom.display_h_offset_adj = CLCD::mem_read_16(CLCD::REG::HOFFSET) - FTDI::Hoffset;
+ eeprom.display_v_offset_adj = CLCD::mem_read_16(CLCD::REG::VOFFSET) - FTDI::Voffset;
+ for (uint8_t i = 0; i < InterfaceSoundsScreen::NUM_EVENTS; i++)
+ eeprom.event_sounds[i] = InterfaceSoundsScreen::event_sounds[i];
+
+ memcpy(buff, &eeprom, sizeof(eeprom));
+}
+
+void InterfaceSettingsScreen::loadSettings(const char *buff) {
+ static_assert(
+ ExtUI::eeprom_data_size >= sizeof(persistent_data_t),
+ "Insufficient space in EEPROM for UI parameters"
+ );
+
+ persistent_data_t eeprom;
+ memcpy(&eeprom, buff, sizeof(eeprom));
+
+ SERIAL_ECHOLNPGM("Loading setting from EEPROM");
+
+ LockScreen::passcode = eeprom.passcode;
+ SoundPlayer::set_volume(eeprom.sound_volume);
+ UIData::set_persistent_data(eeprom.bit_flags);
+ CLCD::set_brightness(eeprom.display_brightness);
+ CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_A, eeprom.touch_transform_a);
+ CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_B, eeprom.touch_transform_b);
+ CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_C, eeprom.touch_transform_c);
+ CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_D, eeprom.touch_transform_d);
+ CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_E, eeprom.touch_transform_e);
+ CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_F, eeprom.touch_transform_f);
+ CLCD::mem_write_16(CLCD::REG::HOFFSET, eeprom.display_h_offset_adj + FTDI::Hoffset);
+ CLCD::mem_write_16(CLCD::REG::VOFFSET, eeprom.display_v_offset_adj + FTDI::Voffset);
+ for (uint8_t i = 0; i < InterfaceSoundsScreen::NUM_EVENTS; i++)
+ InterfaceSoundsScreen::event_sounds[i] = eeprom.event_sounds[i];
+
+ TERN_(TOUCH_UI_DEVELOPER_MENU, StressTestScreen::startupCheck());
+}
+
+#ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE
+ #include "../../../../../HAL/shared/eeprom_api.h"
+
+ bool restoreEEPROM() {
+ uint8_t data[ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE];
+
+ bool success = UIFlashStorage::read_config_data(data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE);
+
+ if (success)
+ success = persistentStore.write_data(0, data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE) == PERSISTENT_STORE_SUCCESS;
+
+ if (success)
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_EEPROM_RESTORED));
+ else
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_EEPROM_RESET));
+
+ return success;
+ }
+
+ bool InterfaceSettingsScreen::backupEEPROM() {
+ uint8_t data[ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE];
+
+ if (persistentStore.read_data(0, data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE) != PERSISTENT_STORE_SUCCESS)
+ return false;
+
+ UIFlashStorage::write_config_data(data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE);
+
+ return true;
+ }
+#endif
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_sounds_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_sounds_screen.cpp
new file mode 100644
index 0000000..9f21c6b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_sounds_screen.cpp
@@ -0,0 +1,160 @@
+/*******************************
+ * interface_sounds_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+uint8_t InterfaceSoundsScreen::event_sounds[];
+
+const char* InterfaceSoundsScreen::getSoundSelection(event_t event) {
+ return SoundList::name(event_sounds[event]);
+}
+
+void InterfaceSoundsScreen::toggleSoundSelection(event_t event) {
+ event_sounds[event] = (event_sounds[event]+1) % SoundList::n;
+ playEventSound(event);
+}
+
+void InterfaceSoundsScreen::setSoundSelection(event_t event, const SoundPlayer::sound_t* sound) {
+ for (uint8_t i = 0; i < SoundList::n; i++)
+ if (SoundList::data(i) == sound)
+ event_sounds[event] = i;
+}
+
+void InterfaceSoundsScreen::playEventSound(event_t event, play_mode_t mode) {
+ sound.play(SoundList::data(event_sounds[event]), mode);
+}
+
+void InterfaceSoundsScreen::defaultSettings() {
+ setSoundSelection(PRINTING_STARTED, twinkle);
+ setSoundSelection(PRINTING_FINISHED, fanfare);
+ setSoundSelection(PRINTING_FAILED, sad_trombone);
+}
+
+void InterfaceSoundsScreen::onRedraw(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+
+ #define GRID_COLS 4
+ #define GRID_ROWS 9
+
+ .font(font_medium)
+ .text(BTN_POS(1,1), BTN_SIZE(4,1), GET_TEXT_F(MSG_SOUNDS))
+ #undef EDGE_R
+ #define EDGE_R 30
+ .font(font_small)
+ .tag(0).text (BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_SOUND_VOLUME), OPT_RIGHTX | OPT_CENTERY)
+ .text (BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_CLICK_SOUNDS), OPT_RIGHTX | OPT_CENTERY)
+ .text (BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_STARTING), OPT_RIGHTX | OPT_CENTERY)
+ .text (BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_FINISHED), OPT_RIGHTX | OPT_CENTERY)
+ .text (BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_ERROR), OPT_RIGHTX | OPT_CENTERY);
+ #undef EDGE_R
+ }
+
+ if (what & FOREGROUND) {
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ constexpr uint8_t w = 2;
+ #else
+ constexpr uint8_t w = 1;
+ #endif
+
+ cmd.font(font_medium)
+ .colors(ui_slider)
+ #define EDGE_R 30
+ .tag(2).slider (BTN_POS(3,2), BTN_SIZE(2,1), screen_data.InterfaceSettings.volume, 0xFF)
+ .colors(ui_toggle)
+ .tag(3).toggle2 (BTN_POS(3,3), BTN_SIZE(w,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), UIData::touch_sounds_enabled())
+ #undef EDGE_R
+ .colors(normal_btn)
+ #define EDGE_R 0
+ .tag(4).button (BTN_POS(3,5), BTN_SIZE(2,1), getSoundSelection(PRINTING_STARTED))
+ .tag(5).button (BTN_POS(3,6), BTN_SIZE(2,1), getSoundSelection(PRINTING_FINISHED))
+ .tag(6).button (BTN_POS(3,7), BTN_SIZE(2,1), getSoundSelection(PRINTING_FAILED))
+ .colors(action_btn)
+ .tag(1).button (BTN_POS(1,9), BTN_SIZE(4,1), GET_TEXT_F(MSG_BACK));
+ }
+}
+
+void InterfaceSoundsScreen::onEntry() {
+ screen_data.InterfaceSettings.volume = SoundPlayer::get_volume();
+ BaseScreen::onEntry();
+}
+
+bool InterfaceSoundsScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); return true;
+ case 3: UIData::enable_touch_sounds(!UIData::touch_sounds_enabled()); break;
+ case 4: toggleSoundSelection(PRINTING_STARTED); break;
+ case 5: toggleSoundSelection(PRINTING_FINISHED); break;
+ case 6: toggleSoundSelection(PRINTING_FAILED); break;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+bool InterfaceSoundsScreen::onTouchStart(uint8_t tag) {
+ CommandProcessor cmd;
+ #undef EDGE_R
+ #define EDGE_R 30
+ switch (tag) {
+ case 2: cmd.track_linear(BTN_POS(3,2), BTN_SIZE(2,1), 2).execute(); break;
+ default: break;
+ }
+ return true;
+}
+
+void InterfaceSoundsScreen::onIdle() {
+ if (refresh_timer.elapsed(TOUCH_UPDATE_INTERVAL)) {
+ refresh_timer.start();
+
+ uint16_t value;
+ CommandProcessor cmd;
+ switch (cmd.track_tag(value)) {
+ case 2:
+ screen_data.InterfaceSettings.volume = value >> 8;
+ SoundPlayer::set_volume(screen_data.InterfaceSettings.volume);
+ SaveSettingsDialogBox::settingsChanged();
+ break;
+ default:
+ return;
+ }
+ onRefresh();
+ }
+ BaseScreen::onIdle();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/jerk_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/jerk_screen.cpp
new file mode 100644
index 0000000..9c751bc
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/jerk_screen.cpp
@@ -0,0 +1,65 @@
+/*******************
+ * jerk_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, CLASSIC_JERK)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void JerkScreen::onRedraw(draw_mode_t what) {
+
+ widgets_t w(what);
+ w.precision(1);
+ w.units(GET_TEXT_F(MSG_UNITS_MM_S));
+ w.heading(GET_TEXT_F(MSG_JERK));
+ w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisMaxJerk_mm_s(X) );
+ w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getAxisMaxJerk_mm_s(Y) );
+ w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getAxisMaxJerk_mm_s(Z) );
+ w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_E), getAxisMaxJerk_mm_s(E0) );
+ w.increments();
+}
+
+bool JerkScreen::onTouchHeld(uint8_t tag) {
+ using namespace ExtUI;
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(AxisMaxJerk_mm_s, X); break;
+ case 3: UI_INCREMENT(AxisMaxJerk_mm_s, X); break;
+ case 4: UI_DECREMENT(AxisMaxJerk_mm_s, Y); break;
+ case 5: UI_INCREMENT(AxisMaxJerk_mm_s, Y); break;
+ case 6: UI_DECREMENT(AxisMaxJerk_mm_s, Z); break;
+ case 7: UI_INCREMENT(AxisMaxJerk_mm_s, Z); break;
+ case 8: UI_DECREMENT(AxisMaxJerk_mm_s, E0); break;
+ case 9: UI_INCREMENT(AxisMaxJerk_mm_s, E0); break;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && CLASSIC_JERK
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/junction_deviation_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/junction_deviation_screen.cpp
new file mode 100644
index 0000000..329fa6c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/junction_deviation_screen.cpp
@@ -0,0 +1,54 @@
+/*******************
+ * boot_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, HAS_JUNCTION_DEVIATION)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void JunctionDeviationScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(2);
+ w.units(GET_TEXT_F(MSG_UNITS_MM));
+ w.heading(GET_TEXT_F(MSG_JUNCTION_DEVIATION));
+ w.color(other) .adjuster( 2, F(""), getJunctionDeviation_mm() );
+ w.increments();
+}
+
+bool JunctionDeviationScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(JunctionDeviation_mm); break;
+ case 3: UI_INCREMENT(JunctionDeviation_mm); break;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && !CLASSIC_JERK
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/kill_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/kill_screen.cpp
new file mode 100644
index 0000000..273da34
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/kill_screen.cpp
@@ -0,0 +1,62 @@
+/*******************
+ * kill_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+
+// The kill screen is an oddball that happens after Marlin has killed the events
+// loop. So we only have a show() method rather than onRedraw(). The KillScreen
+// should not be used as a model for other UI screens as it is an exception.
+
+void KillScreen::show(const char *message) {
+ CommandProcessor cmd;
+
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+
+ #define GRID_COLS 4
+ #define GRID_ROWS 8
+
+ cmd.font(Theme::font_large)
+ .cmd(COLOR_RGB(Theme::bg_text_enabled))
+ .text(BTN_POS(1,2), BTN_SIZE(4,1), message)
+ .text(BTN_POS(1,3), BTN_SIZE(4,1), GET_TEXT_F(MSG_HALTED))
+ .text(BTN_POS(1,6), BTN_SIZE(4,1), GET_TEXT_F(MSG_PLEASE_RESET));
+
+ #undef GRID_COLS
+ #undef GRID_ROWS
+
+ cmd.cmd(DL::DL_DISPLAY)
+ .cmd(CMD_SWAP)
+ .execute();
+
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FAILED, PLAY_SYNCHRONOUS);
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/language_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/language_menu.cpp
new file mode 100644
index 0000000..6c5dfcf
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/language_menu.cpp
@@ -0,0 +1,66 @@
+/*********************
+ * language_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../language/language.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && NUM_LANGUAGES > 1
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void LanguageMenu::onRedraw(draw_mode_t) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .colors(normal_btn)
+ .font(Theme::font_medium);
+
+ #define GRID_ROWS 8
+ #define GRID_COLS 1
+
+ cmd.tag(1).button(BTN_POS(1,1), BTN_SIZE(1,1), GET_LANGUAGE_NAME(1));
+ cmd.tag(2).button(BTN_POS(1,2), BTN_SIZE(1,1), GET_LANGUAGE_NAME(2));
+ #if NUM_LANGUAGES > 2
+ cmd.tag(3).button(BTN_POS(1,3), BTN_SIZE(1,1), GET_LANGUAGE_NAME(3));
+ #if NUM_LANGUAGES > 3
+ cmd.tag(4).button(BTN_POS(1,4), BTN_SIZE(1,1), GET_LANGUAGE_NAME(4));
+ #if NUM_LANGUAGES > 5
+ cmd.tag(5).button(BTN_POS(1,5), BTN_SIZE(1,1), GET_LANGUAGE_NAME(5));
+ #endif
+ #endif
+ #endif
+}
+
+bool LanguageMenu::onTouchEnd(uint8_t tag) {
+
+ if (tag > 0 && tag <= NUM_LANGUAGES) {
+ lang = tag - 1;
+ GOTO_SCREEN(StatusScreen);
+ return true;
+ }
+ return false;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/leveling_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/leveling_menu.cpp
new file mode 100644
index 0000000..8d37230
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/leveling_menu.cpp
@@ -0,0 +1,121 @@
+/*********************
+ * leveling_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE,HAS_LEVELING)
+
+#include "screens.h"
+
+#if BOTH(HAS_BED_PROBE,BLTOUCH)
+ #include "../../../../../feature/bltouch.h"
+#endif
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 9
+ #define GRID_COLS 2
+ #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1)
+ #define LEVEL_AXIS_POS BTN_POS(1,2), BTN_SIZE(2,1)
+ #define LEVEL_BED_POS BTN_POS(1,3), BTN_SIZE(2,1)
+ #define SHOW_MESH_POS BTN_POS(1,4), BTN_SIZE(2,1)
+ #define BLTOUCH_TITLE_POS BTN_POS(1,6), BTN_SIZE(2,1)
+ #define BLTOUCH_RESET_POS BTN_POS(1,7), BTN_SIZE(1,1)
+ #define BLTOUCH_TEST_POS BTN_POS(2,7), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(1,9), BTN_SIZE(2,1)
+#else
+ #define GRID_ROWS 7
+ #define GRID_COLS 2
+ #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1)
+ #define LEVEL_AXIS_POS BTN_POS(1,2), BTN_SIZE(2,1)
+ #define LEVEL_BED_POS BTN_POS(1,3), BTN_SIZE(2,1)
+ #define SHOW_MESH_POS BTN_POS(1,4), BTN_SIZE(2,1)
+ #define BLTOUCH_TITLE_POS BTN_POS(1,5), BTN_SIZE(2,1)
+ #define BLTOUCH_RESET_POS BTN_POS(1,6), BTN_SIZE(1,1)
+ #define BLTOUCH_TEST_POS BTN_POS(2,6), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(1,7), BTN_SIZE(2,1)
+#endif
+
+void LevelingMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.font(font_large)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .text(TITLE_POS, GET_TEXT_F(MSG_LEVELING))
+ #if ENABLED(BLTOUCH)
+ .text(BLTOUCH_TITLE_POS, GET_TEXT_F(MSG_BLTOUCH))
+ #endif
+ .font(font_medium).colors(normal_btn)
+ #if EITHER(Z_STEPPER_AUTO_ALIGN,MECHANICAL_GANTRY_CALIBRATION)
+ .tag(2).button(LEVEL_AXIS_POS, GET_TEXT_F(MSG_AUTOLEVEL_X_AXIS))
+ #endif
+ .tag(3).button(LEVEL_BED_POS, GET_TEXT_F(MSG_LEVEL_BED))
+ .enabled(ENABLED(HAS_MESH))
+ .tag(4).button(SHOW_MESH_POS, GET_TEXT_F(MSG_SHOW_MESH))
+ #if ENABLED(BLTOUCH)
+ .tag(5).button(BLTOUCH_RESET_POS, GET_TEXT_F(MSG_BLTOUCH_RESET))
+ .tag(6).button(BLTOUCH_TEST_POS, GET_TEXT_F(MSG_BLTOUCH_SELFTEST))
+ #endif
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool LevelingMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ #if EITHER(Z_STEPPER_AUTO_ALIGN,MECHANICAL_GANTRY_CALIBRATION)
+ case 2: SpinnerDialogBox::enqueueAndWait_P(F("G34")); break;
+ #endif
+ case 3:
+ #ifndef BED_LEVELING_COMMANDS
+ #define BED_LEVELING_COMMANDS "G29"
+ #endif
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
+ BedMeshScreen::startMeshProbe();
+ #else
+ SpinnerDialogBox::enqueueAndWait_P(F(BED_LEVELING_COMMANDS));
+ #endif
+ break;
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
+ case 4: GOTO_SCREEN(BedMeshScreen); break;
+ #endif
+ #if ENABLED(BLTOUCH)
+ case 5: injectCommands_P(PSTR("M280 P0 S60")); break;
+ case 6: SpinnerDialogBox::enqueueAndWait_P(F("M280 P0 S90\nG4 P100\nM280 P0 S120")); break;
+ #endif
+ default: return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && HAS_LEVELING
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/linear_advance_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/linear_advance_screen.cpp
new file mode 100644
index 0000000..2feaa03
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/linear_advance_screen.cpp
@@ -0,0 +1,77 @@
+/*****************************
+ * linear_advance_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, LIN_ADVANCE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void LinearAdvanceScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(2, DEFAULT_LOWEST).color(e_axis);
+ w.heading( GET_TEXT_F(MSG_LINEAR_ADVANCE));
+ #if !HAS_MULTI_EXTRUDER
+ w.adjuster( 2, GET_TEXT_F(MSG_LINEAR_ADVANCE_K), getLinearAdvance_mm_mm_s(E0) );
+ #else
+ w.adjuster( 2, GET_TEXT_F(MSG_LINEAR_ADVANCE_K1), getLinearAdvance_mm_mm_s(E0) );
+ w.adjuster( 4, GET_TEXT_F(MSG_LINEAR_ADVANCE_K2), getLinearAdvance_mm_mm_s(E1) );
+ #if EXTRUDERS > 2
+ w.adjuster( 6, GET_TEXT_F(MSG_LINEAR_ADVANCE_K3), getLinearAdvance_mm_mm_s(E2) );
+ #if EXTRUDERS > 3
+ w.adjuster( 8, GET_TEXT_F(MSG_LINEAR_ADVANCE_K4), getLinearAdvance_mm_mm_s(E3) );
+ #endif
+ #endif
+ #endif
+ w.increments();
+}
+
+bool LinearAdvanceScreen::onTouchHeld(uint8_t tag) {
+ using namespace ExtUI;
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(LinearAdvance_mm_mm_s, E0); break;
+ case 3: UI_INCREMENT(LinearAdvance_mm_mm_s, E0); break;
+ #if HAS_MULTI_EXTRUDER
+ case 4: UI_DECREMENT(LinearAdvance_mm_mm_s, E1); break;
+ case 5: UI_INCREMENT(LinearAdvance_mm_mm_s, E1); break;
+ #if EXTRUDERS > 2
+ case 6: UI_DECREMENT(LinearAdvance_mm_mm_s, E2); break;
+ case 7: UI_INCREMENT(LinearAdvance_mm_mm_s, E2); break;
+ #if EXTRUDERS > 3
+ case 8: UI_DECREMENT(LinearAdvance_mm_mm_s, E3); break;
+ case 9: UI_INCREMENT(LinearAdvance_mm_mm_s, E3); break;
+ #endif
+ #endif
+ #endif
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/lock_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/lock_screen.cpp
new file mode 100644
index 0000000..766f414
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/lock_screen.cpp
@@ -0,0 +1,205 @@
+/*******************
+ * lock_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+uint16_t LockScreen::passcode = 0;
+
+void LockScreen::onEntry() {
+ const uint8_t siz = sizeof(screen_data.Lock.passcode);
+ memset(screen_data.Lock.passcode, '_', siz-1);
+ screen_data.Lock.passcode[siz-1] = '\0';
+ BaseScreen::onEntry();
+}
+
+void LockScreen::onRedraw(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+ }
+
+ if (what & FOREGROUND) {
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_COLS 1
+ #define GRID_ROWS 10
+ #else
+ #define GRID_COLS 1
+ #define GRID_ROWS 7
+ #endif
+
+ #undef MARGIN_T
+ #undef MARGIN_B
+ #define MARGIN_T 3
+ #define MARGIN_B 3
+
+ progmem_str message;
+ switch (message_style()) {
+ case 'w':
+ message = GET_TEXT_F(MSG_PASSCODE_REJECTED);
+ break;
+ case 'g':
+ message = GET_TEXT_F(MSG_PASSCODE_ACCEPTED);
+ break;
+ default:
+ message = passcode ? GET_TEXT_F(MSG_PASSCODE_REQUEST) : GET_TEXT_F(MSG_PASSCODE_SELECT);
+ }
+ message_style() = '\0'; // Terminate the string.
+
+ constexpr uint8_t l = TERN(TOUCH_UI_PORTRAIT, 6, 3);
+
+ const uint8_t pressed = EventLoop::get_pressed_tag();
+
+ cmd.font(font_large)
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ .text(BTN_POS(1,2), BTN_SIZE(1,1), message)
+ .font(font_xlarge)
+ .text(BTN_POS(1,4), BTN_SIZE(1,1), screen_data.Lock.passcode)
+ #else
+ .text(BTN_POS(1,1), BTN_SIZE(1,1), message)
+ .font(font_xlarge)
+ .text(BTN_POS(1,2), BTN_SIZE(1,1), screen_data.Lock.passcode)
+ #endif
+ .font(font_large)
+ .colors(normal_btn)
+ #ifdef TOUCH_UI_PASSCODE
+ .keys(BTN_POS(1,l+1), BTN_SIZE(1,1), F("123"), pressed)
+ .keys(BTN_POS(1,l+2), BTN_SIZE(1,1), F("456"), pressed)
+ .keys(BTN_POS(1,l+3), BTN_SIZE(1,1), F("789"), pressed)
+ .keys(BTN_POS(1,l+4), BTN_SIZE(1,1), F("0.<"), pressed);
+ #else
+ .keys(BTN_POS(1,l+1), BTN_SIZE(1,1), F("1234567890"), pressed)
+ .keys(BTN_POS(1,l+2), BTN_SIZE(1,1), F("qwertyuiop"), pressed)
+ .keys(BTN_POS(1,l+3), BTN_SIZE(1,1), F("asdfghjkl "), pressed)
+ .keys(BTN_POS(1,l+4), BTN_SIZE(1,1), F("zxcvbnm!?<"), pressed);
+ #endif
+
+ #undef MARGIN_T
+ #undef MARGIN_B
+ #define MARGIN_T MARGIN_DEFAULT
+ #define MARGIN_B MARGIN_DEFAULT
+
+ #undef GRID_COLS
+ #undef GRID_ROWS
+ }
+}
+
+char &LockScreen::message_style() {
+ // We use the last byte of the passcode string as a flag to indicate,
+ // which message to show.
+ constexpr uint8_t last_char = sizeof(screen_data.Lock.passcode)-1;
+ return screen_data.Lock.passcode[last_char];
+}
+
+void LockScreen::onPasscodeEntered() {
+ if (passcode == 0) { // We are defining a passcode
+ message_style() = 0;
+ onRefresh();
+ sound.play(twinkle, PLAY_SYNCHRONOUS);
+ passcode = compute_checksum();
+ GOTO_PREVIOUS();
+ }
+ else if (passcode == compute_checksum()) { // We are verifying a passcode
+ message_style() = 'g';
+ onRefresh();
+ sound.play(twinkle, PLAY_SYNCHRONOUS);
+ GOTO_PREVIOUS();
+ }
+ else {
+ message_style() = 'w';
+ onRefresh();
+ sound.play(sad_trombone, PLAY_SYNCHRONOUS);
+ current_screen.forget(); // Discard the screen the user was trying to go to.
+ GOTO_PREVIOUS();
+ }
+}
+
+bool LockScreen::onTouchEnd(uint8_t tag) {
+ char *c = strchr(screen_data.Lock.passcode,'_');
+ if (c) {
+ if (tag == '<') {
+ if (c != screen_data.Lock.passcode) {
+ // Backspace deletes previous entered characters.
+ *--c = '_';
+ }
+ }
+ else {
+ // Append character to passcode
+ *c++ = tag;
+ if (*c == '\0') {
+ // If at last character, then process the code.
+ onPasscodeEntered();
+ }
+ }
+ }
+ return true;
+}
+
+uint16_t LockScreen::compute_checksum() {
+ uint16_t checksum = 0;
+ const char* c = screen_data.Lock.passcode;
+ while (*c) {
+ checksum = (checksum << 2) ^ *c++;
+ }
+ if (checksum == 0) checksum = 0xFFFF; // Prevent a zero checksum
+ return checksum;
+}
+
+// This function should be called *after* calling GOTO_SCREEN
+// to move to new screen. If a passcode is enabled, it will
+// immediately jump to the keypad screen, pushing the previous
+// screen onto the stack. If the code is entered correctly,
+// the stack will be popped, allowing the user to proceed to
+// the new screen. Otherwise it will be popped twice, taking
+// the user back to where they were before.
+void LockScreen::check_passcode() {
+ if (passcode == 0) return;
+ message_style() = 0;
+ GOTO_SCREEN(LockScreen);
+}
+
+bool LockScreen::is_enabled() {
+ return passcode != 0;
+}
+
+void LockScreen::disable() {
+ passcode = 0;
+}
+
+void LockScreen::enable() {
+ message_style() = 0;
+ passcode = 0;
+ GOTO_SCREEN(LockScreen);
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/main_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/main_menu.cpp
new file mode 100644
index 0000000..146b799
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/main_menu.cpp
@@ -0,0 +1,131 @@
+/*****************
+ * main_menu.cpp *
+ *****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && NONE(TOUCH_UI_LULZBOT_BIO,TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void MainMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 8
+ #define GRID_COLS 2
+ #define ABOUT_PRINTER_POS BTN_POS(1,1), BTN_SIZE(2,1)
+ #define ADVANCED_SETTINGS_POS BTN_POS(1,2), BTN_SIZE(2,1)
+ #if ENABLED(CUSTOM_USER_MENUS)
+ #define FILAMENTCHANGE_POS BTN_POS(1,3), BTN_SIZE(1,1)
+ #define CUSTOM_USER_MENUS_POS BTN_POS(2,3), BTN_SIZE(1,1)
+ #else
+ #define FILAMENTCHANGE_POS BTN_POS(1,3), BTN_SIZE(2,1)
+ #endif
+ #define TEMPERATURE_POS BTN_POS(1,4), BTN_SIZE(2,1)
+ #define DISABLE_STEPPERS_POS BTN_POS(1,5), BTN_SIZE(2,1)
+ #define MOVE_AXIS_POS BTN_POS(1,6), BTN_SIZE(1,1)
+ #define LEVELING_POS BTN_POS(2,6), BTN_SIZE(1,1)
+ #define AUTO_HOME_POS BTN_POS(1,7), BTN_SIZE(1,1)
+ #define CLEAN_NOZZLE_POS BTN_POS(2,7), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(1,8), BTN_SIZE(2,1)
+ #else
+ #define GRID_ROWS 5
+ #define GRID_COLS 6
+ #define ADVANCED_SETTINGS_POS BTN_POS(1,1), BTN_SIZE(3,1)
+ #define ABOUT_PRINTER_POS BTN_POS(4,1), BTN_SIZE(3,1)
+ #define AUTO_HOME_POS BTN_POS(1,2), BTN_SIZE(3,1)
+ #define CLEAN_NOZZLE_POS BTN_POS(4,2), BTN_SIZE(3,1)
+ #define MOVE_AXIS_POS BTN_POS(1,3), BTN_SIZE(3,1)
+ #define DISABLE_STEPPERS_POS BTN_POS(4,3), BTN_SIZE(3,1)
+ #if ENABLED(CUSTOM_USER_MENUS)
+ #define TEMPERATURE_POS BTN_POS(1,4), BTN_SIZE(2,1)
+ #define FILAMENTCHANGE_POS BTN_POS(3,4), BTN_SIZE(2,1)
+ #define CUSTOM_USER_MENUS_POS BTN_POS(5,4), BTN_SIZE(2,1)
+ #else
+ #define TEMPERATURE_POS BTN_POS(1,4), BTN_SIZE(3,1)
+ #define FILAMENTCHANGE_POS BTN_POS(4,4), BTN_SIZE(3,1)
+ #endif
+ #define LEVELING_POS BTN_POS(1,5), BTN_SIZE(3,1)
+ #define BACK_POS BTN_POS(4,5), BTN_SIZE(3,1)
+ #endif
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ .tag( 2).button(AUTO_HOME_POS, GET_TEXT_F(MSG_AUTO_HOME))
+ .enabled(ENABLED(NOZZLE_CLEAN_FEATURE))
+ .tag( 3).button(CLEAN_NOZZLE_POS, GET_TEXT_F(MSG_CLEAN_NOZZLE))
+ .tag( 4).button(MOVE_AXIS_POS, GET_TEXT_F(MSG_MOVE_AXIS))
+ .tag( 5).button(DISABLE_STEPPERS_POS,GET_TEXT_F(MSG_DISABLE_STEPPERS))
+ .tag( 6).button(TEMPERATURE_POS, GET_TEXT_F(MSG_TEMPERATURE))
+ .enabled(IF_DISABLED(TOUCH_UI_LULZBOT_BIO, 1))
+ .tag( 7).button(FILAMENTCHANGE_POS, GET_TEXT_F(MSG_FILAMENTCHANGE))
+ .tag( 8).button(ADVANCED_SETTINGS_POS, GET_TEXT_F(MSG_ADVANCED_SETTINGS))
+ .enabled(TERN_(HAS_LEVELING, 1))
+ .tag( 9).button(LEVELING_POS, GET_TEXT_F(MSG_LEVELING))
+ .tag(10).button(ABOUT_PRINTER_POS, GET_TEXT_F(MSG_INFO_MENU))
+ #if ENABLED(CUSTOM_USER_MENUS)
+ .tag(11).button(CUSTOM_USER_MENUS_POS, GET_TEXT_F(MSG_USER_MENU))
+ #endif
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool MainMenu::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: SpinnerDialogBox::enqueueAndWait_P(F("G28")); break;
+ #if ENABLED(NOZZLE_CLEAN_FEATURE)
+ case 3: injectCommands_P(PSTR("G12")); GOTO_SCREEN(StatusScreen); break;
+ #endif
+ case 4: GOTO_SCREEN(MoveAxisScreen); break;
+ case 5: injectCommands_P(PSTR("M84")); break;
+ case 6: GOTO_SCREEN(TemperatureScreen); break;
+ case 7: GOTO_SCREEN(ChangeFilamentScreen); break;
+ case 8: GOTO_SCREEN(AdvancedSettingsMenu); break;
+ #if HAS_LEVELING
+ case 9: GOTO_SCREEN(LevelingMenu); break;
+ #endif
+ case 10: GOTO_SCREEN(AboutScreen); break;
+ #if ENABLED(CUSTOM_USER_MENUS)
+ case 11: GOTO_SCREEN(CustomUserMenus); break;
+ #endif
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && !TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_acceleration_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_acceleration_screen.cpp
new file mode 100644
index 0000000..fdbb962
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_acceleration_screen.cpp
@@ -0,0 +1,86 @@
+/*******************************
+ * max_acceleration_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void MaxAccelerationScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(0);
+ w.units(GET_TEXT_F(MSG_UNITS_MM_S2));
+ w.heading(GET_TEXT_F(MSG_ACCELERATION));
+ w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AMAX_X), getAxisMaxAcceleration_mm_s2(X) );
+ w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AMAX_Y), getAxisMaxAcceleration_mm_s2(Y) );
+ w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AMAX_Z), getAxisMaxAcceleration_mm_s2(Z) );
+ #if DISTINCT_E == 1
+ w.color(e_axis).adjuster( 8, GET_TEXT_F(MSG_AMAX_E), getAxisMaxAcceleration_mm_s2(E0) );
+ #elif DISTINCT_E > 1
+ w.heading(GET_TEXT_F(MSG_AMAX_E));
+ w.color(e_axis).adjuster( 8, F(LCD_STR_E0), getAxisMaxAcceleration_mm_s2(E0) );
+ w.color(e_axis).adjuster(10, F(LCD_STR_E1), getAxisMaxAcceleration_mm_s2(E1) );
+ #if DISTINCT_E > 2
+ w.color(e_axis).adjuster(12, F(LCD_STR_E2), getAxisMaxAcceleration_mm_s2(E2) );
+ #endif
+ #if DISTINCT_E > 3
+ w.color(e_axis).adjuster(14, F(LCD_STR_E3), getAxisMaxAcceleration_mm_s2(E3) );
+ #endif
+ #endif
+ w.increments();
+}
+
+bool MaxAccelerationScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(AxisMaxAcceleration_mm_s2, X ); break;
+ case 3: UI_INCREMENT(AxisMaxAcceleration_mm_s2, X ); break;
+ case 4: UI_DECREMENT(AxisMaxAcceleration_mm_s2, Y ); break;
+ case 5: UI_INCREMENT(AxisMaxAcceleration_mm_s2, Y ); break;
+ case 6: UI_DECREMENT(AxisMaxAcceleration_mm_s2, Z ); break;
+ case 7: UI_INCREMENT(AxisMaxAcceleration_mm_s2, Z ); break;
+ case 8: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E0); break;
+ case 9: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E0); break;
+ #if DISTINCT_E > 1
+ case 10: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E1); break;
+ case 11: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E1); break;
+ #endif
+ #if DISTINCT_E > 2
+ case 12: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E2); break;
+ case 13: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E2); break;
+ #endif
+ #if DISTINCT_E > 3
+ case 14: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E3); break;
+ case 15: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E3); break;
+ #endif
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_velocity_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_velocity_screen.cpp
new file mode 100644
index 0000000..ac1374b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_velocity_screen.cpp
@@ -0,0 +1,90 @@
+/***************************
+ * max_velocity_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void MaxVelocityScreen::onRedraw(draw_mode_t what) {
+ using namespace ExtUI;
+ widgets_t w(what);
+ w.precision(0);
+ w.units(GET_TEXT_F(MSG_UNITS_MM_S));
+ w.heading( GET_TEXT_F(MSG_VELOCITY));
+ w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_VMAX_X), getAxisMaxFeedrate_mm_s(X) );
+ w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_VMAX_Y), getAxisMaxFeedrate_mm_s(Y) );
+ w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_VMAX_Z), getAxisMaxFeedrate_mm_s(Z) );
+ #if EXTRUDERS == 1 || DISABLED(DISTINCT_E_FACTORS)
+ w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_VMAX_E), getAxisMaxFeedrate_mm_s(E0) );
+ #elif HAS_MULTI_EXTRUDER
+ w.heading(GET_TEXT_F(MSG_VMAX_E));
+ w.color(e_axis) .adjuster( 8, F(LCD_STR_E0), getAxisMaxFeedrate_mm_s(E0) );
+ w.color(e_axis) .adjuster( 10, F(LCD_STR_E1), getAxisMaxFeedrate_mm_s(E1) );
+ #if EXTRUDERS > 2
+ w.color(e_axis).adjuster( 12, F(LCD_STR_E2), getAxisMaxFeedrate_mm_s(E2) );
+ #endif
+ #if EXTRUDERS > 3
+ w.color(e_axis).adjuster( 14, F(LCD_STR_E3), getAxisMaxFeedrate_mm_s(E3) );
+ #endif
+ #endif
+ w.increments();
+}
+
+bool MaxVelocityScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(AxisMaxFeedrate_mm_s, X); break;
+ case 3: UI_INCREMENT(AxisMaxFeedrate_mm_s, X); break;
+ case 4: UI_DECREMENT(AxisMaxFeedrate_mm_s, Y); break;
+ case 5: UI_INCREMENT(AxisMaxFeedrate_mm_s, Y); break;
+ case 6: UI_DECREMENT(AxisMaxFeedrate_mm_s, Z); break;
+ case 7: UI_INCREMENT(AxisMaxFeedrate_mm_s, Z); break;
+ #if DISTINCT_E > 0
+ case 8: UI_DECREMENT(AxisMaxFeedrate_mm_s, E0); break;
+ case 9: UI_INCREMENT(AxisMaxFeedrate_mm_s, E0); break;
+ #endif
+ #if DISTINCT_E > 1
+ case 10: UI_DECREMENT(AxisMaxFeedrate_mm_s, E1); break;
+ case 11: UI_INCREMENT(AxisMaxFeedrate_mm_s, E1); break;
+ #endif
+ #if DISTINCT_E > 2
+ case 12: UI_DECREMENT(AxisMaxFeedrate_mm_s, E2); break;
+ case 13: UI_INCREMENT(AxisMaxFeedrate_mm_s, E2); break;
+ #endif
+ #if DISTINCT_E > 3
+ case 14: UI_DECREMENT(AxisMaxFeedrate_mm_s, E3); break;
+ case 15: UI_INCREMENT(AxisMaxFeedrate_mm_s, E3); break;
+ #endif
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/media_player_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/media_player_screen.cpp
new file mode 100644
index 0000000..eb0b78a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/media_player_screen.cpp
@@ -0,0 +1,168 @@
+/***************************
+ * media_player_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+/**
+ * The MediaPlayerScreen allows an AVI to be played.
+ *
+ * It requires a special AVI file. The following video
+ * and audio codecs must be used:
+ *
+ * -vcodec mjpeg -pix_fmt yuvj420p
+ * -acodec adpcm_ima_wav
+ *
+ * To generate a 2 second static screen from a png file:
+ *
+ * ffmpeg -i startup.png -vcodec mjpeg -pix_fmt yuvj420p -r 1 video.avi
+ * sox -n -r 44100 -b 8 -c 2 -L silence.wav trim 0.0 2.000
+ * ffmpeg -i silence.wav -acodec adpcm_ima_wav silence.avi
+ * ffmpeg -i video.avi -i silence.wav -c copy -map 0:v:0 -map 1:a:0 startup.avi
+ */
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+#include "../archim2-flash/flash_storage.h"
+#include "../archim2-flash/media_file_reader.h"
+
+using namespace FTDI;
+
+void MediaPlayerScreen::onEntry() {
+ BaseScreen::onEntry();
+ CLCD::turn_on_backlight();
+ SoundPlayer::set_volume(255);
+}
+
+void MediaPlayerScreen::onRedraw(draw_mode_t) {
+}
+
+bool MediaPlayerScreen::playCardMedia() {
+ #if ENABLED(SDSUPPORT)
+ char fname[15];
+ strcpy_P(fname, PSTR("STARTUP.AVI"));
+
+ MediaFileReader reader;
+ if (!reader.open(fname))
+ return false;
+
+ SERIAL_ECHO_MSG("Starting to play STARTUP.AVI");
+ playStream(&reader, MediaFileReader::read);
+ reader.close();
+ #endif
+ return true;
+}
+
+// Attempt to play media from the onboard SPI flash chip
+bool MediaPlayerScreen::playBootMedia() {
+ UIFlashStorage::BootMediaReader reader;
+ if (!reader.isAvailable()) return false;
+
+ SERIAL_ECHO_MSG("Starting to play boot video");
+ playStream(&reader, UIFlashStorage::BootMediaReader::read);
+ return true;
+}
+
+void MediaPlayerScreen::playStream(void *obj, media_streamer_func_t *data_stream) {
+ #if FTDI_API_LEVEL >= 810
+ if (FTDI::ftdi_chip >= 810) {
+ // Set up the media FIFO on the end of RAMG, as the top of RAMG
+ // will be used as the framebuffer.
+
+ uint8_t buf[512];
+ const uint32_t block_size = 512;
+ const uint32_t fifo_size = block_size * 2;
+ const uint32_t fifo_start = CLCD::MAP::RAM_G + CLCD::MAP::RAM_G_SIZE - fifo_size;
+
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(0x000000))
+ .cmd(CLEAR(true,true,true))
+ .cmd(DL::DL_DISPLAY)
+ .cmd(CMD_SWAP)
+ .execute()
+ .cmd(CMD_DLSTART)
+ .mediafifo(fifo_start, fifo_size)
+ .playvideo(OPT_FULLSCREEN | OPT_MEDIAFIFO | OPT_NOTEAR | OPT_SOUND)
+ .cmd(DL::DL_DISPLAY)
+ .cmd(CMD_SWAP)
+ .execute();
+
+ uint32_t writePtr = 0;
+ int16_t nBytes;
+
+ uint32_t t = millis();
+ uint8_t timeouts;
+
+ spiInit(SPI_HALF_SPEED); // Boost SPI speed for video playback
+
+ do {
+ // Write block n
+ nBytes = (*data_stream)(obj, buf, block_size);
+ if (nBytes == -1) break;
+
+ if (millis() - t > 10) {
+ ExtUI::yield();
+ t = millis();
+ }
+
+ CLCD::mem_write_bulk (fifo_start + writePtr, buf, nBytes);
+
+ // Wait for FTDI810 to finish playing block n-1
+ timeouts = 20;
+ do {
+ if (millis() - t > 10) {
+ ExtUI::yield();
+ t = millis();
+ timeouts--;
+ if (timeouts == 0) {
+ SERIAL_ECHO_MSG("Timeout playing video");
+ cmd.reset();
+ goto exit;
+ }
+ }
+ } while (CLCD::mem_read_32(CLCD::REG::MEDIAFIFO_READ) != writePtr);
+
+ // Start playing block n
+ writePtr = (writePtr + nBytes) % fifo_size;
+ CLCD::mem_write_32(CLCD::REG::MEDIAFIFO_WRITE, writePtr);
+ } while (nBytes == block_size);
+
+ SERIAL_ECHO_MSG("Done playing video");
+
+ exit:
+ spiInit(SD_SPI_SPEED); // Restore default speed
+
+ // Since playing media overwrites RAMG, we need to reinitialize
+ // everything that is stored in RAMG.
+ cmd.cmd(CMD_DLSTART).execute();
+ DLCache::init();
+ StatusScreen::loadBitmaps();
+ }
+ #else
+ UNUSED(obj);
+ UNUSED(data_stream);
+ #endif // FTDI_API_LEVEL >= 810
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/move_axis_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/move_axis_screen.cpp
new file mode 100644
index 0000000..ba38918
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/move_axis_screen.cpp
@@ -0,0 +1,133 @@
+/************************
+ * move_axis_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+
+void BaseMoveAxisScreen::onEntry() {
+ // Since Marlin keeps only one absolute position for all the extruders,
+ // we have to keep track of the relative motion of individual extruders
+ // ourselves. The relative distances are reset to zero whenever this
+ // screen is entered.
+
+ LOOP_L_N(i, ExtUI::extruderCount) {
+ screen_data.MoveAxis.e_rel[i] = 0;
+ }
+ BaseNumericAdjustmentScreen::onEntry();
+}
+
+void MoveAxisScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(1);
+ w.units(GET_TEXT_F(MSG_UNITS_MM));
+ w.heading( GET_TEXT_F(MSG_MOVE_AXIS));
+ w.home_buttons(20);
+ w.color(Theme::x_axis).adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisPosition_mm(X), canMove(X));
+ w.color(Theme::y_axis).adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getAxisPosition_mm(Y), canMove(Y));
+ w.color(Theme::z_axis).adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getAxisPosition_mm(Z), canMove(Z));
+
+ w.color(Theme::e_axis);
+ #if EXTRUDERS == 1
+ w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E), screen_data.MoveAxis.e_rel[0], canMove(E0));
+ #elif HAS_MULTI_EXTRUDER
+ w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E1), screen_data.MoveAxis.e_rel[0], canMove(E0));
+ w.adjuster( 10, GET_TEXT_F(MSG_AXIS_E2), screen_data.MoveAxis.e_rel[1], canMove(E1));
+ #if EXTRUDERS > 2
+ w.adjuster( 12, GET_TEXT_F(MSG_AXIS_E3), screen_data.MoveAxis.e_rel[2], canMove(E2));
+ #endif
+ #if EXTRUDERS > 3
+ w.adjuster( 14, GET_TEXT_F(MSG_AXIS_E4), screen_data.MoveAxis.e_rel[3], canMove(E3));
+ #endif
+ #endif
+ w.increments();
+}
+
+bool BaseMoveAxisScreen::onTouchHeld(uint8_t tag) {
+ #define UI_INCREMENT_AXIS(axis) UI_INCREMENT(AxisPosition_mm, axis);
+ #define UI_DECREMENT_AXIS(axis) UI_DECREMENT(AxisPosition_mm, axis);
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT_AXIS(X); break;
+ case 3: UI_INCREMENT_AXIS(X); break;
+ case 4: UI_DECREMENT_AXIS(Y); break;
+ case 5: UI_INCREMENT_AXIS(Y); break;
+ case 6: UI_DECREMENT_AXIS(Z); break;
+ case 7: UI_INCREMENT_AXIS(Z); break;
+ // For extruders, also update relative distances.
+ case 8: UI_DECREMENT_AXIS(E0); screen_data.MoveAxis.e_rel[0] -= increment; break;
+ case 9: UI_INCREMENT_AXIS(E0); screen_data.MoveAxis.e_rel[0] += increment; break;
+ #if HAS_MULTI_EXTRUDER
+ case 10: UI_DECREMENT_AXIS(E1); screen_data.MoveAxis.e_rel[1] -= increment; break;
+ case 11: UI_INCREMENT_AXIS(E1); screen_data.MoveAxis.e_rel[1] += increment; break;
+ #endif
+ #if EXTRUDERS > 2
+ case 12: UI_DECREMENT_AXIS(E2); screen_data.MoveAxis.e_rel[2] -= increment; break;
+ case 13: UI_INCREMENT_AXIS(E2); screen_data.MoveAxis.e_rel[2] += increment; break;
+ #endif
+ #if EXTRUDERS > 3
+ case 14: UI_DECREMENT_AXIS(E3); screen_data.MoveAxis.e_rel[3] -= increment; break;
+ case 15: UI_INCREMENT_AXIS(E3); screen_data.MoveAxis.e_rel[3] += increment; break;
+ #endif
+ case 20: SpinnerDialogBox::enqueueAndWait_P(F("G28X")); break;
+ case 21: SpinnerDialogBox::enqueueAndWait_P(F("G28Y")); break;
+ case 22: SpinnerDialogBox::enqueueAndWait_P(F("G28Z")); break;
+ case 23: SpinnerDialogBox::enqueueAndWait_P(F("G28")); break;
+ default:
+ return false;
+ }
+ #undef UI_DECREMENT_AXIS
+ #undef UI_INCREMENT_AXIS
+ return true;
+}
+
+float BaseMoveAxisScreen::getManualFeedrate(uint8_t axis, float increment_mm) {
+ // Compute feedrate so that the tool lags the adjuster when it is
+ // being held down, this allows enough margin for the planner to
+ // connect segments and even out the motion.
+ constexpr xyze_feedrate_t max_manual_feedrate = MANUAL_FEEDRATE;
+ return min(max_manual_feedrate[axis] / 60.0f, abs(increment_mm * (TOUCH_REPEATS_PER_SECOND) * 0.80f));
+}
+
+void BaseMoveAxisScreen::setManualFeedrate(ExtUI::axis_t axis, float increment_mm) {
+ ExtUI::setFeedrate_mm_s(getManualFeedrate(X_AXIS + (axis - ExtUI::X), increment_mm));
+}
+
+void BaseMoveAxisScreen::setManualFeedrate(ExtUI::extruder_t, float increment_mm) {
+ ExtUI::setFeedrate_mm_s(getManualFeedrate(E_AXIS, increment_mm));
+}
+
+void MoveAxisScreen::onIdle() {
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nozzle_offsets_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nozzle_offsets_screen.cpp
new file mode 100644
index 0000000..85c7206
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nozzle_offsets_screen.cpp
@@ -0,0 +1,73 @@
+/*****************************
+ * nozzle_offsets_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, HAS_MULTI_HOTEND)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+
+void NozzleOffsetScreen::onEntry() {
+ // Since we don't allow the user to edit the offsets for E0,
+ // make sure they are all zero.
+ normalizeNozzleOffset(X);
+ normalizeNozzleOffset(Y);
+ normalizeNozzleOffset(Z);
+}
+
+void NozzleOffsetScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(2).units(GET_TEXT_F(MSG_UNITS_MM));
+
+ w.heading( GET_TEXT_F(MSG_OFFSETS_MENU));
+ w.color(Theme::x_axis).adjuster(2, GET_TEXT_F(MSG_AXIS_X), ExtUI::getNozzleOffset_mm(X, E1));
+ w.color(Theme::y_axis).adjuster(4, GET_TEXT_F(MSG_AXIS_Y), ExtUI::getNozzleOffset_mm(Y, E1));
+ w.color(Theme::z_axis).adjuster(6, GET_TEXT_F(MSG_AXIS_Z), ExtUI::getNozzleOffset_mm(Z, E1));
+ #if ENABLED(CALIBRATION_GCODE)
+ w.button(8, GET_TEXT_F(MSG_MEASURE_AUTOMATICALLY), !isPrinting());
+ #endif
+ w.increments();
+}
+
+bool NozzleOffsetScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(NozzleOffset_mm, X, E1); break;
+ case 3: UI_INCREMENT(NozzleOffset_mm, X, E1); break;
+ case 4: UI_DECREMENT(NozzleOffset_mm, Y, E1); break;
+ case 5: UI_INCREMENT(NozzleOffset_mm, Y, E1); break;
+ case 6: UI_DECREMENT(NozzleOffset_mm, Z, E1); break;
+ case 7: UI_INCREMENT(NozzleOffset_mm, Z, E1); break;
+ #if ENABLED(CALIBRATION_GCODE)
+ case 8: GOTO_SCREEN(ConfirmAutoCalibrationDialogBox); return true;
+ #endif
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nudge_nozzle_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nudge_nozzle_screen.cpp
new file mode 100644
index 0000000..f0d3f7e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nudge_nozzle_screen.cpp
@@ -0,0 +1,123 @@
+/********************
+ * nudge_nozzle.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, BABYSTEPPING)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+void NudgeNozzleScreen::onEntry() {
+ screen_data.NudgeNozzle.show_offsets = false;
+ #if HAS_MULTI_EXTRUDER
+ screen_data.NudgeNozzle.link_nozzles = true;
+ #endif
+ screen_data.NudgeNozzle.rel.reset();
+
+ BaseNumericAdjustmentScreen::onEntry();
+}
+
+void NudgeNozzleScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(2, BaseNumericAdjustmentScreen::DEFAULT_MIDRANGE).units(GET_TEXT_F(MSG_UNITS_MM));
+
+ w.heading(GET_TEXT_F(MSG_NUDGE_NOZZLE));
+ #if ENABLED(BABYSTEP_XY)
+ w.color(x_axis).adjuster(2, GET_TEXT_F(MSG_AXIS_X), screen_data.NudgeNozzle.rel.x / getAxisSteps_per_mm(X));
+ w.color(y_axis).adjuster(4, GET_TEXT_F(MSG_AXIS_Y), screen_data.NudgeNozzle.rel.y / getAxisSteps_per_mm(Y));
+ #endif
+ w.color(z_axis).adjuster(6, GET_TEXT_F(MSG_AXIS_Z), screen_data.NudgeNozzle.rel.z / getAxisSteps_per_mm(Z));
+ w.increments();
+ #if HAS_MULTI_EXTRUDER
+ w.toggle(8, GET_TEXT_F(MSG_ADJUST_BOTH_NOZZLES), screen_data.NudgeNozzle.link_nozzles);
+ #endif
+
+ #if HAS_MULTI_EXTRUDER || HAS_BED_PROBE
+ w.toggle(9, GET_TEXT_F(MSG_SHOW_OFFSETS), screen_data.NudgeNozzle.show_offsets);
+
+ if (screen_data.NudgeNozzle.show_offsets) {
+ char str[19];
+
+ w.draw_mode(BOTH);
+ w.color(other);
+
+ #if HAS_BED_PROBE
+ dtostrf(getZOffset_mm(), 4, 2, str);
+ strcat(str, " ");
+ strcat_P(str, GET_TEXT(MSG_UNITS_MM));
+ w.text_field(0, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), str);
+ #endif
+
+ #if HAS_MULTI_HOTEND
+ format_position(str, getNozzleOffset_mm(X, E1), getNozzleOffset_mm(Y, E1), getNozzleOffset_mm(Z, E1));
+ w.text_field(0, GET_TEXT_F(MSG_OFFSETS_MENU), str);
+ #endif
+ }
+ #endif
+}
+
+bool NudgeNozzleScreen::onTouchHeld(uint8_t tag) {
+ const float inc = getIncrement();
+ #if HAS_MULTI_EXTRUDER
+ const bool link = screen_data.NudgeNozzle.link_nozzles;
+ #else
+ constexpr bool link = true;
+ #endif
+ int16_t steps;
+ switch (tag) {
+ case 2: steps = mmToWholeSteps(inc, X); smartAdjustAxis_steps(-steps, X, link); screen_data.NudgeNozzle.rel.x -= steps; break;
+ case 3: steps = mmToWholeSteps(inc, X); smartAdjustAxis_steps( steps, X, link); screen_data.NudgeNozzle.rel.x += steps; break;
+ case 4: steps = mmToWholeSteps(inc, Y); smartAdjustAxis_steps(-steps, Y, link); screen_data.NudgeNozzle.rel.y -= steps; break;
+ case 5: steps = mmToWholeSteps(inc, Y); smartAdjustAxis_steps( steps, Y, link); screen_data.NudgeNozzle.rel.y += steps; break;
+ case 6: steps = mmToWholeSteps(inc, Z); smartAdjustAxis_steps(-steps, Z, link); screen_data.NudgeNozzle.rel.z -= steps; break;
+ case 7: steps = mmToWholeSteps(inc, Z); smartAdjustAxis_steps( steps, Z, link); screen_data.NudgeNozzle.rel.z += steps; break;
+ #if HAS_MULTI_EXTRUDER
+ case 8: screen_data.NudgeNozzle.link_nozzles = !link; break;
+ #endif
+ case 9: screen_data.NudgeNozzle.show_offsets = !screen_data.NudgeNozzle.show_offsets; break;
+ default: return false;
+ }
+ #if HAS_MULTI_EXTRUDER || HAS_BED_PROBE
+ SaveSettingsDialogBox::settingsChanged();
+ #endif
+ return true;
+}
+
+bool NudgeNozzleScreen::onTouchEnd(uint8_t tag) {
+ if (tag == 1) {
+ SaveSettingsDialogBox::promptToSaveSettings();
+ return true;
+ }
+ else
+ return BaseNumericAdjustmentScreen::onTouchEnd(tag);
+}
+
+void NudgeNozzleScreen::onIdle() {
+ reset_menu_timeout();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/restore_failsafe_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/restore_failsafe_dialog_box.cpp
new file mode 100644
index 0000000..9be2239
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/restore_failsafe_dialog_box.cpp
@@ -0,0 +1,51 @@
+/***********************************
+ * restore_failsafe_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace ExtUI;
+
+void RestoreFailsafeDialogBox::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_EEPROM_RESET_WARNING));
+ drawYesNoButtons();
+}
+
+bool RestoreFailsafeDialogBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ ExtUI::injectCommands_P(PSTR("M502"));
+ AlertDialogBox::show(GET_TEXT_F(MSG_EEPROM_RESET));
+ // Remove RestoreFailsafeDialogBox from the stack
+ // so the alert box doesn't return to it.
+ current_screen.forget();
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/save_settings_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/save_settings_dialog_box.cpp
new file mode 100644
index 0000000..eff0431
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/save_settings_dialog_box.cpp
@@ -0,0 +1,64 @@
+/********************************
+ * save_settings_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace ExtUI;
+
+bool SaveSettingsDialogBox::needs_save = false;
+
+void SaveSettingsDialogBox::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_EEPROM_SAVE_PROMPT));
+ drawYesNoButtons();
+}
+
+bool SaveSettingsDialogBox::onTouchEnd(uint8_t tag) {
+ needs_save = false;
+ switch (tag) {
+ case 1:
+ injectCommands_P(PSTR("M500"));
+ AlertDialogBox::show(GET_TEXT_F(MSG_EEPROM_SAVED));
+ // Remove SaveSettingsDialogBox from the stack
+ // so the alert box doesn't return to me.
+ current_screen.forget();
+ return true;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+}
+
+void SaveSettingsDialogBox::promptToSaveSettings() {
+ if (needs_save) {
+ // Remove current screen from the stack
+ // so SaveSettingsDialogBox doesn't return here.
+ GOTO_SCREEN(SaveSettingsDialogBox);
+ current_screen.forget();
+ }
+ else
+ GOTO_PREVIOUS(); // No save needed.
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screen_data.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screen_data.h
new file mode 100644
index 0000000..fe35fc4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screen_data.h
@@ -0,0 +1,97 @@
+/*****************
+ * screen_data.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../ftdi_eve_lib/ftdi_eve_lib.h"
+
+// To save RAM, store state information related to a particular screen
+// in a union. The values should be initialized in the onEntry method.
+
+struct base_numeric_adjustment_t {uint8_t increment;};
+
+union screen_data_t {
+ struct base_numeric_adjustment_t BaseNumericAdjustment;
+ struct {uint8_t volume; uint8_t brightness;} InterfaceSettings;
+ struct {char passcode[5];} Lock;
+ struct {bool isError;} AlertDialog;
+ struct {bool auto_hide;} SpinnerDialog;
+ struct {uint8_t file_index;} ConfirmStartPrintDialog;
+ struct {
+ uint8_t e_tag, t_tag, repeat_tag;
+ ExtUI::extruder_t saved_extruder;
+ #if FILAMENT_UNLOAD_PURGE_LENGTH > 0
+ bool need_purge;
+ #endif
+ } ChangeFilament;
+ struct {
+ struct {
+ uint8_t is_dir : 1;
+ uint8_t is_root : 1;
+ } flags;
+ uint8_t selected_tag;
+ uint8_t num_page;
+ uint8_t cur_page;
+ #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810)
+ uint16_t scroll_pos;
+ uint16_t scroll_max;
+ #endif
+ } Files;
+ struct {
+ struct base_numeric_adjustment_t placeholder;
+ float e_rel[ExtUI::extruderCount];
+ } MoveAxis;
+ #if HAS_MESH
+ struct {
+ enum : uint8_t {
+ MSG_NONE,
+ MSG_MESH_COMPLETE,
+ MSG_MESH_INCOMPLETE
+ } message;
+ uint8_t count;
+ uint8_t highlightedTag;
+ } BedMesh;
+ #endif
+ #if ENABLED(TOUCH_UI_DEVELOPER_MENU)
+ struct {
+ uint32_t next_watchdog_trigger;
+ const char* message;
+ } StressTest;
+ #endif
+ #if ENABLED(TOUCH_UI_COCOA_PRESS)
+ struct {
+ uint32_t start_ms;
+ } PreheatTimer;
+ #endif
+ #if ENABLED(BABYSTEPPING)
+ struct {
+ struct base_numeric_adjustment_t placeholder;
+ xyz_int_t rel;
+ #if HAS_MULTI_EXTRUDER
+ bool link_nozzles;
+ #endif
+ bool show_offsets;
+ } NudgeNozzle;
+ #endif
+};
+
+extern screen_data_t screen_data;
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.cpp
new file mode 100644
index 0000000..5841c38
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.cpp
@@ -0,0 +1,139 @@
+/***************
+ * screens.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+#include "screens.h"
+#include "screen_data.h"
+
+tiny_timer_t refresh_timer;
+screen_data_t screen_data;
+
+SCREEN_TABLE {
+ DECL_SCREEN(BootScreen),
+ #if NUM_LANGUAGES > 1
+ DECL_SCREEN(LanguageMenu),
+ #endif
+ DECL_SCREEN(TouchCalibrationScreen),
+ DECL_SCREEN(StatusScreen),
+ DECL_SCREEN(MainMenu),
+ DECL_SCREEN(TuneMenu),
+ DECL_SCREEN(AdvancedSettingsMenu),
+ DECL_SCREEN(AlertDialogBox),
+ DECL_SCREEN(ConfirmUserRequestAlertBox),
+ DECL_SCREEN(RestoreFailsafeDialogBox),
+ DECL_SCREEN(SaveSettingsDialogBox),
+ DECL_SCREEN(ConfirmStartPrintDialogBox),
+ DECL_SCREEN(ConfirmAbortPrintDialogBox),
+ #if ENABLED(CALIBRATION_GCODE)
+ DECL_SCREEN(ConfirmAutoCalibrationDialogBox),
+ #endif
+ #if ENABLED(CUSTOM_USER_MENUS)
+ DECL_SCREEN(CustomUserMenus),
+ #endif
+ DECL_SCREEN(SpinnerDialogBox),
+ DECL_SCREEN(AboutScreen),
+ #if ENABLED(PRINTCOUNTER)
+ DECL_SCREEN(StatisticsScreen),
+ #endif
+ #if ENABLED(BABYSTEPPING)
+ DECL_SCREEN(NudgeNozzleScreen),
+ #endif
+ DECL_SCREEN(MoveAxisScreen),
+ DECL_SCREEN(StepsScreen),
+ #if HAS_TRINAMIC_CONFIG
+ DECL_SCREEN(StepperCurrentScreen),
+ DECL_SCREEN(StepperBumpSensitivityScreen),
+ #endif
+ #if HAS_LEVELING
+ DECL_SCREEN(LevelingMenu),
+ #if HAS_BED_PROBE
+ DECL_SCREEN(ZOffsetScreen),
+ #endif
+ #if HAS_MESH
+ DECL_SCREEN(BedMeshScreen),
+ #endif
+ #endif
+ #if HAS_MULTI_HOTEND
+ DECL_SCREEN(NozzleOffsetScreen),
+ #endif
+ #if ENABLED(BACKLASH_GCODE)
+ DECL_SCREEN(BacklashCompensationScreen),
+ #endif
+ DECL_SCREEN(FeedratePercentScreen),
+ DECL_SCREEN(MaxVelocityScreen),
+ DECL_SCREEN(MaxAccelerationScreen),
+ DECL_SCREEN(DefaultAccelerationScreen),
+ #if HAS_JUNCTION_DEVIATION
+ DECL_SCREEN(JunctionDeviationScreen),
+ #else
+ DECL_SCREEN(JerkScreen),
+ #endif
+ #if ENABLED(CASE_LIGHT_ENABLE)
+ DECL_SCREEN(CaseLightScreen),
+ #endif
+ #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
+ DECL_SCREEN(FilamentMenu),
+ #endif
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ DECL_SCREEN(FilamentRunoutScreen),
+ #endif
+ #if ENABLED(LIN_ADVANCE)
+ DECL_SCREEN(LinearAdvanceScreen),
+ #endif
+ DECL_SCREEN(TemperatureScreen),
+ DECL_SCREEN(ChangeFilamentScreen),
+ DECL_SCREEN(InterfaceSettingsScreen),
+ DECL_SCREEN(InterfaceSoundsScreen),
+ DECL_SCREEN(LockScreen),
+ #if ENABLED(SDSUPPORT)
+ DECL_SCREEN(FilesScreen),
+ #endif
+ DECL_SCREEN(EndstopStatesScreen),
+ #if ENABLED(TOUCH_UI_LULZBOT_BIO)
+ DECL_SCREEN(BioPrintingDialogBox),
+ DECL_SCREEN(BioConfirmHomeXYZ),
+ DECL_SCREEN(BioConfirmHomeE),
+ #endif
+ #if ENABLED(TOUCH_UI_COCOA_PRESS)
+ DECL_SCREEN(PreheatMenu),
+ DECL_SCREEN(PreheatTimerScreen),
+ DECL_SCREEN(UnloadCartridgeScreen),
+ DECL_SCREEN(LoadChocolateScreen),
+ DECL_SCREEN(MoveXYZScreen),
+ DECL_SCREEN(MoveEScreen),
+ #endif
+ #if ENABLED(TOUCH_UI_DEVELOPER_MENU)
+ DECL_SCREEN(DeveloperMenu),
+ DECL_SCREEN(ConfirmEraseFlashDialogBox),
+ DECL_SCREEN(WidgetsScreen),
+ DECL_SCREEN(TouchRegistersScreen),
+ DECL_SCREEN(StressTestScreen),
+ #endif
+ DECL_SCREEN(MediaPlayerScreen),
+ DECL_SCREEN(DisplayTuningScreen)
+};
+
+SCREEN_TABLE_POST
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h
new file mode 100644
index 0000000..51fc76f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h
@@ -0,0 +1,911 @@
+/*************
+ * screens.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../ftdi_eve_lib/ftdi_eve_lib.h"
+#include "../language/language.h"
+#include "../theme/theme.h"
+#include "string_format.h"
+
+#ifndef BED_LEVELING_COMMANDS
+ #define BED_LEVELING_COMMANDS "G29"
+#endif
+
+extern tiny_timer_t refresh_timer;
+
+/********************************* DL CACHE SLOTS ******************************/
+
+// In order to reduce SPI traffic, we cache display lists (DL) in RAMG. This
+// is done using the CLCD::DLCache class, which takes a unique ID for each
+// cache location. These IDs are defined here:
+
+enum {
+ STATUS_SCREEN_CACHE,
+ MENU_SCREEN_CACHE,
+ TUNE_SCREEN_CACHE,
+ ALERT_BOX_CACHE,
+ SPINNER_CACHE,
+ ADVANCED_SETTINGS_SCREEN_CACHE,
+ MOVE_AXIS_SCREEN_CACHE,
+ TEMPERATURE_SCREEN_CACHE,
+ STEPS_SCREEN_CACHE,
+ MAX_FEEDRATE_SCREEN_CACHE,
+ MAX_VELOCITY_SCREEN_CACHE,
+ MAX_ACCELERATION_SCREEN_CACHE,
+ DEFAULT_ACCELERATION_SCREEN_CACHE,
+ #if HAS_LEVELING
+ LEVELING_SCREEN_CACHE,
+ #if HAS_BED_PROBE
+ ZOFFSET_SCREEN_CACHE,
+ #endif
+ #if HAS_MESH
+ BED_MESH_SCREEN_CACHE,
+ #endif
+ #endif
+ #if ENABLED(BABYSTEPPING)
+ ADJUST_OFFSETS_SCREEN_CACHE,
+ #endif
+ #if HAS_TRINAMIC_CONFIG
+ STEPPER_CURRENT_SCREEN_CACHE,
+ STEPPER_BUMP_SENSITIVITY_SCREEN_CACHE,
+ #endif
+ #if HAS_MULTI_HOTEND
+ NOZZLE_OFFSET_SCREEN_CACHE,
+ #endif
+ #if ENABLED(BACKLASH_GCODE)
+ BACKLASH_COMPENSATION_SCREEN_CACHE,
+ #endif
+ #if HAS_JUNCTION_DEVIATION
+ JUNC_DEV_SCREEN_CACHE,
+ #else
+ JERK_SCREEN_CACHE,
+ #endif
+ #if ENABLED(CASE_LIGHT_ENABLE)
+ CASE_LIGHT_SCREEN_CACHE,
+ #endif
+ #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
+ FILAMENT_MENU_CACHE,
+ #endif
+ #if ENABLED(LIN_ADVANCE)
+ LINEAR_ADVANCE_SCREEN_CACHE,
+ #endif
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ FILAMENT_RUNOUT_SCREEN_CACHE,
+ #endif
+ #if ENABLED(TOUCH_UI_LULZBOT_BIO)
+ PRINTING_SCREEN_CACHE,
+ #endif
+ #if ENABLED(TOUCH_UI_COCOA_PRESS)
+ PREHEAT_MENU_CACHE,
+ PREHEAT_TIMER_SCREEN_CACHE,
+ UNLOAD_CARTRIDGE_SCREEN_CACHE,
+ LOAD_CHOCOLATE_SCREEN_CACHE,
+ MOVE_XYZ_SCREEN_CACHE,
+ MOVE_E_SCREEN_CACHE,
+ #endif
+ #if ENABLED(SDSUPPORT)
+ FILES_SCREEN_CACHE,
+ #endif
+ #if ENABLED(CUSTOM_USER_MENUS)
+ CUSTOM_USER_MENUS_SCREEN_CACHE,
+ #endif
+ CHANGE_FILAMENT_SCREEN_CACHE,
+ INTERFACE_SETTINGS_SCREEN_CACHE,
+ INTERFACE_SOUNDS_SCREEN_CACHE,
+ LOCK_SCREEN_CACHE,
+ DISPLAY_TIMINGS_SCREEN_CACHE
+};
+
+// To save MCU RAM, the status message is "baked" in to the status screen
+// cache, so we reserve a large chunk of memory for the DL cache
+
+#define STATUS_SCREEN_DL_SIZE 4096
+#define ALERT_BOX_DL_SIZE 3072
+#define SPINNER_DL_SIZE 3072
+#define FILE_SCREEN_DL_SIZE 4160
+#define PRINTING_SCREEN_DL_SIZE 2048
+
+/************************* MENU SCREEN DECLARATIONS *************************/
+
+class BaseScreen : public UIScreen {
+ protected:
+ #if LCD_TIMEOUT_TO_STATUS > 0
+ static uint32_t last_interaction;
+ #endif
+
+ static bool buttonIsPressed(uint8_t tag);
+
+ public:
+ static bool buttonStyleCallback(CommandProcessor &, uint8_t, uint8_t &, uint16_t &, bool);
+
+ static void reset_menu_timeout();
+
+ static void onEntry();
+ static void onIdle();
+};
+
+class BootScreen : public BaseScreen, public UncachedScreen {
+ private:
+ static void showSplashScreen();
+ public:
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+};
+
+class AboutScreen : public BaseScreen, public UncachedScreen {
+ public:
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+#if ENABLED(PRINTCOUNTER)
+ class StatisticsScreen : public BaseScreen, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+#endif
+
+class KillScreen {
+ // The KillScreen is behaves differently than the
+ // others, so we do not bother extending UIScreen.
+ public:
+ static void show(const char*);
+};
+
+class DialogBoxBaseClass : public BaseScreen {
+ protected:
+ template<typename T> static void drawMessage(const T, int16_t font = 0);
+ static void drawYesNoButtons(uint8_t default_btn = 0);
+ static void drawOkayButton();
+ static void drawSpinner();
+ static void drawButton(const progmem_str);
+
+ static void onRedraw(draw_mode_t) {};
+ public:
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+};
+
+class AlertDialogBox : public DialogBoxBaseClass, public CachedScreen<ALERT_BOX_CACHE,ALERT_BOX_DL_SIZE> {
+ public:
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ template<typename T> static void show(T);
+ template<typename T> static void showError(T);
+ static void hide();
+};
+
+class RestoreFailsafeDialogBox : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+class SaveSettingsDialogBox : public DialogBoxBaseClass, public UncachedScreen {
+ private:
+ static bool needs_save;
+
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+
+ static void promptToSaveSettings();
+ static void settingsChanged() {needs_save = true;}
+};
+
+class ConfirmStartPrintDialogBox : public DialogBoxBaseClass, public UncachedScreen {
+ private:
+ inline static const char *getShortFilename() {return getFilename(false);}
+ inline static const char *getLongFilename() {return getFilename(true);}
+
+ static const char *getFilename(bool longName);
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t);
+
+ static void show(uint8_t file_index);
+};
+
+class ConfirmAbortPrintDialogBox : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+#if ENABLED(CALIBRATION_GCODE)
+class ConfirmAutoCalibrationDialogBox : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+#endif
+
+class ConfirmUserRequestAlertBox : public AlertDialogBox {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t);
+ static void hide();
+ static void show(const char*);
+};
+
+#if ENABLED(CUSTOM_USER_MENUS)
+ class CustomUserMenus : public BaseScreen, public CachedScreen<CUSTOM_USER_MENUS_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+#endif
+
+class SpinnerDialogBox : public DialogBoxBaseClass, public CachedScreen<SPINNER_CACHE,SPINNER_DL_SIZE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+
+ static void show(const progmem_str);
+ static void hide();
+ static void enqueueAndWait_P(const progmem_str commands);
+ static void enqueueAndWait_P(const progmem_str message, const progmem_str commands);
+};
+
+#if NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS)
+class StatusScreen : public BaseScreen, public CachedScreen<STATUS_SCREEN_CACHE,STATUS_SCREEN_DL_SIZE> {
+ private:
+ static void draw_axis_position(draw_mode_t);
+ static void draw_temperature(draw_mode_t);
+ static void draw_progress(draw_mode_t);
+ static void draw_interaction_buttons(draw_mode_t);
+ static void draw_status_message(draw_mode_t, const char * const);
+ static void _format_time(char *outstr, uint32_t time);
+ public:
+ static void loadBitmaps();
+ static void setStatusMessage(const char *);
+ static void setStatusMessage(progmem_str);
+ static void onRedraw(draw_mode_t);
+ static void onStartup();
+ static void onEntry();
+ static void onIdle();
+ static bool onTouchEnd(uint8_t tag);
+};
+#else
+ class StatusScreen : public BaseScreen, public CachedScreen<STATUS_SCREEN_CACHE> {
+ private:
+ static float increment;
+ static bool jog_xy;
+ static bool fine_motion;
+
+ static void draw_progress(draw_mode_t what);
+ static void draw_temperature(draw_mode_t what);
+ static void draw_syringe(draw_mode_t what);
+ static void draw_arrows(draw_mode_t what);
+ static void draw_overlay_icons(draw_mode_t what);
+ static void draw_fine_motion(draw_mode_t what);
+ static void draw_buttons(draw_mode_t what);
+ public:
+ static void loadBitmaps();
+ static void unlockMotors();
+
+ static void setStatusMessage(const char *);
+ static void setStatusMessage(progmem_str);
+
+ static void onRedraw(draw_mode_t);
+
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+
+ };
+#endif
+
+#if ENABLED(TOUCH_UI_LULZBOT_BIO)
+ class BioPrintingDialogBox : public BaseScreen, public CachedScreen<PRINTING_SCREEN_CACHE,PRINTING_SCREEN_DL_SIZE> {
+ private:
+ static void draw_status_message(draw_mode_t, const char * const);
+ static void draw_progress(draw_mode_t);
+ static void draw_time_remaining(draw_mode_t);
+ static void draw_interaction_buttons(draw_mode_t);
+ public:
+ static void onRedraw(draw_mode_t);
+
+ static void show();
+
+ static void setStatusMessage(const char *);
+ static void setStatusMessage(progmem_str);
+
+ static void onIdle();
+ static bool onTouchEnd(uint8_t tag);
+ };
+
+ class BioConfirmHomeXYZ : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+
+ class BioConfirmHomeE : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+#endif
+
+class MainMenu : public BaseScreen, public CachedScreen<MENU_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+class TuneMenu : public BaseScreen, public CachedScreen<TUNE_SCREEN_CACHE> {
+ private:
+ static void pausePrint();
+ static void resumePrint();
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+class TouchCalibrationScreen : public BaseScreen, public UncachedScreen {
+ public:
+ static void onRefresh();
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+};
+
+class TouchRegistersScreen : public BaseScreen, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+class AdvancedSettingsMenu : public BaseScreen, public CachedScreen<ADVANCED_SETTINGS_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+class ChangeFilamentScreen : public BaseScreen, public CachedScreen<CHANGE_FILAMENT_SCREEN_CACHE> {
+ private:
+ static uint8_t getSoftenTemp();
+ static ExtUI::extruder_t getExtruder();
+ static void drawTempGradient(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
+ static uint32_t getTempColor(uint32_t temp);
+ static void doPurge();
+ public:
+ static void onEntry();
+ static void onExit();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+ static void onIdle();
+};
+
+class BaseNumericAdjustmentScreen : public BaseScreen {
+ public:
+ enum precision_default_t {
+ DEFAULT_LOWEST,
+ DEFAULT_MIDRANGE,
+ DEFAULT_HIGHEST
+ };
+
+ protected:
+ class widgets_t {
+ private:
+ draw_mode_t _what;
+ uint8_t _line;
+ uint32_t _color;
+ uint8_t _decimals;
+ progmem_str _units;
+ enum style_t {
+ BTN_NORMAL,
+ BTN_ACTION,
+ BTN_TOGGLE,
+ BTN_DISABLED,
+ TEXT_AREA,
+ TEXT_LABEL
+ } _style;
+
+ protected:
+ void _draw_increment_btn(CommandProcessor &, uint8_t line, const uint8_t tag);
+ void _button(CommandProcessor &, uint8_t tag, int16_t x, int16_t y, int16_t w, int16_t h, progmem_str, bool enabled = true, bool highlight = false);
+ void _button_style(CommandProcessor &cmd, style_t style);
+ public:
+ widgets_t(draw_mode_t);
+
+ widgets_t &color(uint32_t color) {_color = color; return *this;}
+ widgets_t &units(progmem_str units) {_units = units; return *this;}
+ widgets_t &draw_mode(draw_mode_t what) {_what = what; return *this;}
+ widgets_t &precision(uint8_t decimals, precision_default_t = DEFAULT_HIGHEST);
+
+ void heading (progmem_str label);
+ void adjuster_sram_val (uint8_t tag, progmem_str label, const char *value, bool is_enabled = true);
+ void adjuster (uint8_t tag, progmem_str label, const char *value, bool is_enabled = true);
+ void adjuster (uint8_t tag, progmem_str label, float value=0, bool is_enabled = true);
+ void button (uint8_t tag, progmem_str label, bool is_enabled = true);
+ void text_field (uint8_t tag, progmem_str label, const char *value, bool is_enabled = true);
+ void two_buttons (uint8_t tag1, progmem_str label1,
+ uint8_t tag2, progmem_str label2, bool is_enabled = true);
+ void toggle (uint8_t tag, progmem_str label, bool value, bool is_enabled = true);
+ void home_buttons (uint8_t tag);
+ void increments ();
+ };
+
+ static float getIncrement();
+
+ public:
+ static void onEntry();
+ static bool onTouchEnd(uint8_t tag);
+};
+
+class BaseMoveAxisScreen : public BaseNumericAdjustmentScreen {
+ private:
+ static float getManualFeedrate(uint8_t axis, float increment_mm);
+ public:
+ static void setManualFeedrate(ExtUI::axis_t, float increment_mm);
+ static void setManualFeedrate(ExtUI::extruder_t, float increment_mm);
+
+ static void onEntry();
+ static bool onTouchHeld(uint8_t tag);
+};
+
+class MoveAxisScreen : public BaseMoveAxisScreen, public CachedScreen<MOVE_AXIS_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+};
+
+class StepsScreen : public BaseNumericAdjustmentScreen, public CachedScreen<STEPS_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+};
+
+#if HAS_TRINAMIC_CONFIG
+ class StepperCurrentScreen : public BaseNumericAdjustmentScreen, public CachedScreen<STEPPER_CURRENT_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+
+ class StepperBumpSensitivityScreen : public BaseNumericAdjustmentScreen, public CachedScreen<STEPPER_BUMP_SENSITIVITY_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#endif
+
+#if HAS_MULTI_HOTEND
+ class NozzleOffsetScreen : public BaseNumericAdjustmentScreen, public CachedScreen<NOZZLE_OFFSET_SCREEN_CACHE> {
+ public:
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#endif
+
+#if HAS_LEVELING
+
+ class LevelingMenu : public BaseScreen, public CachedScreen<LEVELING_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+
+ #if HAS_BED_PROBE
+ class ZOffsetScreen : public BaseNumericAdjustmentScreen, public CachedScreen<ZOFFSET_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+ #endif
+
+ #if HAS_MESH
+
+ class BedMeshScreen : public BaseScreen, public CachedScreen<BED_MESH_SCREEN_CACHE> {
+ private:
+ enum MeshOpts {
+ USE_POINTS = 0x01,
+ USE_COLORS = 0x02,
+ USE_TAGS = 0x04,
+ USE_HIGHLIGHT = 0x08,
+ USE_AUTOSCALE = 0x10
+ };
+
+ static uint8_t pointToTag(uint8_t x, uint8_t y);
+ static bool tagToPoint(uint8_t tag, uint8_t &x, uint8_t &y);
+ static float getHightlightedValue();
+ static void drawHighlightedPointValue();
+ static void drawMesh(int16_t x, int16_t y, int16_t w, int16_t h, ExtUI::bed_mesh_t data, uint8_t opts, float autoscale_max = 0.1);
+
+ public:
+ static void onMeshUpdate(const int8_t x, const int8_t y, const float val);
+ static void onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t);
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+
+ static void startMeshProbe();
+ };
+
+ #endif // HAS_MESH
+
+#endif // HAS_LEVELING
+
+#if ENABLED(BABYSTEPPING)
+ class NudgeNozzleScreen : public BaseNumericAdjustmentScreen, public CachedScreen<ADJUST_OFFSETS_SCREEN_CACHE> {
+ public:
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+ static void onIdle();
+ };
+#endif
+
+#if ENABLED(BACKLASH_GCODE)
+ class BacklashCompensationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<BACKLASH_COMPENSATION_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#endif
+
+class FeedratePercentScreen : public BaseNumericAdjustmentScreen, public CachedScreen<MAX_FEEDRATE_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+};
+
+class MaxVelocityScreen : public BaseNumericAdjustmentScreen, public CachedScreen<MAX_VELOCITY_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+};
+
+class MaxAccelerationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<MAX_ACCELERATION_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+};
+
+class DefaultAccelerationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<DEFAULT_ACCELERATION_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+};
+
+#if HAS_JUNCTION_DEVIATION
+ class JunctionDeviationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<JUNC_DEV_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#else
+ class JerkScreen : public BaseNumericAdjustmentScreen, public CachedScreen<JERK_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#endif
+
+#if ENABLED(CASE_LIGHT_ENABLE)
+ class CaseLightScreen : public BaseNumericAdjustmentScreen, public CachedScreen<CASE_LIGHT_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#endif
+
+#if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
+ class FilamentMenu : public BaseNumericAdjustmentScreen, public CachedScreen<FILAMENT_MENU_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+#endif
+
+#if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ class FilamentRunoutScreen : public BaseNumericAdjustmentScreen, public CachedScreen<FILAMENT_RUNOUT_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#endif
+
+#if ENABLED(LIN_ADVANCE)
+ class LinearAdvanceScreen : public BaseNumericAdjustmentScreen, public CachedScreen<LINEAR_ADVANCE_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+ };
+#endif
+
+class TemperatureScreen : public BaseNumericAdjustmentScreen, public CachedScreen<TEMPERATURE_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+};
+
+class InterfaceSoundsScreen : public BaseScreen, public CachedScreen<INTERFACE_SOUNDS_SCREEN_CACHE> {
+ public:
+ enum event_t {
+ PRINTING_STARTED = 0,
+ PRINTING_FINISHED = 1,
+ PRINTING_FAILED = 2,
+
+ NUM_EVENTS
+ };
+
+ private:
+ friend class InterfaceSettingsScreen;
+
+ static uint8_t event_sounds[NUM_EVENTS];
+
+ static const char* getSoundSelection(event_t);
+ static void toggleSoundSelection(event_t);
+ static void setSoundSelection(event_t, const FTDI::SoundPlayer::sound_t*);
+
+ public:
+ static void playEventSound(event_t, FTDI::play_mode_t = FTDI::PLAY_ASYNCHRONOUS);
+
+ static void defaultSettings();
+
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+};
+
+class InterfaceSettingsScreen : public BaseScreen, public CachedScreen<INTERFACE_SETTINGS_SCREEN_CACHE> {
+ private:
+ struct persistent_data_t {
+ uint32_t touch_transform_a;
+ uint32_t touch_transform_b;
+ uint32_t touch_transform_c;
+ uint32_t touch_transform_d;
+ uint32_t touch_transform_e;
+ uint32_t touch_transform_f;
+ uint16_t passcode;
+ uint8_t display_brightness;
+ int8_t display_h_offset_adj;
+ int8_t display_v_offset_adj;
+ uint8_t sound_volume;
+ uint8_t bit_flags;
+ uint8_t event_sounds[InterfaceSoundsScreen::NUM_EVENTS];
+ };
+
+ public:
+ #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE
+ static bool backupEEPROM();
+ #endif
+
+ static void saveSettings(char *);
+ static void loadSettings(const char *);
+ static void defaultSettings();
+ static void failSafeSettings();
+
+ static void onStartup();
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+};
+
+class LockScreen : public BaseScreen, public CachedScreen<LOCK_SCREEN_CACHE> {
+ private:
+ friend InterfaceSettingsScreen;
+
+ static uint16_t passcode;
+
+ static char & message_style();
+ static uint16_t compute_checksum();
+ static void onPasscodeEntered();
+ public:
+ static bool is_enabled();
+ static void check_passcode();
+ static void enable();
+ static void disable();
+
+ static void set_hash(uint16_t pass) {passcode = pass;};
+ static uint16_t get_hash() {return passcode;};
+
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
+
+#if ENABLED(SDSUPPORT)
+
+ class FilesScreen : public BaseScreen, public CachedScreen<FILES_SCREEN_CACHE, FILE_SCREEN_DL_SIZE> {
+ private:
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ static constexpr uint8_t header_h = 2;
+ static constexpr uint8_t footer_h = 2;
+ static constexpr uint8_t files_per_page = 11;
+ #else
+ static constexpr uint8_t header_h = 1;
+ static constexpr uint8_t footer_h = 1;
+ static constexpr uint8_t files_per_page = 6;
+ #endif
+
+ static uint8_t getTagForLine(uint8_t line) {return line + 2;}
+ static uint8_t getLineForTag(uint8_t tag) {return tag - 2;}
+ static uint16_t getFileForTag(uint8_t tag);
+ static uint16_t getSelectedFileIndex();
+
+ inline static const char *getSelectedShortFilename() {return getSelectedFilename(false);}
+ inline static const char *getSelectedLongFilename() {return getSelectedFilename(true);}
+ static const char *getSelectedFilename(bool longName);
+
+ static void drawFileButton(const char* filename, uint8_t tag, bool is_dir, bool is_highlighted);
+ static void drawFileList();
+ static void drawHeader();
+ static void drawFooter();
+ static void drawSelectedFile();
+
+ static void gotoPage(uint8_t);
+ public:
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+ };
+
+#endif // SDSUPPORT
+
+class EndstopStatesScreen : public BaseScreen, public UncachedScreen {
+ public:
+ static void onEntry();
+ static void onExit();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+};
+
+class DisplayTuningScreen : public BaseNumericAdjustmentScreen, public CachedScreen<DISPLAY_TIMINGS_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchHeld(uint8_t tag);
+};
+
+#if ENABLED(TOUCH_UI_DEVELOPER_MENU)
+
+ class DeveloperMenu : public BaseScreen, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+
+ class ConfirmEraseFlashDialogBox : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+
+ class WidgetsScreen : public BaseScreen, public UncachedScreen {
+ public:
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchStart(uint8_t tag);
+ static void onIdle();
+ };
+
+ class StressTestScreen : public BaseScreen, public UncachedScreen {
+ private:
+ static void drawDots(uint16_t x, uint16_t y, uint16_t h, uint16_t v);
+ static bool watchDogTestNow();
+ static void recursiveLockup();
+ static void iterativeLockup();
+ static void runTestOnBootup(bool enable);
+
+ public:
+ static void startupCheck();
+
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+ };
+
+#endif // TOUCH_UI_DEVELOPER_MENU
+
+class MediaPlayerScreen : public BaseScreen, public UncachedScreen {
+ private:
+ typedef int16_t media_streamer_func_t(void *obj, void *buff, size_t bytes);
+
+ public:
+ static bool playCardMedia();
+ static bool playBootMedia();
+
+ static void onEntry();
+ static void onRedraw(draw_mode_t);
+
+ static void playStream(void *obj, media_streamer_func_t*);
+};
+
+#if NUM_LANGUAGES > 1
+ class LanguageMenu : public BaseScreen, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+#endif
+
+#if ENABLED(TOUCH_UI_COCOA_PRESS)
+
+ class PreheatMenu : public BaseScreen, public CachedScreen<PREHEAT_MENU_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ };
+
+ class PreheatTimerScreen : public BaseScreen, public CachedScreen<PREHEAT_TIMER_SCREEN_CACHE> {
+ private:
+ static uint16_t secondsRemaining();
+
+ static void draw_message(draw_mode_t);
+ static void draw_time_remaining(draw_mode_t);
+ static void draw_interaction_buttons(draw_mode_t);
+ static void draw_adjuster(draw_mode_t, uint8_t tag, progmem_str label, float value, int16_t x, int16_t y, int16_t w, int16_t h);
+ public:
+ static void onRedraw(draw_mode_t);
+
+ static void onEntry();
+ static void onIdle();
+ static bool onTouchHeld(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ };
+
+ class UnloadCartridgeScreen : public BaseScreen, public CachedScreen<UNLOAD_CARTRIDGE_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+ };
+
+ class LoadChocolateScreen : public BaseScreen, public CachedScreen<LOAD_CHOCOLATE_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+ };
+
+ class MoveXYZScreen : public BaseMoveAxisScreen, public CachedScreen<MOVE_XYZ_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+ };
+
+ class MoveEScreen : public BaseMoveAxisScreen, public CachedScreen<MOVE_E_SCREEN_CACHE> {
+ public:
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+ };
+
+#endif // TOUCH_UI_COCOA_PRESS
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/spinner_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/spinner_dialog_box.cpp
new file mode 100644
index 0000000..2318a0d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/spinner_dialog_box.cpp
@@ -0,0 +1,68 @@
+/**************************
+ * spinner_dialog_box.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+#include "screen_data.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+
+void SpinnerDialogBox::onRedraw(draw_mode_t) {
+}
+
+void SpinnerDialogBox::show(const progmem_str message) {
+ drawMessage(message);
+ drawSpinner();
+ storeBackground();
+ screen_data.SpinnerDialog.auto_hide = false;
+}
+
+void SpinnerDialogBox::hide() {
+ CommandProcessor cmd;
+ cmd.stop().execute();
+}
+
+void SpinnerDialogBox::enqueueAndWait_P(const progmem_str commands) {
+ enqueueAndWait_P(GET_TEXT_F(MSG_PLEASE_WAIT), commands);
+}
+
+void SpinnerDialogBox::enqueueAndWait_P(const progmem_str message, const progmem_str commands) {
+ show(message);
+ GOTO_SCREEN(SpinnerDialogBox);
+ ExtUI::injectCommands_P((const char*)commands);
+ screen_data.SpinnerDialog.auto_hide = true;
+}
+
+void SpinnerDialogBox::onIdle() {
+ reset_menu_timeout();
+ if (screen_data.SpinnerDialog.auto_hide && !commandsInQueue()) {
+ screen_data.SpinnerDialog.auto_hide = false;
+ hide();
+ GOTO_PREVIOUS();
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/statistics_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/statistics_screen.cpp
new file mode 100644
index 0000000..0e224da
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/statistics_screen.cpp
@@ -0,0 +1,78 @@
+/*************************
+ * statistics_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, PRINTCOUNTER)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_COLS 4
+#define GRID_ROWS 7
+
+void StatisticsScreen::onRedraw(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ char buffer[21];
+
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+
+ .font(Theme::font_medium)
+ .text(BTN_POS(1,1), BTN_SIZE(4,1), GET_TEXT_F(MSG_INFO_STATS_MENU))
+ .font(Theme::font_small)
+ .tag(0)
+ .text(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_COUNT), OPT_RIGHTX | OPT_CENTERY)
+ .text(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_COMPLETED_PRINTS), OPT_RIGHTX | OPT_CENTERY)
+ .text(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_TIME), OPT_RIGHTX | OPT_CENTERY)
+ .text(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_LONGEST), OPT_RIGHTX | OPT_CENTERY)
+ .text(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_FILAMENT), OPT_RIGHTX | OPT_CENTERY);
+ // Don't chain the following, it causes strange issues with evaluation ordering!
+ cmd.text(BTN_POS(3,2), BTN_SIZE(2,1), getTotalPrints_str(buffer));
+ cmd.text(BTN_POS(3,3), BTN_SIZE(2,1), getFinishedPrints_str(buffer));
+ cmd.text(BTN_POS(3,4), BTN_SIZE(2,1), getTotalPrintTime_str(buffer));
+ cmd.text(BTN_POS(3,5), BTN_SIZE(2,1), getLongestPrint_str(buffer));
+ cmd.text(BTN_POS(3,6), BTN_SIZE(2,1), getFilamentUsed_str(buffer));
+ }
+
+ if (what & FOREGROUND) {
+ cmd.font(Theme::font_medium)
+ .colors(action_btn)
+ .tag(1).button(BTN_POS(1,7), BTN_SIZE(4,1), GET_TEXT_F(MSG_BACK));
+ }
+}
+
+bool StatisticsScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); return true;
+ default: return false;
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE && PRINTCOUNTER
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/status_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/status_screen.cpp
new file mode 100644
index 0000000..51f5034
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/status_screen.cpp
@@ -0,0 +1,465 @@
+/*********************
+ * status_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS)
+
+#include "screens.h"
+#include "screen_data.h"
+
+#include "../archim2-flash/flash_storage.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 16
+#else
+ #define GRID_ROWS 16
+#endif
+
+void StatusScreen::draw_axis_position(draw_mode_t what) {
+ CommandProcessor cmd;
+
+ #define GRID_COLS 3
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define X_LBL_POS BTN_POS(1, 9), BTN_SIZE(1,2)
+ #define Y_LBL_POS BTN_POS(1,11), BTN_SIZE(1,2)
+ #define Z_LBL_POS BTN_POS(1,13), BTN_SIZE(1,2)
+ #define X_VAL_POS BTN_POS(2, 9), BTN_SIZE(2,2)
+ #define Y_VAL_POS BTN_POS(2,11), BTN_SIZE(2,2)
+ #define Z_VAL_POS BTN_POS(2,13), BTN_SIZE(2,2)
+ #else
+ #define X_LBL_POS BTN_POS(1, 9), BTN_SIZE(1,2)
+ #define Y_LBL_POS BTN_POS(2, 9), BTN_SIZE(1,2)
+ #define Z_LBL_POS BTN_POS(3, 9), BTN_SIZE(1,2)
+ #define X_VAL_POS BTN_POS(1,11), BTN_SIZE(1,2)
+ #define Y_VAL_POS BTN_POS(2,11), BTN_SIZE(1,2)
+ #define Z_VAL_POS BTN_POS(3,11), BTN_SIZE(1,2)
+ #endif
+
+ #define _UNION_POS(x1,y1,w1,h1,x2,y2,w2,h2) x1,y1,max(x1+w1,x2+w2)-x1,max(y1+h1,y2+h2)-y1
+ #define UNION_POS(p1, p2) _UNION_POS(p1, p2)
+
+ if (what & BACKGROUND) {
+ cmd.tag(6)
+ .fgcolor(Theme::axis_label)
+ .font(Theme::font_large)
+ .button(UNION_POS(X_LBL_POS, X_VAL_POS), F(""), OPT_FLAT)
+ .button(UNION_POS(Y_LBL_POS, Y_VAL_POS), F(""), OPT_FLAT)
+ .button(UNION_POS(Z_LBL_POS, Z_VAL_POS), F(""), OPT_FLAT)
+ .font(Theme::font_medium)
+ .fgcolor(Theme::x_axis) .button(X_VAL_POS, F(""), OPT_FLAT)
+ .fgcolor(Theme::y_axis) .button(Y_VAL_POS, F(""), OPT_FLAT)
+ .fgcolor(Theme::z_axis) .button(Z_VAL_POS, F(""), OPT_FLAT)
+ .font(Theme::font_small)
+ .text ( X_LBL_POS, GET_TEXT_F(MSG_AXIS_X))
+ .text ( Y_LBL_POS, GET_TEXT_F(MSG_AXIS_Y))
+ .text ( Z_LBL_POS, GET_TEXT_F(MSG_AXIS_Z))
+ .colors(normal_btn);
+ }
+
+ if (what & FOREGROUND) {
+ using namespace ExtUI;
+ char x_str[15];
+ char y_str[15];
+ char z_str[15];
+
+ if (isAxisPositionKnown(X))
+ format_position(x_str, getAxisPosition_mm(X));
+ else
+ strcpy_P(x_str, PSTR("?"));
+
+ if (isAxisPositionKnown(Y))
+ format_position(y_str, getAxisPosition_mm(Y));
+ else
+ strcpy_P(y_str, PSTR("?"));
+
+ if (isAxisPositionKnown(Z))
+ format_position(z_str, getAxisPosition_mm(Z), 2);
+ else
+ strcpy_P(z_str, PSTR("?"));
+
+ cmd.tag(6)
+ .font(Theme::font_medium)
+ .text(X_VAL_POS, x_str)
+ .text(Y_VAL_POS, y_str)
+ .text(Z_VAL_POS, z_str);
+ }
+
+ #undef GRID_COLS
+}
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_COLS 8
+#else
+ #define GRID_COLS 12
+#endif
+
+void StatusScreen::draw_temperature(draw_mode_t what) {
+ using namespace Theme;
+
+ #define TEMP_RECT_1 BTN_POS(1,1), BTN_SIZE(4,4)
+ #define TEMP_RECT_2 BTN_POS(1,1), BTN_SIZE(8,2)
+ #define NOZ_1_POS BTN_POS(1,1), BTN_SIZE(4,2)
+ #define NOZ_2_POS BTN_POS(5,1), BTN_SIZE(4,2)
+ #define BED_POS BTN_POS(1,3), BTN_SIZE(4,2)
+ #define FAN_POS BTN_POS(5,3), BTN_SIZE(4,2)
+
+ #define _ICON_POS(x,y,w,h) x, y, w/4, h
+ #define _TEXT_POS(x,y,w,h) x + w/4, y, w - w/4, h
+ #define ICON_POS(pos) _ICON_POS(pos)
+ #define TEXT_POS(pos) _TEXT_POS(pos)
+
+ CommandProcessor cmd;
+
+ if (what & BACKGROUND) {
+ cmd.font(Theme::font_small)
+ .tag(5)
+ .fgcolor(temp) .button(TEMP_RECT_1, F(""), OPT_FLAT)
+ .button(TEMP_RECT_2, F(""), OPT_FLAT)
+ .fgcolor(fan_speed).button(FAN_POS, F(""), OPT_FLAT)
+ .tag(0);
+
+ // Draw Extruder Bitmap on Extruder Temperature Button
+
+ cmd.tag(5)
+ .cmd (BITMAP_SOURCE(Extruder_Icon_Info))
+ .cmd (BITMAP_LAYOUT(Extruder_Icon_Info))
+ .cmd (BITMAP_SIZE (Extruder_Icon_Info))
+ .icon(ICON_POS(NOZ_1_POS), Extruder_Icon_Info, icon_scale)
+ .icon(ICON_POS(NOZ_2_POS), Extruder_Icon_Info, icon_scale);
+
+ // Draw Bed Heat Bitmap on Bed Heat Button
+ cmd.cmd (BITMAP_SOURCE(Bed_Heat_Icon_Info))
+ .cmd (BITMAP_LAYOUT(Bed_Heat_Icon_Info))
+ .cmd (BITMAP_SIZE (Bed_Heat_Icon_Info))
+ .icon(ICON_POS(BED_POS), Bed_Heat_Icon_Info, icon_scale);
+
+ // Draw Fan Percent Bitmap on Bed Heat Button
+
+ cmd.cmd (BITMAP_SOURCE(Fan_Icon_Info))
+ .cmd (BITMAP_LAYOUT(Fan_Icon_Info))
+ .cmd (BITMAP_SIZE (Fan_Icon_Info))
+ .icon(ICON_POS(FAN_POS), Fan_Icon_Info, icon_scale);
+
+ TERN_(TOUCH_UI_USE_UTF8, load_utf8_bitmaps(cmd)); // Restore font bitmap handles
+ }
+
+ if (what & FOREGROUND) {
+ using namespace ExtUI;
+ char e0_str[20], e1_str[20], bed_str[20], fan_str[20];
+
+ sprintf_P(fan_str, PSTR("%-3d %%"), int8_t(getActualFan_percent(FAN0)));
+
+ if (isHeaterIdle(BED))
+ format_temp_and_idle(bed_str, getActualTemp_celsius(BED));
+ else
+ format_temp_and_temp(bed_str, getActualTemp_celsius(BED), getTargetTemp_celsius(BED));
+
+ if (isHeaterIdle(H0))
+ format_temp_and_idle(e0_str, getActualTemp_celsius(H0));
+ else
+ format_temp_and_temp(e0_str, getActualTemp_celsius(H0), getTargetTemp_celsius(H0));
+
+ #if HAS_MULTI_EXTRUDER
+ if (isHeaterIdle(H1))
+ format_temp_and_idle(e1_str, getActualTemp_celsius(H1));
+ else
+ format_temp_and_temp(e1_str, getActualTemp_celsius(H1), getTargetTemp_celsius(H1));
+ #else
+ strcpy_P(e1_str, PSTR("-"));
+ #endif
+
+ cmd.tag(5)
+ .font(font_medium)
+ .text(TEXT_POS(NOZ_1_POS), e0_str)
+ .text(TEXT_POS(NOZ_2_POS), e1_str)
+ .text(TEXT_POS(BED_POS), bed_str)
+ .text(TEXT_POS(FAN_POS), fan_str);
+ }
+}
+
+void StatusScreen::_format_time(char *outstr, uint32_t time) {
+ const uint8_t hrs = time / 3600,
+ min = (time / 60) % 60,
+ sec = time % 60;
+ if (hrs)
+ sprintf_P(outstr, PSTR("%02d:%02d"), hrs, min);
+ else
+ sprintf_P(outstr, PSTR("%02d:%02ds"), min, sec);
+}
+
+void StatusScreen::draw_progress(draw_mode_t what) {
+ using namespace ExtUI;
+ using namespace Theme;
+
+ CommandProcessor cmd;
+
+ #undef GRID_COLS
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_COLS 3
+ #define PROGRESSZONE_POS BTN_POS(1,5), BTN_SIZE(3,2)
+ #define TIME_POS_X BTN_X(1)
+ #define TIME_POS_W BTN_W(1)
+ #define REMAINING_POS_X BTN_X(2)
+ #define REMAINING_POS_W BTN_W(1)
+ #define PROGRESS_POS_X BTN_X(3)
+ #define PROGRESS_POS_W BTN_W(1)
+ #define PROGRESSZONE_FIRSTLINE_Y BTN_Y(5)
+ #define PROGRESSBAR_POS BTN_POS(1,6), BTN_SIZE(3,1)
+ #else
+ #define GRID_COLS 6
+ #define PROGRESSZONE_POS BTN_POS(5,1), BTN_SIZE(2,4)
+ #if ENABLED(SHOW_REMAINING_TIME)
+ #define TIME_POS BTN_POS(5,1), BTN_SIZE(1,2)
+ #define REMAINING_POS BTN_POS(6,1), BTN_SIZE(1,2)
+ #else
+ #define TIME_POS BTN_POS(5,1), BTN_SIZE(2,2)
+ #endif
+ #define PROGRESS_POS BTN_POS(5,3), BTN_SIZE(2,2)
+ #define PROGRESSBAR_POS BTN_POS(5,2), BTN_SIZE(2,2)
+ #endif
+
+ if (what & BACKGROUND) {
+ cmd.tag(0).font(font_medium)
+ .fgcolor(progress).button(PROGRESSZONE_POS, F(""), OPT_FLAT);
+ }
+
+ if (what & FOREGROUND) {
+ const uint32_t elapsed = getProgress_seconds_elapsed();
+ char elapsed_str[10];
+ _format_time(elapsed_str, elapsed);
+
+ #if ENABLED(SHOW_REMAINING_TIME)
+ const uint32_t remaining = getProgress_seconds_remaining();
+ char remaining_str[10];
+ _format_time(remaining_str, remaining);
+ #endif
+
+ const uint16_t current_progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, getProgress_permyriad(), getProgress_percent() * 100);
+ constexpr uint16_t progress_range = 10000U;
+
+ const bool show_progress_bar = current_progress > 0 && current_progress < progress_range + 1;
+ if (show_progress_bar) {
+ cmd.tag(0).font(font_medium)
+ .bgcolor(progress)
+ .progress(PROGRESSBAR_POS, current_progress, progress_range, OPT_FLAT);
+ }
+
+ char progress_str[10];
+ sprintf_P(progress_str,
+ #if ENABLED(PRINT_PROGRESS_SHOW_DECIMALS)
+ PSTR("%3d.%02d%%"), uint8_t(current_progress / 100), current_progress % 100
+ #else
+ PSTR("%3d%%"), uint8_t(current_progress / 100)
+ #endif
+ );
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ const uint16_t texts_pos_h = show_progress_bar ? (BTN_H(1)) : (BTN_H(2));
+ cmd.font(font_medium)
+ .tag(7).text(TIME_POS_X, PROGRESSZONE_FIRSTLINE_Y, TIME_POS_W, texts_pos_h, elapsed_str)
+ #if ENABLED(SHOW_REMAINING_TIME)
+ .text(REMAINING_POS_X, PROGRESSZONE_FIRSTLINE_Y, REMAINING_POS_W, texts_pos_h, remaining_str)
+ #endif
+ .text(PROGRESS_POS_X, PROGRESSZONE_FIRSTLINE_Y, PROGRESS_POS_W, texts_pos_h, progress_str);
+ #else
+ cmd.font(font_medium)
+ .tag(7).text(TIME_POS, elapsed_str)
+ #if ENABLED(SHOW_REMAINING_TIME)
+ .text(REMAINING_POS, remaining_str)
+ #endif
+ .text(PROGRESS_POS, progress_str);
+ #endif
+ }
+
+ #undef GRID_COLS
+}
+
+void StatusScreen::draw_interaction_buttons(draw_mode_t what) {
+ #define GRID_COLS 4
+ if (what & FOREGROUND) {
+ using namespace ExtUI;
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define MEDIA_BTN_POS BTN_POS(1,15), BTN_SIZE(2,2)
+ #define MENU_BTN_POS BTN_POS(3,15), BTN_SIZE(2,2)
+ #else
+ #define MEDIA_BTN_POS BTN_POS(1,13), BTN_SIZE(2,4)
+ #define MENU_BTN_POS BTN_POS(3,13), BTN_SIZE(2,4)
+ #endif
+
+ const bool has_media = isMediaInserted() && !isPrintingFromMedia();
+
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ .colors(has_media ? action_btn : normal_btn)
+ .enabled(has_media)
+ .tag(3).button(MEDIA_BTN_POS, isPrintingFromMedia() ? GET_TEXT_F(MSG_PRINTING) : GET_TEXT_F(MSG_BUTTON_MEDIA))
+ .colors(!has_media ? action_btn : normal_btn)
+ .tag(4).button(MENU_BTN_POS, GET_TEXT_F(MSG_BUTTON_MENU));
+ }
+ #undef GRID_COLS
+}
+
+void StatusScreen::draw_status_message(draw_mode_t what, const char* message) {
+ #define GRID_COLS 1
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define STATUS_POS BTN_POS(1,7), BTN_SIZE(1,2)
+ #else
+ #define STATUS_POS BTN_POS(1,5), BTN_SIZE(1,4)
+ #endif
+
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.fgcolor(Theme::status_msg)
+ .tag(0)
+ .button(STATUS_POS, F(""), OPT_FLAT);
+
+ draw_text_box(cmd, STATUS_POS, message, OPT_CENTER, font_large);
+ }
+ #undef GRID_COLS
+}
+
+void StatusScreen::setStatusMessage(progmem_str message) {
+ char buff[strlen_P((const char * const)message)+1];
+ strcpy_P(buff, (const char * const) message);
+ setStatusMessage((const char *) buff);
+}
+
+void StatusScreen::setStatusMessage(const char* message) {
+ if (CommandProcessor::is_processing()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Cannot update status message, command processor busy");
+ #endif
+ return;
+ }
+
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+
+ draw_temperature(BACKGROUND);
+ draw_status_message(BACKGROUND, message);
+ draw_interaction_buttons(BACKGROUND);
+ draw_progress(BACKGROUND);
+ draw_axis_position(BACKGROUND);
+
+ storeBackground();
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("New status message: ", message);
+ #endif
+
+ if (AT_SCREEN(StatusScreen)) {
+ current_screen.onRefresh();
+ }
+}
+
+void StatusScreen::loadBitmaps() {
+ // Load the bitmaps for the status screen
+ using namespace Theme;
+ constexpr uint32_t base = ftdi_memory_map::RAM_G;
+ CLCD::mem_write_pgm(base + TD_Icon_Info.RAMG_offset, TD_Icon, sizeof(TD_Icon));
+ CLCD::mem_write_pgm(base + Extruder_Icon_Info.RAMG_offset, Extruder_Icon, sizeof(Extruder_Icon));
+ CLCD::mem_write_pgm(base + Bed_Heat_Icon_Info.RAMG_offset, Bed_Heat_Icon, sizeof(Bed_Heat_Icon));
+ CLCD::mem_write_pgm(base + Fan_Icon_Info.RAMG_offset, Fan_Icon, sizeof(Fan_Icon));
+
+ // Load fonts for internationalization
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_data(base + UTF8_FONT_OFFSET);
+ #endif
+}
+
+void StatusScreen::onStartup() {
+ UIFlashStorage::initialize();
+}
+
+void StatusScreen::onRedraw(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ draw_temperature(FOREGROUND);
+ draw_progress(FOREGROUND);
+ draw_axis_position(FOREGROUND);
+ draw_interaction_buttons(FOREGROUND);
+ }
+}
+
+void StatusScreen::onEntry() {
+ BaseScreen::onEntry();
+ onRefresh();
+}
+
+void StatusScreen::onIdle() {
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+
+bool StatusScreen::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ switch (tag) {
+ #if ENABLED(SDSUPPORT)
+ case 3: GOTO_SCREEN(FilesScreen); break;
+ #endif
+ case 4:
+ if (isPrinting()) {
+ GOTO_SCREEN(TuneMenu);
+ }
+ else {
+ GOTO_SCREEN(MainMenu);
+ }
+ break;
+ case 5: GOTO_SCREEN(TemperatureScreen); break;
+ case 6:
+ if (isPrinting()) {
+ #if ENABLED(BABYSTEPPING)
+ GOTO_SCREEN(NudgeNozzleScreen);
+ #elif HAS_BED_PROBE
+ GOTO_SCREEN(ZOffsetScreen);
+ #else
+ return false;
+ #endif
+ }
+ else {
+ GOTO_SCREEN(MoveAxisScreen);
+ }
+ break;
+ case 7: GOTO_SCREEN(FeedratePercentScreen); break;
+ default:
+ return true;
+ }
+ // If a passcode is enabled, the LockScreen will prevent the
+ // user from proceeding.
+ LockScreen::check_passcode();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_bump_sensitivity_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_bump_sensitivity_screen.cpp
new file mode 100644
index 0000000..84d76dc
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_bump_sensitivity_screen.cpp
@@ -0,0 +1,59 @@
+/**************************************
+ * stepper_bump_sensiivity_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, HAS_TRINAMIC_CONFIG)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void StepperBumpSensitivityScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(0, BaseNumericAdjustmentScreen::DEFAULT_LOWEST);
+ w.heading( GET_TEXT_F(MSG_TMC_HOMING_THRS));
+ w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getTMCBumpSensitivity(X), ENABLED(X_SENSORLESS));
+ w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getTMCBumpSensitivity(Y), ENABLED(Y_SENSORLESS));
+ w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getTMCBumpSensitivity(Z), ENABLED(Z_SENSORLESS));
+ w.increments();
+}
+
+bool StepperBumpSensitivityScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(TMCBumpSensitivity, X); break;
+ case 3: UI_INCREMENT(TMCBumpSensitivity, X); break;
+ case 4: UI_DECREMENT(TMCBumpSensitivity, Y); break;
+ case 5: UI_INCREMENT(TMCBumpSensitivity, Y); break;
+ case 6: UI_DECREMENT(TMCBumpSensitivity, Z); break;
+ case 7: UI_INCREMENT(TMCBumpSensitivity, Z); break;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && HAS_TRINAMIC_CONFIG
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_current_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_current_screen.cpp
new file mode 100644
index 0000000..d6e36c1
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_current_screen.cpp
@@ -0,0 +1,127 @@
+/******************************
+ * stepper_current_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, HAS_TRINAMIC_CONFIG)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void StepperCurrentScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(0);
+ w.units(GET_TEXT_F(MSG_UNITS_MILLIAMP));
+ w.heading( GET_TEXT_F(MSG_TMC_CURRENT));
+ #if AXIS_IS_TMC(X)
+ w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisCurrent_mA(X) );
+ #endif
+ #if AXIS_IS_TMC(X2)
+ w.color(x_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_X2), getAxisCurrent_mA(X2) );
+ #endif
+ #if AXIS_IS_TMC(Y)
+ w.color(y_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Y), getAxisCurrent_mA(Y) );
+ #endif
+ #if AXIS_IS_TMC(Y2)
+ w.color(x_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_Y2), getAxisCurrent_mA(Y2) );
+ #endif
+ #if AXIS_IS_TMC(Z)
+ w.color(z_axis) .adjuster(10, GET_TEXT_F(MSG_AXIS_Z), getAxisCurrent_mA(Z) );
+ #endif
+ #if AXIS_IS_TMC(Z2)
+ w.color(z_axis) .adjuster(12, GET_TEXT_F(MSG_AXIS_Z2), getAxisCurrent_mA(Z2) );
+ #endif
+ #if AXIS_IS_TMC(E0)
+ w.color(e_axis) .adjuster(14, GET_TEXT_F(
+ #if EXTRUDERS == 1
+ MSG_AXIS_E
+ #else
+ MSG_AXIS_E1
+ #endif
+ ), getAxisCurrent_mA(E0) );
+ #endif
+ #if AXIS_IS_TMC(E1)
+ w.color(e_axis).adjuster(16, GET_TEXT_F(MSG_AXIS_E2), getAxisCurrent_mA(E1) );
+ #endif
+ #if AXIS_IS_TMC(E2)
+ w.color(e_axis).adjuster(18, GET_TEXT_F(MSG_AXIS_E3), getAxisCurrent_mA(E2) );
+ #endif
+ #if AXIS_IS_TMC(E3)
+ w.color(e_axis).adjuster(20, GET_TEXT_F(MSG_AXIS_E4), getAxisCurrent_mA(E3) );
+ #endif
+ w.increments();
+}
+
+bool StepperCurrentScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ #if AXIS_IS_TMC(X)
+ case 2: UI_DECREMENT(AxisCurrent_mA, X ); break;
+ case 3: UI_INCREMENT(AxisCurrent_mA, X ); break;
+ #endif
+ #if AXIS_IS_TMC(X2)
+ case 4: UI_DECREMENT(AxisCurrent_mA, X2 ); break;
+ case 5: UI_INCREMENT(AxisCurrent_mA, X2 ); break;
+ #endif
+ #if AXIS_IS_TMC(Y)
+ case 6: UI_DECREMENT(AxisCurrent_mA, Y ); break;
+ case 7: UI_INCREMENT(AxisCurrent_mA, Y ); break;
+ #endif
+ #if AXIS_IS_TMC(Y2)
+ case 8: UI_DECREMENT(AxisCurrent_mA, Y2 ); break;
+ case 9: UI_INCREMENT(AxisCurrent_mA, Y2 ); break;
+ #endif
+ #if AXIS_IS_TMC(Z)
+ case 10: UI_DECREMENT(AxisCurrent_mA, Z ); break;
+ case 11: UI_INCREMENT(AxisCurrent_mA, Z ); break;
+ #endif
+ #if AXIS_IS_TMC(Z2)
+ case 12: UI_DECREMENT(AxisCurrent_mA, Z2 ); break;
+ case 13: UI_INCREMENT(AxisCurrent_mA, Z2 ); break;
+ #endif
+ #if AXIS_IS_TMC(E0)
+ case 14: UI_DECREMENT(AxisCurrent_mA, E0); break;
+ case 15: UI_INCREMENT(AxisCurrent_mA, E0); break;
+ #endif
+ #if AXIS_IS_TMC(E1)
+ case 16: UI_DECREMENT(AxisCurrent_mA, E1); break;
+ case 17: UI_INCREMENT(AxisCurrent_mA, E1); break;
+ #endif
+ #if AXIS_IS_TMC(E2)
+ case 18: UI_DECREMENT(AxisCurrent_mA, E2); break;
+ case 19: UI_INCREMENT(AxisCurrent_mA, E2); break;
+ #endif
+ #if AXIS_IS_TMC(E3)
+ case 20: UI_DECREMENT(AxisCurrent_mA, E3); break;
+ case 21: UI_INCREMENT(AxisCurrent_mA, E3); break;
+ #endif
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/steps_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/steps_screen.cpp
new file mode 100644
index 0000000..e9bc50a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/steps_screen.cpp
@@ -0,0 +1,86 @@
+/********************
+ * steps_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void StepsScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(0);
+ w.units(GET_TEXT_F(MSG_UNITS_STEP_MM));
+ w.heading( GET_TEXT_F(MSG_STEPS_PER_MM));
+ w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisSteps_per_mm(X) );
+ w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getAxisSteps_per_mm(Y) );
+ w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getAxisSteps_per_mm(Z) );
+ #if EXTRUDERS == 1 || DISABLED(DISTINCT_E_FACTORS)
+ w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_E), getAxisSteps_per_mm(E0) );
+ #elif HAS_MULTI_EXTRUDER
+ w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_E1), getAxisSteps_per_mm(E0) );
+ w.color(e_axis) .adjuster(10, GET_TEXT_F(MSG_AXIS_E2), getAxisSteps_per_mm(E1) );
+ #if EXTRUDERS > 2
+ w.color(e_axis) .adjuster(12, GET_TEXT_F(MSG_AXIS_E3), getAxisSteps_per_mm(E2) );
+ #endif
+ #if EXTRUDERS > 3
+ w.color(e_axis) .adjuster(14, GET_TEXT_F(MSG_AXIS_E4), getAxisSteps_per_mm(E3) );
+ #endif
+ #endif
+ w.increments();
+}
+
+bool StepsScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 2: UI_DECREMENT(AxisSteps_per_mm, X); break;
+ case 3: UI_INCREMENT(AxisSteps_per_mm, X); break;
+ case 4: UI_DECREMENT(AxisSteps_per_mm, Y); break;
+ case 5: UI_INCREMENT(AxisSteps_per_mm, Y); break;
+ case 6: UI_DECREMENT(AxisSteps_per_mm, Z); break;
+ case 7: UI_INCREMENT(AxisSteps_per_mm, Z); break;
+ case 8: UI_DECREMENT(AxisSteps_per_mm, E0); break;
+ case 9: UI_INCREMENT(AxisSteps_per_mm, E0); break;
+ #if HAS_MULTI_EXTRUDER
+ case 10: UI_DECREMENT(AxisSteps_per_mm, E1); break;
+ case 11: UI_INCREMENT(AxisSteps_per_mm, E1); break;
+ #endif
+ #if EXTRUDERS > 2
+ case 12: UI_DECREMENT(AxisSteps_per_mm, E2); break;
+ case 13: UI_INCREMENT(AxisSteps_per_mm, E2); break;
+ #endif
+ #if EXTRUDERS > 3
+ case 14: UI_DECREMENT(AxisSteps_per_mm, E3); break;
+ case 15: UI_INCREMENT(AxisSteps_per_mm, E3); break;
+ #endif
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp
new file mode 100644
index 0000000..6c4aab6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp
@@ -0,0 +1,149 @@
+/**************************
+ * stress_test_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU)
+
+#include "screens.h"
+#include "screen_data.h"
+
+#define STRESS_TEST_CHANGE_INTERVAL 6000
+
+#define GRID_COLS 4
+#define GRID_ROWS 9
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+void StressTestScreen::drawDots(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
+ CommandProcessor cmd;
+ for (uint8_t i = 0; i < 100; i++) {
+ cmd.cmd(BEGIN(POINTS))
+ .cmd(POINT_SIZE(20*16))
+ .cmd(COLOR_RGB(random(0xFFFFFF)))
+ .cmd(VERTEX2F((x + random(w)) * 16,(y + random(h)) * 16));
+ }
+}
+
+bool StressTestScreen::watchDogTestNow() {
+ return screen_data.StressTest.next_watchdog_trigger &&
+ ELAPSED(millis(), screen_data.StressTest.next_watchdog_trigger);
+}
+
+void StressTestScreen::onRedraw(draw_mode_t) {
+ using namespace ExtUI;
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .font(font_medium)
+ .text(BTN_POS(1,1), BTN_SIZE(4,1), progmem_str(screen_data.StressTest.message));
+
+ drawDots(BTN_POS(1,3), BTN_SIZE(4,4));
+
+ cmd.font(font_medium).enabled(!watchDogTestNow()).colors(action_btn).tag(1).button(BTN_POS(2,8), BTN_SIZE(2,1), F("Exit"));
+}
+
+bool StressTestScreen::onTouchEnd(uint8_t tag) {
+ CommandProcessor cmd;
+ switch (tag) {
+ case 1:
+ runTestOnBootup(false);
+ GOTO_SCREEN(StatusScreen);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void StressTestScreen::runTestOnBootup(bool enable) {
+ // Use a magic value in passcode to indicate
+ // whether or not we need to re-run the test
+ // at startup.
+ LockScreen::set_hash(enable ? 0xDEAD : 0);
+ injectCommands_P(PSTR("M500"));
+}
+
+void StressTestScreen::startupCheck() {
+ if (LockScreen::get_hash() == 0xDEAD)
+ GOTO_SCREEN(StressTestScreen);
+}
+
+void StressTestScreen::onEntry() {
+ screen_data.StressTest.next_watchdog_trigger = millis() + 10000 + random(40000);
+ screen_data.StressTest.message = PSTR("Test 1: Stress testing...");
+
+ // Turn off heaters.
+ setTargetTemp_celsius(0, E0);
+ setTargetTemp_celsius(0, E1);
+ setTargetTemp_celsius(0, BED);
+
+ runTestOnBootup(true);
+}
+
+void StressTestScreen::recursiveLockup() {
+ screen_data.StressTest.message = PSTR("Test 2: Printer will restart.");
+ current_screen.onRefresh();
+ recursiveLockup();
+}
+
+void StressTestScreen::iterativeLockup() {
+ screen_data.StressTest.message = PSTR("Test 3: Printer will restart.");
+ for (;;) current_screen.onRefresh();
+}
+
+void StressTestScreen::onIdle() {
+ current_screen.onRefresh();
+ reset_menu_timeout();
+
+ if (!commandsInQueue()) {
+ if (!isPositionKnown()) {
+ injectCommands_P(G28_STR);
+ }
+ else {
+ injectCommands_P(PSTR(
+ "G0 X100 Y100 Z100 F6000\n"
+ "T0\nG4 S1"
+ TERN_(HAS_MULTI_EXTRUDER, "\nT1\nG4 S1")
+ "\nG0 X150 Y150 Z150"
+ ));
+ }
+ }
+
+ if (refresh_timer.elapsed(STRESS_TEST_CHANGE_INTERVAL)) {
+ setTargetFan_percent(random(100),FAN0);
+ }
+
+ if (watchDogTestNow()) {
+ if (random(2) % 2)
+ iterativeLockup();
+ else
+ recursiveLockup();
+ }
+
+ BaseScreen::onIdle();
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.cpp
new file mode 100644
index 0000000..c3114a3
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.cpp
@@ -0,0 +1,83 @@
+/*********************
+ * string_format.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+#define ROUND(val) uint16_t((val)+0.5)
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wno-format"
+
+/**
+ * Formats a temperature string (e.g. "100°C")
+ */
+void format_temp(char *str, float t1) {
+ sprintf_P(str, PSTR("%3d" S_FMT), ROUND(t1), GET_TEXT(MSG_UNITS_C));
+}
+
+/**
+ * Formats a temperature string for an idle heater (e.g. "100 °C / idle")
+ */
+void format_temp_and_idle(char *str, float t1) {
+ sprintf_P(str, PSTR("%3d" S_FMT " / " S_FMT), ROUND(t1), GET_TEXT(MSG_UNITS_C), GET_TEXT(MSG_IDLE));
+}
+
+/**
+ * Formats a temperature string for an active heater (e.g. "100 / 200°C")
+ */
+void format_temp_and_temp(char *str, float t1, float t2) {
+ sprintf_P(str, PSTR("%3d / %3d" S_FMT), ROUND(t1), ROUND(t2), GET_TEXT(MSG_UNITS_C));
+}
+
+/**
+ * Formats a temperature string for a material (e.g. "100°C (PLA)")
+ */
+void format_temp_and_material(char *str, float t1, const char *material) {
+ sprintf_P(str, PSTR("%3d" S_FMT " (" S_FMT ")"), ROUND(t1), GET_TEXT(MSG_UNITS_C), material);
+}
+
+/**
+ * Formats a position value (e.g. "10 mm")
+ */
+void format_position(char *str, float p, uint8_t decimals) {
+ dtostrf(p, 4 + decimals, decimals, str);
+ strcat_P(str, PSTR(" "));
+ strcat_P(str, GET_TEXT(MSG_UNITS_MM));
+}
+
+/**
+ * Formats a position vector (e.g. "10; 20; 30 mm")
+ */
+void format_position(char *str, float x, float y, float z) {
+ char num1[7], num2[7], num3[7];
+ dtostrf(x, 4, 2, num1);
+ dtostrf(y, 4, 2, num2);
+ dtostrf(z, 4, 2, num3);
+ sprintf_P(str, PSTR("%s; %s; %s " S_FMT), num1, num2, num3, GET_TEXT(MSG_UNITS_MM));
+}
+
+#pragma GCC diagnostic pop
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.h
new file mode 100644
index 0000000..545c701
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.h
@@ -0,0 +1,29 @@
+/*******************
+ * string_format.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+void format_temp(char *str, float t1);
+void format_temp_and_idle(char *str, float t1);
+void format_temp_and_temp(char *str, float t1, float t2);
+void format_temp_and_material(char *str, float t1, const char *material);
+void format_position(char *str, float p, uint8_t decimals = 1);
+void format_position(char *str, float x, float y, float z);
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/temperature_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/temperature_screen.cpp
new file mode 100644
index 0000000..bdd434b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/temperature_screen.cpp
@@ -0,0 +1,119 @@
+/*******************
+ * boot_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+void TemperatureScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ #if TOUCH_UI_LCD_TEMP_SCALING == 10
+ w.precision(1, DEFAULT_MIDRANGE)
+ #else
+ w.precision(0, getTargetTemp_celsius(E0) == 0 ? DEFAULT_HIGHEST : DEFAULT_MIDRANGE)
+ #endif
+ .color(temp).units(GET_TEXT_F(MSG_UNITS_C));
+ w.heading(GET_TEXT_F(MSG_TEMPERATURE));
+ w.button(30, GET_TEXT_F(MSG_COOLDOWN));
+ #ifndef NO_TOOLHEAD_HEATER_GCODE
+ #if ENABLED(TOUCH_UI_COCOA_PRESS)
+ w.adjuster( 2, GET_TEXT_F(MSG_NOZZLE), getTargetTemp_celsius(E0));
+ w.adjuster( 4, GET_TEXT_F(MSG_BODY), getTargetTemp_celsius(E1));
+ #if ENABLED(COCOA_PRESS_EXTRA_HEATER)
+ if (has_extra_heater())
+ w.adjuster(6, GET_TEXT_F(MSG_EXTERNAL), getTargetTemp_celsius(E2));
+ #endif
+ #elif HOTENDS == 1
+ w.adjuster( 2, GET_TEXT_F(MSG_NOZZLE), getTargetTemp_celsius(E0));
+ #else
+ w.adjuster( 2, F(LCD_STR_E0), getTargetTemp_celsius(E0));
+ w.adjuster( 4, F(LCD_STR_E1), getTargetTemp_celsius(E1));
+ #if HOTENDS > 2
+ w.adjuster( 6, F(LCD_STR_E2), getTargetTemp_celsius(E2));
+ #endif
+ #if HOTENDS > 3
+ w.adjuster( 8, F(LCD_STR_E3), getTargetTemp_celsius(E3));
+ #endif
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ w.adjuster( 20, GET_TEXT_F(MSG_BED), getTargetTemp_celsius(BED));
+ #endif
+ #if HAS_HEATED_CHAMBER
+ w.adjuster( 22, GET_TEXT_F(MSG_CHAMBER), getTargetTemp_celsius(CHAMBER));
+ #endif
+ #if HAS_FAN
+ w.color(fan_speed).units(GET_TEXT_F(MSG_UNITS_PERCENT));
+ w.adjuster( 10, GET_TEXT_F(MSG_FAN_SPEED), getTargetFan_percent(FAN0));
+ #endif
+ w.increments();
+}
+
+bool TemperatureScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 20: UI_DECREMENT(TargetTemp_celsius, BED); break;
+ case 21: UI_INCREMENT(TargetTemp_celsius, BED); break;
+ case 22: UI_DECREMENT(TargetTemp_celsius, CHAMBER); break;
+ case 23: UI_INCREMENT(TargetTemp_celsius, CHAMBER); break;
+ #ifndef NO_TOOLHEAD_HEATER_GCODE
+ case 2: UI_DECREMENT(TargetTemp_celsius, E0); break;
+ case 3: UI_INCREMENT(TargetTemp_celsius, E0); break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case 4: UI_DECREMENT(TargetTemp_celsius, E1); break;
+ case 5: UI_INCREMENT(TargetTemp_celsius, E1); break;
+ #endif
+ #if HOTENDS > 2
+ case 6: UI_DECREMENT(TargetTemp_celsius, E2); break;
+ case 7: UI_INCREMENT(TargetTemp_celsius, E2); break;
+ #endif
+ #if HOTENDS > 3
+ case 8: UI_DECREMENT(TargetTemp_celsius, E3); break;
+ case 9: UI_INCREMENT(TargetTemp_celsius, E3); break;
+ #endif
+ #if HAS_FAN
+ case 10: UI_DECREMENT(TargetFan_percent, FAN0); break;
+ case 11: UI_INCREMENT(TargetFan_percent, FAN0); break;
+ #endif
+ case 30:
+ #define _HOTEND_OFF(N) setTargetTemp_celsius(0, E##N);
+ REPEAT(HOTENDS, _HOTEND_OFF);
+ TERN_(HAS_HEATED_BED, setTargetTemp_celsius(0, BED));
+ TERN_(HAS_HEATED_CHAMBER, setTargetTemp_celsius(0, CHAMBER));
+ #if HAS_FAN
+ setTargetFan_percent(0, FAN0);
+ #endif
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_calibration_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_calibration_screen.cpp
new file mode 100644
index 0000000..b5312ad
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_calibration_screen.cpp
@@ -0,0 +1,94 @@
+/********************************
+ * touch_calibration_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_COLS 4
+#define GRID_ROWS 16
+
+#define TEXT_POS BTN_POS(1,1), BTN_SIZE(4,12)
+
+void TouchCalibrationScreen::onEntry() {
+ CommandProcessor cmd;
+
+ BaseScreen::onEntry();
+
+ if (CLCD::is_touching()) {
+ // Ask the user to release the touch before starting,
+ // as otherwise the first calibration point could
+ // be misinterpreted.
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled));
+ draw_text_box(cmd, TEXT_POS, GET_TEXT_F(MSG_TOUCH_CALIBRATION_START), OPT_CENTER, font_large);
+ cmd.cmd(DL::DL_DISPLAY)
+ .cmd(CMD_SWAP)
+ .execute();
+
+ while (CLCD::is_touching()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Waiting for touch release");
+ #endif
+ }
+ }
+
+ // Force a refresh
+ cmd.cmd(CMD_DLSTART);
+ onRedraw(FOREGROUND);
+ cmd.cmd(DL::DL_DISPLAY);
+ cmd.execute();
+}
+
+void TouchCalibrationScreen::onRefresh() {
+ // Don't do the regular refresh, as this would
+ // cause the calibration be restarted on every
+ // touch.
+}
+
+void TouchCalibrationScreen::onRedraw(draw_mode_t) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled));
+
+ draw_text_box(cmd, TEXT_POS, GET_TEXT_F(MSG_TOUCH_CALIBRATION_PROMPT), OPT_CENTER, font_large);
+ cmd.cmd(CMD_CALIBRATE);
+}
+
+void TouchCalibrationScreen::onIdle() {
+ if (!CLCD::is_touching() && !CommandProcessor::is_processing()) {
+ GOTO_PREVIOUS();
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Calibration routine finished");
+ #endif
+ }
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_registers_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_registers_screen.cpp
new file mode 100644
index 0000000..3739413
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_registers_screen.cpp
@@ -0,0 +1,86 @@
+/******************************
+ * touch_registers_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void TouchRegistersScreen::onRedraw(draw_mode_t) {
+ const uint32_t T_Transform_A = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_A);
+ const uint32_t T_Transform_B = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_B);
+ const uint32_t T_Transform_C = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_C);
+ const uint32_t T_Transform_D = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_D);
+ const uint32_t T_Transform_E = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_E);
+ const uint32_t T_Transform_F = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_F);
+ char b[20];
+
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+
+ #define GRID_ROWS 7
+ #define GRID_COLS 2
+ cmd.tag(0)
+ .font(font_xsmall)
+ .fgcolor(transformA) .button(BTN_POS(1,1), BTN_SIZE(1,1), F("TOUCH_XFORM_A"))
+ .fgcolor(transformB) .button(BTN_POS(1,2), BTN_SIZE(1,1), F("TOUCH_XFORM_B"))
+ .fgcolor(transformC) .button(BTN_POS(1,3), BTN_SIZE(1,1), F("TOUCH_XFORM_C"))
+ .fgcolor(transformD) .button(BTN_POS(1,4), BTN_SIZE(1,1), F("TOUCH_XFORM_D"))
+ .fgcolor(transformE) .button(BTN_POS(1,5), BTN_SIZE(1,1), F("TOUCH_XFORM_E"))
+ .fgcolor(transformF) .button(BTN_POS(1,6), BTN_SIZE(1,1), F("TOUCH_XFORM_F"))
+
+ .fgcolor(transformVal).button(BTN_POS(2,1), BTN_SIZE(1,1), F(""), OPT_FLAT)
+ .fgcolor(transformVal).button(BTN_POS(2,2), BTN_SIZE(1,1), F(""), OPT_FLAT)
+ .fgcolor(transformVal).button(BTN_POS(2,3), BTN_SIZE(1,1), F(""), OPT_FLAT)
+ .fgcolor(transformVal).button(BTN_POS(2,4), BTN_SIZE(1,1), F(""), OPT_FLAT)
+ .fgcolor(transformVal).button(BTN_POS(2,5), BTN_SIZE(1,1), F(""), OPT_FLAT)
+ .fgcolor(transformVal).button(BTN_POS(2,6), BTN_SIZE(1,1), F(""), OPT_FLAT);
+
+ sprintf_P(b, PSTR("0x%08lX"), T_Transform_A); cmd.text( BTN_POS(2,1), BTN_SIZE(1,1), b);
+ sprintf_P(b, PSTR("0x%08lX"), T_Transform_B); cmd.text( BTN_POS(2,2), BTN_SIZE(1,1), b);
+ sprintf_P(b, PSTR("0x%08lX"), T_Transform_C); cmd.text( BTN_POS(2,3), BTN_SIZE(1,1), b);
+ sprintf_P(b, PSTR("0x%08lX"), T_Transform_D); cmd.text( BTN_POS(2,4), BTN_SIZE(1,1), b);
+ sprintf_P(b, PSTR("0x%08lX"), T_Transform_E); cmd.text( BTN_POS(2,5), BTN_SIZE(1,1), b);
+ sprintf_P(b, PSTR("0x%08lX"), T_Transform_F); cmd.text( BTN_POS(2,6), BTN_SIZE(1,1), b);
+
+ cmd.colors(action_btn).font(font_medium)
+ .tag(1).button(BTN_POS(2,7), BTN_SIZE(1,1), F("Back"));
+ #undef GRID_COLS
+ #undef GRID_ROWS
+ }
+
+ bool TouchRegistersScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/tune_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/tune_menu.cpp
new file mode 100644
index 0000000..5a29010
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/tune_menu.cpp
@@ -0,0 +1,156 @@
+/*******************
+ * tune_menu.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && DISABLED(TOUCH_UI_LULZBOT_BIO)
+
+#include "screens.h"
+
+#include "../../../../../feature/host_actions.h"
+
+using namespace FTDI;
+using namespace Theme;
+
+void TuneMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_ROWS 9
+ #define GRID_COLS 2
+ #define TEMPERATURE_POS BTN_POS(1,1), BTN_SIZE(2,1)
+ #define FIL_CHANGE_POS BTN_POS(1,2), BTN_SIZE(2,1)
+ #define FILAMENT_POS BTN_POS(1,3), BTN_SIZE(2,1)
+ #define NUDGE_NOZ_POS BTN_POS(1,4), BTN_SIZE(2,1)
+ #define SPEED_POS BTN_POS(1,5), BTN_SIZE(2,1)
+ #define PAUSE_POS BTN_POS(1,6), BTN_SIZE(2,1)
+ #define STOP_POS BTN_POS(1,7), BTN_SIZE(2,1)
+ #define CASE_LIGHT_POS BTN_POS(1,8), BTN_SIZE(2,1)
+ #define ADVANCED_SETTINGS_POS BTN_POS(1,9), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(2,9), BTN_SIZE(1,1)
+ #else
+ #define GRID_ROWS 5
+ #define GRID_COLS 2
+ #define TEMPERATURE_POS BTN_POS(1,1), BTN_SIZE(1,1)
+ #define NUDGE_NOZ_POS BTN_POS(2,1), BTN_SIZE(1,1)
+ #define FIL_CHANGE_POS BTN_POS(1,2), BTN_SIZE(1,1)
+ #define SPEED_POS BTN_POS(2,2), BTN_SIZE(1,1)
+ #define PAUSE_POS BTN_POS(1,3), BTN_SIZE(1,1)
+ #define STOP_POS BTN_POS(2,3), BTN_SIZE(1,1)
+ #define FILAMENT_POS BTN_POS(1,4), BTN_SIZE(1,1)
+ #define CASE_LIGHT_POS BTN_POS(2,4), BTN_SIZE(1,1)
+ #define ADVANCED_SETTINGS_POS BTN_POS(1,5), BTN_SIZE(1,1)
+ #define BACK_POS BTN_POS(2,5), BTN_SIZE(2,1)
+ #endif
+
+ if (what & FOREGROUND) {
+ const bool sdOrHostPrinting = ExtUI::isPrinting();
+ const bool sdOrHostPaused = ExtUI::isPrintingPaused();
+
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .tag(2).button(TEMPERATURE_POS, GET_TEXT_F(MSG_TEMPERATURE))
+ .enabled(!sdOrHostPrinting || sdOrHostPaused)
+ .tag(3).button(FIL_CHANGE_POS, GET_TEXT_F(MSG_FILAMENTCHANGE))
+ .enabled(EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR))
+ .tag(9).button(FILAMENT_POS, GET_TEXT_F(MSG_FILAMENT))
+ .enabled(BOTH(HAS_LEVELING, HAS_BED_PROBE) || ENABLED(BABYSTEPPING))
+ .tag(4).button(NUDGE_NOZ_POS, GET_TEXT_F(TERN(BABYSTEPPING, MSG_NUDGE_NOZZLE, MSG_ZPROBE_ZOFFSET)))
+ .tag(5).button(SPEED_POS, GET_TEXT_F(MSG_PRINT_SPEED))
+ .enabled(sdOrHostPrinting)
+ .tag(sdOrHostPaused ? 7 : 6)
+ .button(PAUSE_POS, sdOrHostPaused ? GET_TEXT_F(MSG_RESUME_PRINT) : GET_TEXT_F(MSG_PAUSE_PRINT))
+ .enabled(sdOrHostPrinting)
+ .tag(8).button(STOP_POS, GET_TEXT_F(MSG_STOP_PRINT))
+ .enabled(ENABLED(CASE_LIGHT_ENABLE))
+ .tag(10).button(CASE_LIGHT_POS, GET_TEXT_F(MSG_CASE_LIGHT))
+ .tag(11).button(ADVANCED_SETTINGS_POS, GET_TEXT_F(MSG_ADVANCED_SETTINGS))
+ .tag(1).colors(action_btn)
+ .button(BACK_POS, GET_TEXT_F(MSG_BACK));
+ }
+ #undef GRID_COLS
+ #undef GRID_ROWS
+}
+
+bool TuneMenu::onTouchEnd(uint8_t tag) {
+ using namespace Theme;
+ using namespace ExtUI;
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2: GOTO_SCREEN(TemperatureScreen); break;
+ case 3: GOTO_SCREEN(ChangeFilamentScreen); break;
+ case 4:
+ #if ENABLED(BABYSTEPPING)
+ GOTO_SCREEN(NudgeNozzleScreen);
+ #elif BOTH(HAS_LEVELING, HAS_BED_PROBE)
+ GOTO_SCREEN(ZOffsetScreen);
+ #endif
+ break;
+ case 5: GOTO_SCREEN(FeedratePercentScreen); break;
+ case 6: pausePrint(); break;
+ case 7: resumePrint(); break;
+ case 8:
+ GOTO_SCREEN(ConfirmAbortPrintDialogBox);
+ current_screen.forget();
+ PUSH_SCREEN(StatusScreen);
+ break;
+ #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)
+ case 9: GOTO_SCREEN(FilamentMenu); break;
+ #endif
+ #if ENABLED(CASE_LIGHT_ENABLE)
+ case 10: GOTO_SCREEN(CaseLightScreen); break;
+ #endif
+ case 11: GOTO_SCREEN(AdvancedSettingsMenu); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void TuneMenu::pausePrint() {
+ sound.play(twinkle, PLAY_ASYNCHRONOUS);
+ if (ExtUI::isPrintingFromMedia())
+ ExtUI::pausePrint();
+ #ifdef ACTION_ON_PAUSE
+ else host_action_pause();
+ #endif
+ GOTO_SCREEN(StatusScreen);
+}
+
+void TuneMenu::resumePrint() {
+ sound.play(twinkle, PLAY_ASYNCHRONOUS);
+ if (ExtUI::awaitingUserConfirm())
+ ExtUI::setUserConfirmed();
+ else if (ExtUI::isPrintingFromMedia())
+ ExtUI::resumePrint();
+ #ifdef ACTION_ON_RESUME
+ else host_action_resume();
+ #endif
+ GOTO_SCREEN(StatusScreen);
+}
+
+#endif // TOUCH_UI_FTDI_EVE && !TOUCH_UI_LULZBOT_BIO
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/widget_demo_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/widget_demo_screen.cpp
new file mode 100644
index 0000000..9688710
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/widget_demo_screen.cpp
@@ -0,0 +1,158 @@
+/**************************
+ * widget_demo_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+uint16_t slider_val;
+bool show_grid;
+
+void WidgetsScreen::onEntry() {
+ BaseScreen::onEntry();
+ CLCD::turn_on_backlight();
+ SoundPlayer::set_volume(255);
+}
+
+void WidgetsScreen::onRedraw(draw_mode_t) {
+ using namespace ExtUI;
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+
+ const uint16_t hrs = (slider_val*12/0xFFFFU);
+ const uint16_t m = (slider_val*12*60/0xFFFFU)%60;
+ const uint16_t s = (slider_val*12*60*60/0xFFFFU)%60;
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ #define GRID_COLS 3
+ #define GRID_ROWS 8
+ cmd.font(font_large)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .text (BTN_POS(1,1), BTN_SIZE(3,1), F("Sample Widgets"))
+ .tag(0).text (BTN_POS(2,6), BTN_SIZE(1,1), F("Show grid:"))
+ .colors(ui_toggle)
+ .tag(2).dial (BTN_POS(1,2), BTN_SIZE(1,2), slider_val)
+ .tag(0).clock (BTN_POS(1,4), BTN_SIZE(1,2), hrs, m, s, 0)
+ .gauge (BTN_POS(1,6), BTN_SIZE(1,2), 5, 4, slider_val, 0xFFFFU)
+ .font(font_medium)
+ .colors(ui_slider)
+ .tag(4).slider (BTN_POS(2,3), BTN_SIZE(2,1), slider_val, 0xFFFFU)
+ .tag(5).progress (BTN_POS(2,4), BTN_SIZE(2,1), slider_val, 0xFFFFU)
+ .tag(6).scrollbar (BTN_POS(2,5), BTN_SIZE(2,1), slider_val, 1000, 0xFFFFU)
+ .font(font_small)
+ .colors(ui_toggle)
+ .tag(7).toggle (BTN_POS(3,6), BTN_SIZE(1,1), F("no\xFFyes"), show_grid)
+ .colors(normal_btn)
+ .font(font_medium)
+ .tag(1)
+ .button (BTN_POS(2, 8), BTN_SIZE(1,1), F("1"))
+ .button (BTN_POS(3, 8), BTN_SIZE(1,1), F("2"))
+ .colors(action_btn)
+ .button (BTN_POS(1, 8), BTN_SIZE(1,1), F("Back"));
+ #else
+ #define GRID_COLS 4
+ #define GRID_ROWS 8
+
+ cmd.font(font_large)
+ .text (BTN_POS(1,1), BTN_SIZE(4,1), F("Sample Widgets"))
+ .tag(0).text (BTN_POS(3,6), BTN_SIZE(1,1), F("Show grid:"))
+ .colors(ui_toggle)
+ .tag(2).dial (BTN_POS(1,2), BTN_SIZE(1,3), slider_val)
+ .tag(3).dial (BTN_POS(1,5), BTN_SIZE(1,3), slider_val)
+ .tag(0).clock (BTN_POS(2,2), BTN_SIZE(1,3), hrs, m, s, 0)
+ .gauge (BTN_POS(2,5), BTN_SIZE(1,3), 5, 4, slider_val, 0xFFFFU)
+ .font(font_medium)
+ .colors(ui_slider)
+ .tag(4).slider (BTN_POS(3,3), BTN_SIZE(2,1), slider_val, 0xFFFFU)
+ .tag(5).progress (BTN_POS(3,4), BTN_SIZE(2,1), slider_val, 0xFFFFU)
+ .tag(6).scrollbar (BTN_POS(3,5), BTN_SIZE(2,1), slider_val, 1000, 0xFFFFU)
+ .font(font_small)
+ .colors(ui_toggle)
+ .tag(7).toggle (BTN_POS(4,6), BTN_SIZE(1,1), F("no\xFFyes"), show_grid)
+ .colors(normal_btn)
+ .font(font_medium)
+ .tag(1).button (BTN_POS(3, 8), BTN_SIZE(1,1), F("1"))
+ .button (BTN_POS(4, 8), BTN_SIZE(1,1), F("2"))
+ .colors(action_btn)
+ .button (BTN_POS(1, 8), BTN_SIZE(2,1), F("Back"));
+ #endif
+
+ cmd.cmd(COLOR_RGB(bg_text_enabled));
+ if (show_grid) DRAW_LAYOUT_GRID
+}
+
+bool WidgetsScreen::onTouchStart(uint8_t tag) {
+ CommandProcessor cmd;
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ case 2: cmd.track_circular (BTN_POS(1,2), BTN_SIZE(1,2), 2).execute(); break;
+ case 4: cmd.track_linear (BTN_POS(2,3), BTN_SIZE(2,1), 4).execute(); break;
+ case 5: cmd.track_linear (BTN_POS(2,4), BTN_SIZE(2,1), 5).execute(); break;
+ case 6: cmd.track_linear (BTN_POS(2,5), BTN_SIZE(2,1), 6).execute(); break;
+ #else
+ case 2: cmd.track_circular (BTN_POS(1,2), BTN_SIZE(1,3), 2).execute(); break;
+ case 3: cmd.track_circular (BTN_POS(1,5), BTN_SIZE(1,3), 3).execute(); break;
+ case 4: cmd.track_linear (BTN_POS(3,3), BTN_SIZE(2,1), 4).execute(); break;
+ case 5: cmd.track_linear (BTN_POS(3,4), BTN_SIZE(2,1), 5).execute(); break;
+ case 6: cmd.track_linear (BTN_POS(3,5), BTN_SIZE(2,1), 6).execute(); break;
+ #endif
+ case 7: show_grid = !show_grid; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+void WidgetsScreen::onIdle() {
+ if (refresh_timer.elapsed(TOUCH_UPDATE_INTERVAL)) {
+ refresh_timer.start();
+
+ uint16_t value;
+ CommandProcessor cmd;
+ switch (cmd.track_tag(value)) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ slider_val = value; break;
+ default:
+ return;
+ }
+ onRefresh();
+ }
+ BaseScreen::onIdle();
+}
+
+#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_DEVELOPER_MENU
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/z_offset_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/z_offset_screen.cpp
new file mode 100644
index 0000000..0acfbb0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/z_offset_screen.cpp
@@ -0,0 +1,54 @@
+/***********************
+ * z_offset_screen.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE) && BOTH(HAS_LEVELING, HAS_BED_PROBE)
+
+#include "screens.h"
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+void ZOffsetScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(2, BaseNumericAdjustmentScreen::DEFAULT_MIDRANGE).units(GET_TEXT_F(MSG_UNITS_MM));
+
+ w.heading( GET_TEXT_F(MSG_ZPROBE_ZOFFSET));
+ w.color(z_axis).adjuster(4, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), getZOffset_mm());
+ w.increments();
+}
+
+bool ZOffsetScreen::onTouchHeld(uint8_t tag) {
+ const float increment = getIncrement();
+ switch (tag) {
+ case 4: UI_DECREMENT(ZOffset_mm); break;
+ case 5: UI_INCREMENT(ZOffset_mm); break;
+ default:
+ return false;
+ }
+ SaveSettingsDialogBox::settingsChanged();
+ return true;
+}
+
+#endif // TOUCH_UI_FTDI_EVE && HAS_BED_PROBE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bitmaps.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bitmaps.h
new file mode 100644
index 0000000..8c0366e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bitmaps.h
@@ -0,0 +1,183 @@
+/*************
+ * bitmaps.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+namespace Theme {
+ using namespace FTDI;
+
+ constexpr PROGMEM bitmap_info_t Extruder_Icon_Info = {
+ .format = L1,
+ .linestride = 3,
+ .filter = BILINEAR,
+ .wrapx = BORDER,
+ .wrapy = BORDER,
+ .RAMG_offset = 8000,
+ .width = 24,
+ .height = 23,
+ };
+
+ constexpr PROGMEM unsigned char Extruder_Icon[] = {
+ 0x3F, 0xFF, 0xFC,
+ 0x7F, 0xFF, 0xFE,
+ 0xC0, 0x00, 0x03,
+ 0xC0, 0x00, 0x03,
+ 0xC0, 0x00, 0x03,
+ 0xC0, 0x00, 0x03,
+ 0x7F, 0xFF, 0xFE,
+ 0x3F, 0xFF, 0xFC,
+ 0x3F, 0xFF, 0xFC,
+ 0x7F, 0xFF, 0xFE,
+ 0xC0, 0x00, 0x03,
+ 0xC0, 0x00, 0x03,
+ 0xC0, 0x00, 0x03,
+ 0xC0, 0x00, 0x03,
+ 0x7F, 0xFF, 0xFE,
+ 0x7F, 0xFF, 0xFE,
+ 0x07, 0xFF, 0xE0,
+ 0x03, 0xFF, 0xC0,
+ 0x01, 0x81, 0x80,
+ 0x00, 0xC3, 0x00,
+ 0x00, 0x66, 0x00,
+ 0x00, 0x3C, 0x00,
+ 0x00, 0x3C, 0x00
+ };
+
+ constexpr PROGMEM bitmap_info_t Bed_Heat_Icon_Info = {
+ .format = L1,
+ .linestride = 4,
+ .filter = BILINEAR,
+ .wrapx = BORDER,
+ .wrapy = BORDER,
+ .RAMG_offset = 8100,
+ .width = 32,
+ .height = 23,
+ };
+
+ constexpr PROGMEM unsigned char Bed_Heat_Icon[] = {
+ 0x01, 0x81, 0x81, 0x80,
+ 0x01, 0x81, 0x81, 0x80,
+ 0x00, 0xC0, 0xC0, 0xC0,
+ 0x00, 0xC0, 0xC0, 0xC0,
+ 0x00, 0x60, 0x60, 0x60,
+ 0x00, 0x60, 0x60, 0x60,
+ 0x00, 0xC0, 0xC0, 0xC0,
+ 0x00, 0xC0, 0xC0, 0xC0,
+ 0x01, 0x81, 0x81, 0x80,
+ 0x01, 0x81, 0x81, 0x80,
+ 0x03, 0x03, 0x03, 0x00,
+ 0x03, 0x03, 0x03, 0x00,
+ 0x06, 0x06, 0x06, 0x00,
+ 0x06, 0x06, 0x06, 0x00,
+ 0x03, 0x03, 0x03, 0x00,
+ 0x03, 0x03, 0x03, 0x00,
+ 0x01, 0x81, 0x81, 0x80,
+ 0x01, 0x81, 0x81, 0x80,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC0, 0x00, 0x00, 0x03,
+ 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+ constexpr PROGMEM bitmap_info_t Fan_Icon_Info = {
+ .format = L1,
+ .linestride = 4,
+ .filter = BILINEAR,
+ .wrapx = BORDER,
+ .wrapy = BORDER,
+ .RAMG_offset = 8300,
+ .width = 32,
+ .height = 32,
+ };
+
+ constexpr PROGMEM unsigned char Fan_Icon[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF8, 0x00, 0x00, 0x1F,
+ 0xF0, 0x03, 0xF8, 0x0F,
+ 0xE0, 0x07, 0xF0, 0x07,
+ 0xC0, 0x0F, 0xE0, 0x03,
+ 0xC0, 0x1F, 0xE0, 0x03,
+ 0xC0, 0x1F, 0xE0, 0x03,
+ 0xC0, 0x0F, 0xE0, 0x03,
+ 0xC0, 0x07, 0xE0, 0x03,
+ 0xC0, 0x03, 0xC0, 0x03,
+ 0xD0, 0x00, 0x00, 0xC3,
+ 0xD8, 0x03, 0xC1, 0xE3,
+ 0xDF, 0xC7, 0xE3, 0xF3,
+ 0xDF, 0xEF, 0xF7, 0xFB,
+ 0xDF, 0xEF, 0xF7, 0xFB,
+ 0xDF, 0xEF, 0xF7, 0xFB,
+ 0xDF, 0xEF, 0xF7, 0xFB,
+ 0xCF, 0xC7, 0xE3, 0xFB,
+ 0xC7, 0x83, 0xC0, 0x1B,
+ 0xC3, 0x00, 0x00, 0x0B,
+ 0xC0, 0x03, 0xC0, 0x03,
+ 0xC0, 0x07, 0xE0, 0x03,
+ 0xC0, 0x07, 0xF0, 0x03,
+ 0xC0, 0x07, 0xF8, 0x03,
+ 0xC0, 0x07, 0xF8, 0x03,
+ 0xC0, 0x07, 0xF0, 0x03,
+ 0xE0, 0x0F, 0xE0, 0x07,
+ 0xF0, 0x1F, 0xC0, 0x0F,
+ 0xF8, 0x00, 0x00, 0x1F,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+ constexpr PROGMEM bitmap_info_t TD_Icon_Info = {
+ .format = L1,
+ .linestride = 7,
+ .filter = BILINEAR,
+ .wrapx = BORDER,
+ .wrapy = BORDER,
+ .RAMG_offset = 9000,
+ .width = 50,
+ .height = 20,
+ };
+
+ constexpr PROGMEM unsigned char TD_Icon[] = {
+ 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, // Thumb Drive Widget
+ 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x80,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x80,
+ 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00
+ };
+
+ constexpr PROGMEM uint32_t UTF8_FONT_OFFSET = 10000;
+}; // namespace Theme
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bootscreen_logo_portrait.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bootscreen_logo_portrait.h
new file mode 100644
index 0000000..5d97358
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bootscreen_logo_portrait.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.pl"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+
+constexpr float x_min = 0.000000, x_max = 272.000000,
+ y_min = 0.000000, y_max = 480.000000;
+
+const PROGMEM uint16_t logo_green[] = {0x8048, 0x46D9, 0x27BC, 0x9DBA, 0xD8D3, 0x9DBA};
+const PROGMEM uint16_t logo_mark[] = {0xDB9F, 0xAC0C, 0xDA6F, 0xAC2D, 0xD970, 0xAC91, 0xD8C0, 0xAD23, 0xD885, 0xADCF, 0xD8C0, 0xAE7A, 0xD970, 0xAF0C, 0xDA6F, 0xAF6F, 0xDB9F, 0xAF8F, 0xDCCE, 0xAF6F, 0xDDD0, 0xAF0C, 0xDE7D, 0xAE7B, 0xDEB9, 0xADCF, 0xDE7D, 0xAD22, 0xDDD0, 0xAC91, 0xDCCE, 0xAC2D, 0xFFFF, 0xDB9F, 0xABC3, 0xDCFE, 0xABEA, 0xDE28, 0xAC5E, 0xDEF1, 0xAD06, 0xDF36, 0xADCF, 0xDEF1, 0xAE95, 0xDE28, 0xAF3E, 0xDCFE, 0xAFB1, 0xDB9F, 0xAFD8, 0xDA3F, 0xAFB1, 0xD916, 0xAF3E, 0xD849, 0xAE95, 0xD808, 0xADCF, 0xD849, 0xAD06, 0xD916, 0xAC5E, 0xDA3F, 0xABEA, 0xFFFF, 0xDB7D, 0xACE6, 0xDAE4, 0xACE6, 0xDAE4, 0xADA9, 0xDB7D, 0xADA9, 0xDC3B, 0xAD94, 0xDC71, 0xAD48, 0xDC3B, 0xACFD, 0xFFFF, 0xDB85, 0xAC9E, 0xDCCB, 0xACC8, 0xDD37, 0xAD47, 0xDCF6, 0xADAC, 0xDC3E, 0xADDE, 0xDC85, 0xADFF, 0xDCE8, 0xAE4E, 0xDD92, 0xAEEA, 0xDCBD, 0xAEEA, 0xDC1E, 0xAE58, 0xDBA7, 0xAE03, 0xDB36, 0xADEF, 0xDAE4, 0xADEF, 0xDAE4, 0xAEEA, 0xDA26, 0xAEEA, 0xDA26, 0xAC9E};
+const PROGMEM uint16_t logo_type[] = {0xD8D5, 0xA520, 0xD8A5, 0xA563, 0xD82E, 0xA57F, 0xD348, 0xA57F, 0xD2D1, 0xA598, 0xD2A0, 0xA5D9, 0xD2A0, 0xAF7A, 0xD274, 0xAFBE, 0xD202, 0xAFDA, 0xCD37, 0xAFDA, 0xCCBF, 0xAFBE, 0xCC8F, 0xAF7A, 0xCC8F, 0xA5D9, 0xCC63, 0xA598, 0xCBF1, 0xA57F, 0xC70B, 0xA57F, 0xC694, 0xA563, 0xC664, 0xA520, 0xC664, 0xA28C, 0xC70B, 0xA22C, 0xD82E, 0xA22C, 0xD8A5, 0xA248, 0xD8D5, 0xA28C, 0xFFFF, 0xB138, 0xAC8C, 0xB952, 0xAC8C, 0xB952, 0xA57F, 0xB138, 0xA57F, 0xFFFF, 0xBF27, 0xA421, 0xBF57, 0xA476, 0xBF6D, 0xA4D0, 0xBF6D, 0xAD36, 0xBF57, 0xAD90, 0xBF27, 0xADE6, 0xBBFA, 0xAFB2, 0xBB60, 0xAFCF, 0xBABD, 0xAFDA, 0xAFCE, 0xAFDA, 0xAF30, 0xAFCF, 0xAE9A, 0xAFB2, 0xAB6E, 0xADE6, 0xAB39, 0xAD90, 0xAB28, 0xAD36, 0xAB28, 0xA4D0, 0xAB39, 0xA476, 0xAB6E, 0xA421, 0xAE9A, 0xA255, 0xAF30, 0xA239, 0xAFCE, 0xA22C, 0xBABD, 0xA22C, 0xBB60, 0xA239, 0xBBFA, 0xA255, 0xFFFF, 0x93A4, 0xACDC, 0x9CEA, 0xACDC, 0x9CEA, 0xAA34, 0x93A4, 0xAA34, 0x93A4, 0xACDC, 0xFFFF, 0x93A4, 0xA796, 0x9CEA, 0xA796, 0x9CEA, 0xA525, 0x93A4, 0xA525, 0xFFFF, 0xA227, 0xA421, 0xA258, 0xA478, 0xA26E, 0xA4D5, 0xA26E, 0xA700, 0xA24F, 0xA757, 0xA204, 0xA7A5, 0xA089, 0xA8B8, 0xA061, 0xA903, 0xA092, 0xA949, 0xA1FC, 0xAA43, 0xA24B, 0xAA91, 0xA26E, 0xAAE8, 0xA26E, 0xAD36, 0xA258, 0xAD90, 0xA227, 0xADE6, 0x9EFC, 0xAFB2, 0x9E61, 0xAFCF, 0x9DBE, 0xAFDA, 0x8ED0, 0xAFDA, 0x8E28, 0xAF7A, 0x8E28, 0xA28C, 0x8E59, 0xA248, 0x8ED0, 0xA22C, 0x9DBE, 0xA22C, 0x9E61, 0xA239, 0x9EFC, 0xA255, 0xFFFF, 0x853C, 0xA502, 0x8517, 0xA557, 0x84C9, 0xA5A2, 0x7994, 0xACC8, 0x8494, 0xACC8, 0x850A, 0xACE4, 0x853C, 0xAD27, 0x853C, 0xAF7A, 0x850A, 0xAFBE, 0x8494, 0xAFDA, 0x7371, 0xAFDA, 0x72C9, 0xAF7A, 0x72C9, 0xAD09, 0x72E8, 0xACB2, 0x7333, 0xAC64, 0x7EA5, 0xA53E, 0x73A6, 0xA53E, 0x732F, 0xA522, 0x72FE, 0xA4DF, 0x72FE, 0xA28C, 0x732F, 0xA248, 0x73A6, 0xA22C, 0x8494, 0xA22C, 0x850A, 0xA248, 0x853C, 0xA28C, 0xFFFF, 0x6B68, 0xAC87, 0x6BDB, 0xACA3, 0x6C07, 0xACE6, 0x6C07, 0xAF7A, 0x6BDB, 0xAFBE, 0x6B68, 0xAFDA, 0x5C84, 0xAFDA, 0x5BDC, 0xAF7A, 0x5BDC, 0xA28C, 0x5C84, 0xA22C, 0x6146, 0xA22C, 0x61EE, 0xA28C, 0x61EE, 0xAC2D, 0x621E, 0xAC6E, 0x6295, 0xAC87, 0xFFFF, 0x52C6, 0xA248, 0x52F7, 0xA28C, 0x52F7, 0xAD45, 0x52EE, 0xAD45, 0x52DC, 0xAD9B, 0x52B1, 0xADE6, 0x4F85, 0xAFB2, 0x4EEA, 0xAFCF, 0x4E47, 0xAFDA, 0x4359, 0xAFDA, 0x42BA, 0xAFCF, 0x4224, 0xAFB2, 0x3EF8, 0xADE6, 0x3EC3, 0xAD90, 0x3EB2, 0xAD36, 0x3EB2, 0xA28C, 0x3EE2, 0xA248, 0x3F5A, 0xA22C, 0x441B, 0xA22C, 0x4493, 0xA248, 0x44C3, 0xA28C, 0x44C3, 0xAC2D, 0x44F4, 0xAC71, 0x456B, 0xAC8C, 0x4C3E, 0xAC8C, 0x4CB1, 0xAC71, 0x4CDD, 0xAC2D, 0x4CDD, 0xA28C, 0x4D0D, 0xA248, 0x4D85, 0xA22C, 0x524F, 0xA22C, 0xFFFF, 0x3748, 0xAC87, 0x37BB, 0xACA3, 0x37E7, 0xACE6, 0x37E7, 0xAF7A, 0x37BB, 0xAFBE, 0x3748, 0xAFDA, 0x2864, 0xAFDA, 0x27BC, 0xAF7A, 0x27BC, 0xA28C, 0x2864, 0xA22C, 0x2D26, 0xA22C, 0x2DCD, 0xA28C, 0x2DCD, 0xAC2D, 0x2DFE, 0xAC6E, 0x2E75, 0xAC87};
+const PROGMEM uint16_t logo_black[] = {0x8048, 0x527A, 0x8ADE, 0x5CDE, 0x75B2, 0x5CDE, 0xFFFF, 0x8048, 0x4FF6, 0x71D9, 0x5E20, 0x8EB8, 0x5E20, 0x8048, 0x4FF6, 0xFFFF, 0x4436, 0x8D8E, 0x4ECC, 0x97F2, 0x39A0, 0x97F2, 0xFFFF, 0x4436, 0x8B0A, 0x35C8, 0x9934, 0x52A5, 0x9934, 0xFFFF, 0xBC3D, 0x8D8E, 0xC6D4, 0x97F2, 0xB1A7, 0x97F2, 0xFFFF, 0xBC3D, 0x8B0A, 0xADCE, 0x9934, 0xCAAC, 0x9934, 0xFFFF, 0x8045, 0x6778, 0x7F6D, 0x67A7, 0x7E9D, 0x689F, 0x7D49, 0x69EA, 0x7B41, 0x6A81, 0x7908, 0x6A3A, 0x7726, 0x692C, 0x75EA, 0x685A, 0x7505, 0x684C, 0x744A, 0x6899, 0x73F5, 0x69A8, 0x7345, 0x6B1A, 0x7193, 0x6BF8, 0x6F4D, 0x6C08, 0x6CFA, 0x6B45, 0x6B61, 0x6AA3, 0x6A7D, 0x6AB7, 0x69EB, 0x6B1D, 0x6A1D, 0x6C34, 0x6A22, 0x6DB8, 0x68E5, 0x6ECD, 0x66B9, 0x6F33, 0x6417, 0x6EC5, 0x6239, 0x6E5C, 0x6165, 0x6E91, 0x6108, 0x6F09, 0x61C1, 0x7018, 0x6282, 0x7196, 0x61CF, 0x72D1, 0x5FE5, 0x7384, 0x5D38, 0x7380, 0x5B4B, 0x7365, 0x5A97, 0x73B7, 0x5A74, 0x7438, 0x5B90, 0x7520, 0x5CE8, 0x7671, 0x5CCB, 0x77BB, 0x5B43, 0x78B0, 0x58B6, 0x7914, 0x56D7, 0x7944, 0x564F, 0x79AD, 0x5667, 0x7A2F, 0x57DA, 0x7AE3, 0x59B7, 0x7BF3, 0x5A31, 0x7D37, 0x5927, 0x7E5D, 0x56E0, 0x7F1E, 0x5529, 0x7F93, 0x54D7, 0x800D, 0x5529, 0x8087, 0x56E0, 0x80FD, 0x5926, 0x81BE, 0x5A30, 0x82E5, 0x59B5, 0x8428, 0x57D8, 0x8538, 0x5664, 0x85EB, 0x564C, 0x866D, 0x56D4, 0x86D7, 0x58B2, 0x8708, 0x5B3F, 0x876B, 0x5CC6, 0x8860, 0x5CE3, 0x89AA, 0x5B8B, 0x8AFC, 0x5A6D, 0x8BE3, 0x5A91, 0x8C65, 0x5B44, 0x8CB7, 0x5D32, 0x8C9C, 0x5FDE, 0x8C98, 0x61C7, 0x8D4B, 0x627A, 0x8E87, 0x61B9, 0x9005, 0x60FF, 0x9114, 0x615C, 0x918B, 0x622F, 0x91C0, 0x640E, 0x9158, 0x66B0, 0x90EA, 0x68DC, 0x9150, 0x6A18, 0x9266, 0x6A12, 0x93E9, 0x69E0, 0x9501, 0x6A72, 0x9567, 0x6B56, 0x957B, 0x6CEE, 0x94D9, 0x6F43, 0x9417, 0x7188, 0x9428, 0x7339, 0x9506, 0x73E9, 0x9678, 0x743E, 0x9787, 0x74F8, 0x97D4, 0x75DD, 0x97C6, 0x771A, 0x96F4, 0x78FB, 0x95E6, 0x7B35, 0x95A1, 0x7D3D, 0x9637, 0x7E91, 0x9782, 0x7F60, 0x987A, 0x8038, 0x98AA, 0x810F, 0x987B, 0x81DF, 0x9782, 0x8333, 0x9638, 0x853B, 0x95A1, 0x8775, 0x95E7, 0x8956, 0x96F5, 0x8A92, 0x97C8, 0x8B78, 0x97D6, 0x8C32, 0x9789, 0x8C88, 0x967A, 0x8D37, 0x9508, 0x8EE9, 0x942A, 0x912F, 0x941A, 0x9383, 0x94DD, 0x951B, 0x957F, 0x95FF, 0x956B, 0x9690, 0x9505, 0x9660, 0x93ED, 0x9659, 0x926A, 0x9797, 0x9154, 0x99C3, 0x90EF, 0x9C65, 0x915D, 0x9E43, 0x91C6, 0x9F17, 0x9191, 0x9F74, 0x9119, 0x9EBB, 0x900A, 0x9DFA, 0x8E8C, 0x9EAE, 0x8D51, 0xA098, 0x8C9E, 0xA345, 0x8CA2, 0xA531, 0x8CBE, 0xA5E5, 0x8C6B, 0xA609, 0x8BEA, 0xA4EC, 0x8B02, 0xA394, 0x89B1, 0xA3B2, 0x8867, 0xA53A, 0x8772, 0xA7C6, 0x870E, 0xA9A5, 0x86DE, 0xAA2D, 0x8675, 0xAA14, 0x85F2, 0xA8A2, 0x853F, 0xA6C5, 0x842E, 0xA64B, 0x82EB, 0xA755, 0x81C5, 0xA99C, 0x8104, 0xAB52, 0x808F, 0xABA6, 0x8015, 0xAB52, 0x7F9B, 0xA99C, 0x7F25, 0xA755, 0x7E64, 0xA64C, 0x7D3E, 0xA6C7, 0x7BFA, 0xA8A5, 0x7AEA, 0xAA18, 0x7A37, 0xAA31, 0x79B5, 0xA9A9, 0x794B, 0xA7CA, 0x791B, 0xA53C, 0x78B7, 0xA3B6, 0x77C1, 0xA39A, 0x7677, 0xA4F1, 0x7526, 0xA60E, 0x743F, 0xA5EB, 0x73BD, 0xA538, 0x736B, 0xA34B, 0x7387, 0xA09E, 0x738A, 0x9EB4, 0x72D6, 0x9E02, 0x719B, 0x9EC4, 0x701D, 0x9F7E, 0x6F0E, 0x9F20, 0x6E96, 0x9E4E, 0x6E61, 0x9C6E, 0x6ECA, 0x99CB, 0x6F37, 0x97A0, 0x6ED2, 0x9664, 0x6DBC, 0x966B, 0x6C38, 0x969B, 0x6B21, 0x960B, 0x6ABB, 0x9526, 0x6AA6, 0x938E, 0x6B48, 0x913B, 0x6C0B, 0x8EF4, 0x6BFA, 0x8D43, 0x6B1D, 0x8C94, 0x69AA, 0x8C3F, 0x689B, 0x8B85, 0x684D, 0x8A9E, 0x685C, 0x8962, 0x692E, 0x8781, 0x6A3C, 0x8546, 0x6A82, 0x833F, 0x69EA, 0x81EC, 0x68A0, 0x811C, 0x67A8, 0x8045, 0x6778, 0x8045, 0x6778, 0xFFFF, 0x8047, 0x6AA0, 0x81C8, 0x6AFA, 0x8268, 0x6BD5, 0x81C8, 0x6CAF, 0x8047, 0x6D09, 0x7EC6, 0x6CAF, 0x7E27, 0x6BD5, 0x7EC6, 0x6AFA, 0x8047, 0x6AA0, 0x8047, 0x6AA0, 0xFFFF, 0x803E, 0x6E19, 0x867C, 0x6E71, 0x8C65, 0x6F75, 0x91D7, 0x711B, 0x96AD, 0x735B, 0x9ABC, 0x762C, 0x9DA2, 0x794C, 0x9F5F, 0x7CA2, 0x9FF3, 0x8011, 0x9F5E, 0x8380, 0x9DA1, 0x86D5, 0x9ABA, 0x89F6, 0x96AB, 0x8CC7, 0x91D6, 0x8F08, 0x8C65, 0x90AD, 0x867C, 0x91B1, 0x803D, 0x9209, 0x7A00, 0x91B1, 0x7416, 0x90AD, 0x6EA6, 0x8F08, 0x69D0, 0x8CC7, 0x65D6, 0x8A0A, 0x62EE, 0x86F4, 0x6125, 0x839B, 0x6089, 0x8011, 0x6124, 0x7C88, 0x62ED, 0x792E, 0x65D6, 0x7619, 0x69CF, 0x735B, 0x6EA5, 0x711B, 0x7416, 0x6F75, 0x7A00, 0x6E71, 0x803E, 0x6E19, 0x803E, 0x6E19, 0xFFFF, 0x803E, 0x6EB2, 0x7A5A, 0x6F04, 0x74B2, 0x6FF8, 0x6F4B, 0x7194, 0x6A8F, 0x73C7, 0x66A2, 0x7681, 0x63D5, 0x7986, 0x6226, 0x7CBF, 0x6197, 0x8011, 0x6226, 0x8363, 0x63D5, 0x869C, 0x66A2, 0x89A2, 0x6A8F, 0x8C5B, 0x6F4B, 0x8E8E, 0x74B2, 0x902B, 0x7A5A, 0x911E, 0x803D, 0x9170, 0x803E, 0x9170, 0x8621, 0x911E, 0x8BCA, 0x902B, 0x9130, 0x8E8E, 0x95ED, 0x8C5B, 0x99CF, 0x89AB, 0x9CA7, 0x869C, 0x9E55, 0x8367, 0x9EE5, 0x8011, 0x9E55, 0x7CBB, 0x9CA7, 0x7986, 0x99CF, 0x7677, 0x95ED, 0x73C7, 0x9130, 0x7194, 0x8BCA, 0x6FF8, 0x8621, 0x6F04, 0x803E, 0x6EB2, 0x803E, 0x6EB2, 0xFFFF, 0x80BC, 0x6FD7, 0x80AF, 0x71D8, 0x7FC8, 0x71D9, 0x7FB7, 0x6FD8, 0x80BC, 0x6FD7, 0x80BC, 0x6FD7, 0xFFFF, 0x83CB, 0x6FF6, 0x84CD, 0x700B, 0x843E, 0x7206, 0x835B, 0x71F4, 0xFFFF, 0x7CA9, 0x6FF8, 0x7D1A, 0x71F5, 0x7C37, 0x7207, 0x7BA7, 0x700D, 0x7CA9, 0x6FF8, 0x7CA9, 0x6FF8, 0xFFFF, 0x87CD, 0x7068, 0x88C7, 0x7092, 0x87BA, 0x727C, 0x86DF, 0x7258, 0xFFFF, 0x78A8, 0x706B, 0x7997, 0x725A, 0x78BA, 0x727E, 0x77AD, 0x7095, 0x78A8, 0x706B, 0x78A8, 0x706B, 0xFFFF, 0x6700, 0x708A, 0x6880, 0x70E5, 0x6920, 0x71BF, 0x6880, 0x7299, 0x66FF, 0x72F4, 0x657F, 0x7299, 0x64E0, 0x71BF, 0x657F, 0x70E4, 0x6700, 0x708A, 0x6700, 0x708A, 0xFFFF, 0x998D, 0x708C, 0x9B0E, 0x70E6, 0x9BAE, 0x71C0, 0x9B0E, 0x729B, 0x998D, 0x72F6, 0x980D, 0x729B, 0x976E, 0x71C1, 0x980D, 0x70E7, 0x998D, 0x708C, 0x998D, 0x708C, 0xFFFF, 0x8BA7, 0x712C, 0x8C95, 0x716A, 0x8B10, 0x7339, 0x8A3F, 0x7303, 0x8BA7, 0x712C, 0xFFFF, 0x74CE, 0x712F, 0x7635, 0x7307, 0x7564, 0x733C, 0x73DE, 0x716D, 0x74CE, 0x712F, 0x74CE, 0x712F, 0xFFFF, 0x8F47, 0x723F, 0x9023, 0x728E, 0x8E2D, 0x743A, 0x8D6B, 0x73F4, 0x8F47, 0x723F, 0xFFFF, 0x712D, 0x7242, 0x7308, 0x73F7, 0x7248, 0x743D, 0x7050, 0x7292, 0x712D, 0x7242, 0x712D, 0x7242, 0xFFFF, 0x803E, 0x72F6, 0x891B, 0x73F4, 0x909A, 0x76CC, 0x959F, 0x7B0B, 0x975E, 0x8011, 0x959F, 0x8517, 0x909A, 0x8957, 0x891B, 0x8C2E, 0x803E, 0x8D2B, 0x7761, 0x8C2E, 0x6FE2, 0x8957, 0x6ADD, 0x8517, 0x691E, 0x8011, 0x6ADD, 0x7B0B, 0x6FE2, 0x76CC, 0x7761, 0x73F4, 0x803E, 0x72F6, 0x803E, 0x72F6, 0xFFFF, 0x803E, 0x738F, 0x77C8, 0x7481, 0x70A0, 0x7738, 0x6BD7, 0x7B46, 0x6A2C, 0x8011, 0x6BD7, 0x84DC, 0x70A1, 0x88EA, 0x77C9, 0x8BA1, 0x803E, 0x8C93, 0x88B4, 0x8BA1, 0x8FDB, 0x88EA, 0x94A5, 0x84DD, 0x9650, 0x8011, 0x94A5, 0x7B46, 0x8FDB, 0x7738, 0x88B4, 0x7481, 0x803E, 0x738F, 0x803E, 0x738F, 0xFFFF, 0x929B, 0x739A, 0x935C, 0x73FA, 0x9100, 0x7578, 0x905A, 0x7527, 0x9175, 0x745E, 0xFFFF, 0x6DDC, 0x739D, 0x7022, 0x7527, 0x6F74, 0x757C, 0x6D16, 0x73FF, 0x6DDC, 0x739D, 0x6DDC, 0x739D, 0xFFFF, 0x9589, 0x7533, 0x9634, 0x75A4, 0x937E, 0x76ED, 0x92E8, 0x768B, 0xFFFF, 0x6AEB, 0x7539, 0x6D8D, 0x7690, 0x6CFB, 0x76F0, 0x6CEC, 0x76FA, 0x6BED, 0x7674, 0x6A40, 0x75A9, 0x6A45, 0x75A7, 0x6AEB, 0x7539, 0x6AEB, 0x7539, 0xFFFF, 0x980B, 0x7707, 0x989A, 0x7784, 0x9597, 0x7892, 0x951A, 0x7825, 0xFFFF, 0x686A, 0x770C, 0x6B5B, 0x782A, 0x6ADF, 0x7897, 0x67DD, 0x7788, 0x686A, 0x770C, 0x686A, 0x770C, 0xFFFF, 0x9A12, 0x790A, 0x9A7E, 0x7991, 0x9740, 0x7A5E, 0x96E1, 0x79E8, 0x9A12, 0x790A, 0xFFFF, 0x6664, 0x790F, 0x6996, 0x79ED, 0x6937, 0x7A63, 0x65F9, 0x7996, 0x6664, 0x790F, 0x6664, 0x790F, 0xFFFF, 0x9B91, 0x7B32, 0x9BDB, 0x7BC1, 0x9870, 0x7C48, 0x9831, 0x7BCB, 0xFFFF, 0x64E6, 0x7B37, 0x6847, 0x7BD0, 0x6807, 0x7C4C, 0x649D, 0x7BC5, 0x64E6, 0x7B37, 0x64E6, 0x7B37, 0xFFFF, 0x9C82, 0x7D72, 0x9CA7, 0x7E06, 0x9925, 0x7E46, 0x9903, 0x7DC5, 0xFFFF, 0x63F7, 0x7D78, 0x6776, 0x7DC9, 0x6756, 0x7E49, 0x63D3, 0x7E0A, 0x63F7, 0x7D78, 0x63F7, 0x7D78, 0xFFFF, 0x5C87, 0x7EDB, 0x5E08, 0x7F35, 0x5EA8, 0x800F, 0x5E08, 0x80E9, 0x5C87, 0x8144, 0x5C85, 0x8144, 0x5B06, 0x80E9, 0x5A67, 0x800F, 0x5B06, 0x7F35, 0x5C87, 0x7EDB, 0x5C87, 0x7EDB, 0xFFFF, 0xA402, 0x7EDE, 0xA583, 0x7F38, 0xA623, 0x8011, 0xA623, 0x8013, 0xA583, 0x80EC, 0xA402, 0x8147, 0xA281, 0x80ED, 0xA1E2, 0x8013, 0xA281, 0x7F38, 0xA402, 0x7EDE, 0xA402, 0x7EDE, 0xFFFF, 0x9CE0, 0x7FC0, 0x9CE0, 0x8055, 0x9957, 0x804D, 0x9957, 0x7FCB, 0xFFFF, 0x639D, 0x7FC5, 0x6726, 0x7FCE, 0x6726, 0x8051, 0x639D, 0x805A, 0x639D, 0x7FC5, 0x639D, 0x7FC5, 0xFFFF, 0x9927, 0x81D1, 0x9CAA, 0x8210, 0x9C87, 0x82A2, 0x9907, 0x8252, 0x9927, 0x81D1, 0x9927, 0x81D1, 0xFFFF, 0x6757, 0x81D5, 0x6777, 0x8255, 0x63F9, 0x82A7, 0x63D4, 0x8214, 0xFFFF, 0x9877, 0x83CF, 0x9BE2, 0x8455, 0x9B99, 0x84E3, 0x9838, 0x844C, 0x9877, 0x83CF, 0x9877, 0x83CF, 0xFFFF, 0x6808, 0x83D3, 0x6848, 0x8450, 0x64E7, 0x84E8, 0x649E, 0x845A, 0xFFFF, 0x9749, 0x85B9, 0x9A88, 0x8684, 0x9A1D, 0x870C, 0x96EB, 0x862E, 0x9749, 0x85B9, 0x9749, 0x85B9, 0xFFFF, 0x6938, 0x85BD, 0x6997, 0x8634, 0x6665, 0x8710, 0x65F9, 0x8689, 0xFFFF, 0x95A2, 0x8785, 0x98A5, 0x8892, 0x9818, 0x890F, 0x9527, 0x87F2, 0x95A2, 0x8785, 0x95A2, 0x8785, 0xFFFF, 0x6ADF, 0x878A, 0x6B5B, 0x87F8, 0x686A, 0x8914, 0x67DC, 0x8897, 0x6ADF, 0x878A, 0xFFFF, 0x6CF7, 0x892F, 0x6D8D, 0x8991, 0x6AEB, 0x8AE9, 0x6A40, 0x8A79, 0xFFFF, 0x9380, 0x8932, 0x9645, 0x8A72, 0x963E, 0x8A77, 0x9599, 0x8AE3, 0x92F5, 0x898D, 0x9380, 0x8932, 0x9380, 0x8932, 0xFFFF, 0x9110, 0x8AA1, 0x936F, 0x8C1F, 0x92AA, 0x8C80, 0x9064, 0x8AF7, 0x9110, 0x8AA1, 0x9110, 0x8AA1, 0xFFFF, 0x6F73, 0x8AA5, 0x7021, 0x8AFB, 0x7035, 0x8B04, 0x6DED, 0x8C8B, 0x6DE1, 0x8C87, 0x6D17, 0x8C23, 0xFFFF, 0x8E3E, 0x8BE1, 0x9037, 0x8D8B, 0x8F59, 0x8DDC, 0x8D7C, 0x8C27, 0x8E3E, 0x8BE1, 0x8E3E, 0x8BE1, 0xFFFF, 0x7259, 0x8BEB, 0x731B, 0x8C31, 0x7140, 0x8DE7, 0x7064, 0x8D97, 0xFFFF, 0x8B21, 0x8CE3, 0x8CA9, 0x8EB2, 0x8BBA, 0x8EEF, 0x8A51, 0x8D18, 0x8B21, 0x8CE3, 0x8B21, 0x8CE3, 0xFFFF, 0x7576, 0x8CEB, 0x7648, 0x8D20, 0x74E0, 0x8EF8, 0x73F2, 0x8EBB, 0xFFFF, 0x66F3, 0x8D2F, 0x6874, 0x8D8A, 0x687D, 0x8D8F, 0x6886, 0x8D94, 0x6926, 0x8E6E, 0x6887, 0x8F48, 0x6705, 0x8FA2, 0x6584, 0x8F49, 0x657F, 0x8F45, 0x6570, 0x8F3E, 0x6573, 0x8F3E, 0x64D3, 0x8E63, 0x6573, 0x8D89, 0x66F3, 0x8D2F, 0x66F3, 0x8D2F, 0xFFFF, 0x9993, 0x8D31, 0x9B13, 0x8D8C, 0x9BB4, 0x8E66, 0x9B16, 0x8F40, 0x9993, 0x8F9A, 0x9814, 0x8F40, 0x9774, 0x8E66, 0x9812, 0x8D8C, 0x9993, 0x8D31, 0x9993, 0x8D31, 0xFFFF, 0x87CD, 0x8DA1, 0x88DC, 0x8F8B, 0x87E0, 0x8FB5, 0x86F0, 0x8DC6, 0x87CD, 0x8DA1, 0x87CD, 0x8DA1, 0xFFFF, 0x78CD, 0x8DA8, 0x79A8, 0x8DCB, 0x78BC, 0x8FBB, 0x77C1, 0x8F92, 0xFFFF, 0x8450, 0x8E19, 0x84E2, 0x9014, 0x83E0, 0x9029, 0x836C, 0x8E2C, 0x8450, 0x8E19, 0x8450, 0x8E19, 0xFFFF, 0x7C48, 0x8E1C, 0x7D2B, 0x8E2E, 0x7CBD, 0x902C, 0x7BBB, 0x9017, 0x7C48, 0x8E1C, 0xFFFF, 0x80BF, 0x8E49, 0x80D2, 0x904A, 0x7FCC, 0x904A, 0x7FD9, 0x8E49, 0x80BF, 0x8E49, 0x80BF, 0x8E49, 0xFFFF, 0x804F, 0x9321, 0x81D0, 0x937A, 0x8271, 0x9455, 0x81D1, 0x952F, 0x8051, 0x958A, 0x7ECF, 0x9530, 0x7E2F, 0x9456, 0x7ECE, 0x937B, 0x804F, 0x9321, 0x804F, 0x9321, 0xFFFF, 0x8048, 0x46D9, 0x27BC, 0x9DBA, 0xD8D3, 0x9DBA, 0xFFFF, 0x8048, 0x4BC9, 0x952E, 0x604A, 0x6B62, 0x604A, 0xFFFF, 0x68D2, 0x62CE, 0x97BF, 0x62CE, 0xB9BA, 0x8427, 0xA239, 0x9B36, 0x5E16, 0x9B36, 0x46B6, 0x8446, 0x68D2, 0x62CE, 0xFFFF, 0xBC3E, 0x869F, 0xD13B, 0x9B36, 0xA742, 0x9B36, 0xFFFF, 0x4431, 0x86BE, 0x590E, 0x9B36, 0x2F54, 0x9B36, 0x4431, 0x86BE};
+const PROGMEM uint16_t logo_white[] = {0x80BC, 0x6FD7, 0x80AF, 0x71D8, 0x7FC8, 0x71D9, 0x7FB7, 0x6FD8, 0x80BC, 0x6FD7, 0xFFFF, 0x83CB, 0x6FF6, 0x84CD, 0x700B, 0x843E, 0x7206, 0x835B, 0x71F4, 0xFFFF, 0x7CA9, 0x6FF8, 0x7D1A, 0x71F5, 0x7C37, 0x7207, 0x7BA7, 0x700D, 0x7CA9, 0x6FF8, 0x7CA9, 0x6FF8, 0xFFFF, 0x87CD, 0x7068, 0x88C7, 0x7092, 0x87BA, 0x727C, 0x86DF, 0x7258, 0xFFFF, 0x78A8, 0x706B, 0x7997, 0x725A, 0x78BA, 0x727E, 0x77AD, 0x7095, 0x78A8, 0x706B, 0x78A8, 0x706B, 0xFFFF, 0x8BA7, 0x712C, 0x8C95, 0x716A, 0x8B10, 0x7339, 0x8A3F, 0x7303, 0xFFFF, 0x74CE, 0x712F, 0x7635, 0x7307, 0x7564, 0x733C, 0x73DE, 0x716D, 0x74CE, 0x712F, 0x74CE, 0x712F, 0xFFFF, 0x8F47, 0x723F, 0x9023, 0x728E, 0x8E2D, 0x743A, 0x8D6B, 0x73F4, 0xFFFF, 0x712D, 0x7242, 0x7309, 0x73F7, 0x7248, 0x743D, 0x7050, 0x7292, 0x712D, 0x7242, 0x712D, 0x7242, 0xFFFF, 0x929B, 0x739A, 0x935C, 0x73FA, 0x9100, 0x7578, 0x905A, 0x7527, 0xFFFF, 0x6DDC, 0x739D, 0x7022, 0x7527, 0x6F74, 0x757C, 0x6D16, 0x73FF, 0x6DDC, 0x739D, 0x6DDC, 0x739D, 0xFFFF, 0x9589, 0x7533, 0x9634, 0x75A4, 0x937E, 0x76ED, 0x92E8, 0x768B, 0xFFFF, 0x6AEB, 0x7539, 0x6D8D, 0x7690, 0x6CFB, 0x76F0, 0x6A40, 0x75A9, 0x6AEB, 0x7539, 0xFFFF, 0x980B, 0x7707, 0x989A, 0x7784, 0x9597, 0x7892, 0x951A, 0x7825, 0xFFFF, 0x686A, 0x770C, 0x6B5B, 0x782A, 0x6ADF, 0x7897, 0x67DD, 0x7788, 0x686A, 0x770C, 0x686A, 0x770C, 0xFFFF, 0x9A12, 0x790A, 0x9A7E, 0x7991, 0x9740, 0x7A5E, 0x96E1, 0x79E8, 0xFFFF, 0x6664, 0x790F, 0x6996, 0x79ED, 0x6937, 0x7A63, 0x65F9, 0x7996, 0x6664, 0x790F, 0x6664, 0x790F, 0xFFFF, 0x9B91, 0x7B32, 0x9BDB, 0x7BC1, 0x9870, 0x7C48, 0x9831, 0x7BCC, 0xFFFF, 0x64E6, 0x7B37, 0x6847, 0x7BD0, 0x6807, 0x7C4C, 0x649D, 0x7BC5, 0x64E6, 0x7B37, 0x64E6, 0x7B37, 0xFFFF, 0x9C82, 0x7D72, 0x9CA7, 0x7E06, 0x9925, 0x7E46, 0x9903, 0x7DC5, 0xFFFF, 0x63F7, 0x7D78, 0x6776, 0x7DC9, 0x6756, 0x7E49, 0x63D3, 0x7E0A, 0x63F7, 0x7D78, 0x63F7, 0x7D78, 0xFFFF, 0x9CE0, 0x7FC0, 0x9CE0, 0x8055, 0x9957, 0x804D, 0x9957, 0x7FCB, 0xFFFF, 0x639D, 0x7FC5, 0x6726, 0x7FCE, 0x6726, 0x8051, 0x639D, 0x805A, 0x639D, 0x7FC5, 0xFFFF, 0x9927, 0x81D1, 0x9CAA, 0x8210, 0x9C87, 0x82A2, 0x9907, 0x8252, 0x9927, 0x81D1, 0x9927, 0x81D1, 0xFFFF, 0x6757, 0x81D5, 0x6777, 0x8256, 0x63F9, 0x82A7, 0x63D4, 0x8214, 0xFFFF, 0x9877, 0x83CF, 0x9BE2, 0x8455, 0x9B99, 0x84E3, 0x9838, 0x844C, 0x9877, 0x83CF, 0xFFFF, 0x6808, 0x83D3, 0x6848, 0x8450, 0x64E7, 0x84E8, 0x649E, 0x845A, 0xFFFF, 0x9749, 0x85B9, 0x9A88, 0x8684, 0x9A1D, 0x870C, 0x96EB, 0x862E, 0x9749, 0x85B9, 0x9749, 0x85B9, 0xFFFF, 0x6938, 0x85BD, 0x6997, 0x8634, 0x6665, 0x8710, 0x65F9, 0x8689, 0xFFFF, 0x95A2, 0x8785, 0x98A5, 0x8892, 0x9818, 0x890F, 0x9527, 0x87F2, 0x95A2, 0x8785, 0x95A2, 0x8785, 0xFFFF, 0x6ADF, 0x878A, 0x6B5B, 0x87F8, 0x686A, 0x8915, 0x67DC, 0x8897, 0xFFFF, 0x6CF7, 0x8930, 0x6D8D, 0x8991, 0x6AEB, 0x8AE9, 0x6A40, 0x8A79, 0xFFFF, 0x9380, 0x8932, 0x9645, 0x8A72, 0x9599, 0x8AE3, 0x92F5, 0x898D, 0x9380, 0x8932, 0xFFFF, 0x9110, 0x8AA1, 0x936F, 0x8C1F, 0x92AA, 0x8C80, 0x9064, 0x8AF7, 0x9110, 0x8AA1, 0x9110, 0x8AA1, 0xFFFF, 0x6F73, 0x8AA5, 0x7021, 0x8AFB, 0x6DED, 0x8C8C, 0x6D17, 0x8C23, 0xFFFF, 0x8E3E, 0x8BE1, 0x9037, 0x8D8B, 0x8F59, 0x8DDC, 0x8D7C, 0x8C27, 0x8E3E, 0x8BE1, 0x8E3E, 0x8BE1, 0xFFFF, 0x7259, 0x8BEB, 0x731B, 0x8C31, 0x7140, 0x8DE7, 0x7064, 0x8D97, 0xFFFF, 0x8B21, 0x8CE3, 0x8CA9, 0x8EB2, 0x8BBA, 0x8EEF, 0x8A51, 0x8D18, 0x8B21, 0x8CE3, 0x8B21, 0x8CE3, 0xFFFF, 0x7576, 0x8CEB, 0x7648, 0x8D20, 0x74E0, 0x8EF8, 0x73F2, 0x8EBB, 0xFFFF, 0x87CD, 0x8DA1, 0x88DC, 0x8F8B, 0x87E0, 0x8FB5, 0x86F0, 0x8DC6, 0x87CD, 0x8DA1, 0x87CD, 0x8DA1, 0xFFFF, 0x78CC, 0x8DA8, 0x79A8, 0x8DCB, 0x78BC, 0x8FBB, 0x77C0, 0x8F92, 0xFFFF, 0x8450, 0x8E19, 0x84E2, 0x9014, 0x83E0, 0x9029, 0x836C, 0x8E2C, 0x8450, 0x8E19, 0x8450, 0x8E19, 0xFFFF, 0x7C48, 0x8E1C, 0x7D2B, 0x8E2E, 0x7CBD, 0x902C, 0x7BBB, 0x9017, 0xFFFF, 0x80BE, 0x8E49, 0x80D1, 0x904A, 0x7FCC, 0x904A, 0x7FD9, 0x8E49, 0x80BE, 0x8E49, 0xFFFF, 0x8276, 0x75D6, 0x83AF, 0x75FE, 0x8436, 0x7628, 0x84AE, 0x7661, 0x8542, 0x7706, 0x8512, 0x77BA, 0x8457, 0x7845, 0x8335, 0x788B, 0x8318, 0x7882, 0x82D8, 0x7860, 0x831E, 0x7830, 0x8353, 0x7823, 0x83E6, 0x77F9, 0x8464, 0x7790, 0x847A, 0x771A, 0x8415, 0x76B7, 0x83B6, 0x7691, 0x8351, 0x7676, 0x827F, 0x7662, 0x81BB, 0x7687, 0x8161, 0x76AF, 0x8123, 0x76DA, 0x80E5, 0x771A, 0x80C5, 0x774D, 0x80B8, 0x77C1, 0x80D1, 0x77EE, 0x8107, 0x7814, 0x81CC, 0x786B, 0x837F, 0x7918, 0x8464, 0x7983, 0x84C0, 0x79B2, 0x852D, 0x79FD, 0x859D, 0x7ABC, 0x858E, 0x7B79, 0x8545, 0x7C25, 0x84D9, 0x7CC5, 0x8469, 0x7D4D, 0x843B, 0x7DCD, 0x8555, 0x7DA8, 0x85D3, 0x7D67, 0x870D, 0x7CA0, 0x87E0, 0x7BC0, 0x880D, 0x7B5B, 0x886D, 0x7A46, 0x88B3, 0x799B, 0x88CC, 0x7970, 0x893A, 0x78EA, 0x8995, 0x78A8, 0x8A01, 0x786F, 0x8AF8, 0x781F, 0x8BA6, 0x77FD, 0x8C0C, 0x77EF, 0x8C96, 0x77FB, 0x8D1D, 0x7815, 0x8D59, 0x7826, 0x8E40, 0x7889, 0x8EDB, 0x7925, 0x8EFC, 0x797B, 0x8EFF, 0x79D4, 0x8E71, 0x7A7B, 0x8D58, 0x7AD2, 0x8C23, 0x7ADE, 0x8AFF, 0x7A97, 0x8AF5, 0x7A81, 0x8AEF, 0x7A4E, 0x8B68, 0x7A52, 0x8B96, 0x7A5F, 0x8C39, 0x7A87, 0x8D33, 0x7A7F, 0x8E07, 0x7A3F, 0x8E66, 0x79CB, 0x8E63, 0x7985, 0x8E43, 0x793F, 0x8DC6, 0x78C6, 0x8CFA, 0x7876, 0x8C7E, 0x785F, 0x8C18, 0x7857, 0x8B84, 0x7874, 0x8B22, 0x788F, 0x8A7D, 0x78CA, 0x8A2E, 0x78F9, 0x89F0, 0x7930, 0x89A3, 0x79A5, 0x8979, 0x7AC0, 0x897C, 0x7B9C, 0x8972, 0x7BF2, 0x88CC, 0x7D32, 0x87B7, 0x7E4C, 0x8665, 0x7F52, 0x8660, 0x7F5A, 0x878F, 0x7F01, 0x88AE, 0x7EC2, 0x89FD, 0x7E9E, 0x8B8D, 0x7EC6, 0x8C40, 0x7F0E, 0x8CB6, 0x7F68, 0x8D1D, 0x7FD7, 0x8DFA, 0x80BD, 0x8EA8, 0x816E, 0x8F34, 0x81D4, 0x8F8A, 0x81F9, 0x8FDA, 0x820A, 0x90AB, 0x820F, 0x9120, 0x81FF, 0x91A5, 0x81DC, 0x91F4, 0x81B8, 0x922C, 0x8198, 0x9288, 0x812B, 0x927D, 0x80AB, 0x9252, 0x8068, 0x921C, 0x8033, 0x9174, 0x7FEB, 0x9099, 0x7FEB, 0x8FCF, 0x8029, 0x8F5D, 0x808D, 0x8F47, 0x80A4, 0x8ED4, 0x80A4, 0x8EC5, 0x8070, 0x8F65, 0x7FE6, 0x906D, 0x7F92, 0x91A4, 0x7F90, 0x92A8, 0x7FF7, 0x92FC, 0x8043, 0x9331, 0x8090, 0x9349, 0x813D, 0x92D1, 0x81E3, 0x9264, 0x8227, 0x91E5, 0x825B, 0x915D, 0x8280, 0x90D3, 0x8296, 0x8FA0, 0x829A, 0x8F2C, 0x8286, 0x8EE7, 0x8273, 0x8E78, 0x824A, 0x8DA9, 0x81D4, 0x8CB9, 0x8127, 0x8B68, 0x802C, 0x8B22, 0x8001, 0x8AC3, 0x7FE7, 0x8A50, 0x7FF4, 0x88FD, 0x8068, 0x87A4, 0x811D, 0x879E, 0x812D, 0x8904, 0x81F1, 0x89D4, 0x8285, 0x8A7C, 0x8343, 0x8A94, 0x8431, 0x8A4E, 0x84A1, 0x89E8, 0x850E, 0x892F, 0x85E5, 0x88B0, 0x86E5, 0x88C0, 0x8757, 0x88F2, 0x878D, 0x8927, 0x87AD, 0x8ABF, 0x8821, 0x8B0E, 0x881E, 0x8B70, 0x8811, 0x8C1B, 0x87D6, 0x8C9B, 0x8776, 0x8CC4, 0x873D, 0x8CD3, 0x8705, 0x8CA2, 0x86A3, 0x8C06, 0x8662, 0x8B39, 0x864F, 0x8A77, 0x8662, 0x89F9, 0x864D, 0x8A10, 0x8606, 0x8A66, 0x85F7, 0x8B35, 0x85DC, 0x8C50, 0x85FD, 0x8D3C, 0x8663, 0x8D94, 0x870A, 0x8D7D, 0x875F, 0x8D3A, 0x87B8, 0x8CB1, 0x882D, 0x8BC1, 0x888C, 0x8B30, 0x88A7, 0x8A8D, 0x88AE, 0x89EE, 0x8898, 0x896E, 0x887E, 0x8869, 0x882D, 0x87EE, 0x87EA, 0x87A4, 0x87A8, 0x878E, 0x8785, 0x874D, 0x86E3, 0x875D, 0x8637, 0x87FD, 0x8466, 0x8705, 0x835A, 0x86B8, 0x8359, 0x84A4, 0x8358, 0x7F20, 0x851B, 0x7F13, 0x864D, 0x8016, 0x86F9, 0x818E, 0x87D8, 0x823B, 0x8869, 0x8272, 0x88C9, 0x8276, 0x8915, 0x8266, 0x893D, 0x81FB, 0x89D8, 0x8197, 0x8A21, 0x8119, 0x8A62, 0x80A7, 0x8A8A, 0x8016, 0x8AAA, 0x7EDC, 0x8AAE, 0x7DC5, 0x8A63, 0x7D55, 0x8A29, 0x7CFA, 0x89E5, 0x7CAD, 0x8939, 0x7D1B, 0x8895, 0x7E00, 0x8825, 0x7F27, 0x8800, 0x7F66, 0x880F, 0x7F69, 0x8850, 0x7E49, 0x8873, 0x7D9A, 0x88C9, 0x7D4F, 0x893E, 0x7D8B, 0x89B2, 0x7DD8, 0x89E6, 0x7E36, 0x8A10, 0x7F02, 0x8A40, 0x7FDB, 0x8A34, 0x8046, 0x8A16, 0x8091, 0x89F5, 0x80A5, 0x89EB, 0x80FE, 0x89AB, 0x8126, 0x8981, 0x8159, 0x8918, 0x814F, 0x88E6, 0x8128, 0x88B8, 0x8094, 0x8856, 0x7EFC, 0x8796, 0x7D74, 0x86E7, 0x7D3D, 0x86C5, 0x7CD8, 0x8674, 0x7C98, 0x8605, 0x7CA0, 0x8536, 0x7D7C, 0x83E6, 0x7E07, 0x8357, 0x7DED, 0x835B, 0x79CC, 0x843E, 0x7962, 0x8448, 0x77CB, 0x8450, 0x76F3, 0x8438, 0x763E, 0x841E, 0x7502, 0x83FE, 0x746C, 0x83FD, 0x73E4, 0x840A, 0x72CE, 0x8444, 0x729B, 0x8457, 0x71E6, 0x84B7, 0x71B5, 0x84EB, 0x719B, 0x853B, 0x719B, 0x8558, 0x71D4, 0x85E0, 0x72B0, 0x8642, 0x73D4, 0x8661, 0x74B3, 0x8616, 0x74AD, 0x84D7, 0x74B2, 0x84B3, 0x74B5, 0x849B, 0x751E, 0x8496, 0x753B, 0x84B8, 0x75C5, 0x856E, 0x756D, 0x865A, 0x74D0, 0x86B8, 0x73FA, 0x86EA, 0x7250, 0x86CF, 0x70E7, 0x863F, 0x707E, 0x85C8, 0x705F, 0x8549, 0x7075, 0x84CC, 0x70AC, 0x8475, 0x70CD, 0x8452, 0x71FF, 0x839C, 0x7287, 0x8376, 0x736A, 0x833A, 0x7443, 0x8319, 0x751E, 0x8311, 0x76AC, 0x8327, 0x77C4, 0x8341, 0x7810, 0x8340, 0x799F, 0x8313, 0x7A2A, 0x82EA, 0x7B24, 0x8281, 0x7BE4, 0x820C, 0x7BEC, 0x81B1, 0x7A5E, 0x81C8, 0x7809, 0x81ED, 0x7751, 0x81F8, 0x7664, 0x81EF, 0x7571, 0x81B4, 0x74BB, 0x8141, 0x7483, 0x80F9, 0x7408, 0x802F, 0x73D9, 0x7FEB, 0x7359, 0x7F50, 0x72A0, 0x7EC4, 0x719E, 0x7E89, 0x7074, 0x7EA8, 0x7015, 0x7ECC, 0x6FD0, 0x7EF8, 0x6FA3, 0x7F19, 0x6F6B, 0x7FBB, 0x6F93, 0x8017, 0x6FA7, 0x8032, 0x6FD7, 0x805A, 0x70DF, 0x8092, 0x7205, 0x805A, 0x729E, 0x7FCB, 0x72B3, 0x7FBC, 0x7309, 0x7FA6, 0x733B, 0x7FDE, 0x72F9, 0x804B, 0x726D, 0x80A7, 0x70E6, 0x80FB, 0x700D, 0x80EC, 0x6F48, 0x80A8, 0x6EFC, 0x8073, 0x6EC1, 0x8026, 0x6E93, 0x7FCC, 0x6ED4, 0x7ED8, 0x6F54, 0x7E72, 0x6FCB, 0x7E3A, 0x700B, 0x7E25, 0x71AB, 0x7DED, 0x7356, 0x7E3E, 0x7472, 0x7EF4, 0x7536, 0x7FBD, 0x75DA, 0x8075, 0x7628, 0x80B6, 0x767B, 0x80D8, 0x76D9, 0x80EF, 0x7755, 0x80FC, 0x7881, 0x80D5, 0x7931, 0x8093, 0x7A00, 0x801E, 0x799B, 0x7D9B, 0x789A, 0x7CD8, 0x77C0, 0x7BE5, 0x7783, 0x7B55, 0x7787, 0x7AB9, 0x77AE, 0x7A67, 0x77E6, 0x7A1D, 0x781E, 0x79CD, 0x785E, 0x7909, 0x7853, 0x78C0, 0x7823, 0x788B, 0x7808, 0x7875, 0x7649, 0x77E8, 0x74B6, 0x7869, 0x7488, 0x78B3, 0x7472, 0x7901, 0x74D2, 0x796F, 0x75D8, 0x799A, 0x76EE, 0x7971, 0x774A, 0x797A, 0x7751, 0x79B4, 0x76A0, 0x79F0, 0x75E4, 0x7A0A, 0x7454, 0x79E1, 0x73AF, 0x7986, 0x7369, 0x7909, 0x7374, 0x7891, 0x739D, 0x783C, 0x73B6, 0x781E, 0x74B7, 0x7768, 0x765D, 0x772C, 0x77ED, 0x7769, 0x7932, 0x77FC, 0x7979, 0x7836, 0x79B8, 0x787B, 0x79DF, 0x7912, 0x7998, 0x7A14, 0x7967, 0x7AB4, 0x796A, 0x7AD8, 0x79C5, 0x7B60, 0x7A9D, 0x7BE9, 0x7B72, 0x7C47, 0x7EBA, 0x7BD6, 0x8206, 0x7CA8, 0x82FA, 0x7C2E, 0x8391, 0x7BB4, 0x83F6, 0x7B40, 0x8413, 0x7AD0, 0x83DD, 0x7A71, 0x838A, 0x7A39, 0x8296, 0x79B7, 0x80F3, 0x78FA, 0x8016, 0x788A, 0x7FB4, 0x7833, 0x7F8D, 0x77DF, 0x7F92, 0x77A9, 0x7FB3, 0x7718, 0x7FF6, 0x76C2, 0x8036, 0x768A, 0x8097, 0x764A, 0x80DF, 0x762A, 0x813C, 0x7605, 0x8275, 0x75D5};
+
+#define LOGO_BACKGROUND 0xDEEA5C
+
+#define LOGO_PAINT_PATHS \
+ LOGO_PAINT_PATH(0xC1D82F, logo_green) \
+ LOGO_PAINT_PATH(0x000000, logo_black) \
+ LOGO_PAINT_PATH(0x000000, logo_type) \
+ LOGO_PAINT_PATH(0x000000, logo_mark) \
+ LOGO_PAINT_PATH(0xFFFFFF, logo_white)
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/colors.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/colors.h
new file mode 100644
index 0000000..cdcf00a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/colors.h
@@ -0,0 +1,183 @@
+/************
+ * colors.h *
+ ************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+namespace Theme {
+ #if ENABLED(TOUCH_UI_COCOA_THEME)
+ constexpr int accent_hue = 23;
+
+ // Browns and Oranges
+ constexpr uint32_t accent_color_1 = hsl_to_rgb(12.8,0.597,0.263); // Darkest
+ constexpr uint32_t accent_color_2 = hsl_to_rgb(12.8,0.597,0.263);
+ constexpr uint32_t accent_color_3 = hsl_to_rgb( 9.6,0.664,0.443);
+ constexpr uint32_t accent_color_4 = hsl_to_rgb(16.3,0.873,0.537);
+ constexpr uint32_t accent_color_5 = hsl_to_rgb(23.0,0.889,0.539);
+ constexpr uint32_t accent_color_6 = hsl_to_rgb(23.0,0.889,0.539); // Lightest
+ #else
+ // Use linear accent colors
+
+ #if ANY(TOUCH_UI_ROYAL_THEME, TOUCH_UI_FROZEN_THEME)
+ // Dark blue accent colors
+ constexpr int accent_hue = 216;
+ constexpr float accent_sat = 0.7;
+ #else
+ // Green accent colors
+ constexpr int accent_hue = 68;
+ constexpr float accent_sat = 0.68;
+ #endif
+
+ // Shades of accent color
+ constexpr uint32_t accent_color_0 = hsl_to_rgb(accent_hue, accent_sat, 0.15); // Darkest
+ constexpr uint32_t accent_color_1 = hsl_to_rgb(accent_hue, accent_sat, 0.26);
+ constexpr uint32_t accent_color_2 = hsl_to_rgb(accent_hue, accent_sat, 0.39);
+ constexpr uint32_t accent_color_3 = hsl_to_rgb(accent_hue, accent_sat, 0.52);
+ constexpr uint32_t accent_color_4 = hsl_to_rgb(accent_hue, accent_sat, 0.65);
+ constexpr uint32_t accent_color_5 = hsl_to_rgb(accent_hue, accent_sat, 0.78);
+ constexpr uint32_t accent_color_6 = hsl_to_rgb(accent_hue, accent_sat, 0.91); // Lightest
+ #endif
+
+ // Shades of gray
+
+ constexpr float gray_sat = 0.14;
+ constexpr uint32_t gray_color_0 = hsl_to_rgb(accent_hue, gray_sat, 0.15); // Darkest
+ constexpr uint32_t gray_color_1 = hsl_to_rgb(accent_hue, gray_sat, 0.26);
+ constexpr uint32_t gray_color_2 = hsl_to_rgb(accent_hue, gray_sat, 0.39);
+ constexpr uint32_t gray_color_3 = hsl_to_rgb(accent_hue, gray_sat, 0.52);
+ constexpr uint32_t gray_color_4 = hsl_to_rgb(accent_hue, gray_sat, 0.65);
+ constexpr uint32_t gray_color_5 = hsl_to_rgb(accent_hue, gray_sat, 0.78);
+ constexpr uint32_t gray_color_6 = hsl_to_rgb(accent_hue, gray_sat, 0.91); // Lightest
+
+ #if ENABLED(TOUCH_UI_ROYAL_THEME)
+ constexpr uint32_t theme_darkest = accent_color_1;
+ constexpr uint32_t theme_dark = accent_color_4;
+
+ constexpr uint32_t bg_color = gray_color_0;
+ constexpr uint32_t axis_label = gray_color_1;
+
+ constexpr uint32_t bg_text_enabled = accent_color_6;
+ constexpr uint32_t bg_text_disabled = gray_color_0;
+ constexpr uint32_t bg_normal = accent_color_4;
+ constexpr uint32_t fg_disabled = gray_color_0;
+ constexpr uint32_t fg_normal = accent_color_0;
+ constexpr uint32_t fg_action = accent_color_1;
+
+ constexpr uint32_t logo_bg_rgb = accent_color_1;
+ constexpr uint32_t logo_fill_rgb = accent_color_0;
+ constexpr uint32_t logo_stroke_rgb = accent_color_4;
+ #elif ANY(TOUCH_UI_COCOA_THEME, TOUCH_UI_FROZEN_THEME)
+ constexpr uint32_t theme_darkest = accent_color_1;
+ constexpr uint32_t theme_dark = accent_color_4;
+
+ constexpr uint32_t bg_color = 0xFFFFFF;
+ constexpr uint32_t axis_label = gray_color_5;
+
+ constexpr uint32_t bg_text_enabled = accent_color_1;
+ constexpr uint32_t bg_text_disabled = gray_color_1;
+ constexpr uint32_t bg_normal = accent_color_4;
+ constexpr uint32_t fg_disabled = gray_color_6;
+ constexpr uint32_t fg_normal = accent_color_1;
+ constexpr uint32_t fg_action = accent_color_4;
+
+ constexpr uint32_t logo_bg_rgb = accent_color_5;
+ constexpr uint32_t logo_fill_rgb = accent_color_6;
+ constexpr uint32_t logo_stroke_rgb = accent_color_2;
+ #else
+ constexpr uint32_t theme_darkest = gray_color_1;
+ constexpr uint32_t theme_dark = gray_color_2;
+
+ constexpr uint32_t bg_color = gray_color_1;
+ constexpr uint32_t axis_label = gray_color_2;
+
+ constexpr uint32_t bg_text_enabled = 0xFFFFFF;
+ constexpr uint32_t bg_text_disabled = gray_color_2;
+ constexpr uint32_t bg_normal = gray_color_1;
+ constexpr uint32_t fg_disabled = gray_color_1;
+ constexpr uint32_t fg_normal = gray_color_2;
+ constexpr uint32_t fg_action = accent_color_2;
+
+ constexpr uint32_t logo_bg_rgb = accent_color_4;
+ constexpr uint32_t logo_fill_rgb = accent_color_3;
+ constexpr uint32_t logo_stroke_rgb = 0x000000;
+ #endif
+
+ constexpr uint32_t shadow_rgb = gray_color_6;
+ constexpr uint32_t stroke_rgb = accent_color_1;
+ constexpr uint32_t fill_rgb = accent_color_3;
+ #if ENABLED(TOUCH_UI_COCOA_PRESS)
+ constexpr uint32_t syringe_rgb = 0xFFFFFF;
+ constexpr uint32_t fluid_rgb = accent_color_5;
+ #else
+ constexpr uint32_t syringe_rgb = accent_color_5;
+ constexpr uint32_t fluid_rgb = accent_color_3;
+ #endif
+
+ #if ENABLED(TOUCH_UI_ROYAL_THEME)
+ constexpr uint32_t x_axis = hsl_to_rgb(0, 1.00, 0.26);
+ constexpr uint32_t y_axis = hsl_to_rgb(120, 1.00, 0.13);
+ constexpr uint32_t z_axis = hsl_to_rgb(240, 1.00, 0.10);
+ #else
+ constexpr uint32_t x_axis = hsl_to_rgb(0, 1.00, 0.5);
+ constexpr uint32_t y_axis = hsl_to_rgb(120, 1.00, 0.37);
+ constexpr uint32_t z_axis = hsl_to_rgb(240, 1.00, 0.37);
+ #endif
+ constexpr uint32_t e_axis = axis_label;
+ constexpr uint32_t feedrate = axis_label;
+ constexpr uint32_t other = axis_label;
+
+ // Status screen
+ constexpr uint32_t progress = axis_label;
+ constexpr uint32_t status_msg = axis_label;
+ #if ENABLED(TOUCH_UI_ROYAL_THEME)
+ constexpr uint32_t fan_speed = hsl_to_rgb(240, 0.5, 0.13);
+ constexpr uint32_t temp = hsl_to_rgb(343, 1.0, 0.23);
+ #else
+ constexpr uint32_t fan_speed = hsl_to_rgb(204, 0.47, 0.41);
+ constexpr uint32_t temp = hsl_to_rgb(311, 0.51, 0.35);
+ #endif
+
+ constexpr uint32_t disabled_icon = gray_color_1;
+
+ // Calibration Registers Screen
+ constexpr uint32_t transformA = 0x3010D0;
+ constexpr uint32_t transformB = 0x4010D0;
+ constexpr uint32_t transformC = 0x5010D0;
+ constexpr uint32_t transformD = 0x6010D0;
+ constexpr uint32_t transformE = 0x7010D0;
+ constexpr uint32_t transformF = 0x8010D0;
+ constexpr uint32_t transformVal = 0x104010;
+
+ constexpr btn_colors disabled_btn = {.bg = bg_color, .grad = fg_disabled, .fg = fg_disabled, .rgb = fg_disabled };
+ constexpr btn_colors normal_btn = {.bg = fg_action, .grad = 0xFFFFFF, .fg = fg_normal, .rgb = 0xFFFFFF };
+ constexpr btn_colors action_btn = {.bg = bg_color, .grad = 0xFFFFFF, .fg = fg_action, .rgb = 0xFFFFFF };
+ constexpr btn_colors red_btn = {.bg = 0xFF5555, .grad = 0xFFFFFF, .fg = 0xFF0000, .rgb = 0xFFFFFF };
+ constexpr btn_colors ui_slider = {.bg = theme_darkest, .grad = 0xFFFFFF, .fg = theme_dark, .rgb = accent_color_3 };
+ constexpr btn_colors ui_toggle = {.bg = theme_darkest, .grad = 0xFFFFFF, .fg = theme_dark, .rgb = 0xFFFFFF };
+
+ // Temperature color scale
+
+ const rgb_t cool_rgb ( 0, 0, 0);
+ const rgb_t low_rgb (128, 0, 0);
+ const rgb_t med_rgb (255, 128, 0);
+ const rgb_t high_rgb (255, 255, 128);
+};
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/fonts.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/fonts.h
new file mode 100644
index 0000000..7cc4e07
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/fonts.h
@@ -0,0 +1,80 @@
+/***********
+ * fonts.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+namespace Theme {
+ #ifdef TOUCH_UI_800x480
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ constexpr int16_t font_tiny = 26;
+ constexpr int16_t font_xsmall = 28;
+ constexpr int16_t font_small = 29;
+ constexpr int16_t font_medium = 30;
+ constexpr int16_t font_large = 30;
+ constexpr int16_t font_xlarge = 31;
+ #else
+ constexpr int16_t font_tiny = 27;
+ constexpr int16_t font_xsmall = 29;
+ constexpr int16_t font_small = 30;
+ constexpr int16_t font_medium = 30;
+ constexpr int16_t font_large = 31;
+ constexpr int16_t font_xlarge = 31;
+ #endif
+ constexpr float icon_scale = 1.0;
+ #elif defined(TOUCH_UI_480x272)
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ constexpr int16_t font_tiny = 26;
+ constexpr int16_t font_xsmall = 26;
+ constexpr int16_t font_small = 26;
+ constexpr int16_t font_medium = 27;
+ constexpr int16_t font_large = 28;
+ constexpr int16_t font_xlarge = 29;
+ constexpr float icon_scale = 0.7;
+ #else
+ constexpr int16_t font_tiny = 26;
+ constexpr int16_t font_xsmall = 26;
+ constexpr int16_t font_small = 27;
+ constexpr int16_t font_medium = 28;
+ constexpr int16_t font_large = 30;
+ constexpr int16_t font_xlarge = 31;
+ constexpr float icon_scale = 0.6;
+ #endif
+ #elif defined(TOUCH_UI_320x240)
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ constexpr int16_t font_tiny = 26;
+ constexpr int16_t font_xsmall = 26;
+ constexpr int16_t font_small = 26;
+ constexpr int16_t font_medium = 27;
+ constexpr int16_t font_large = 27;
+ constexpr int16_t font_xlarge = 28;
+ constexpr float icon_scale = 0.6;
+ #else
+ constexpr int16_t font_tiny = 26;
+ constexpr int16_t font_xsmall = 26;
+ constexpr int16_t font_small = 26;
+ constexpr int16_t font_medium = 27;
+ constexpr int16_t font_large = 29;
+ constexpr int16_t font_xlarge = 30;
+ constexpr float icon_scale = 0.5;
+ #endif
+ #endif
+}
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_landscape.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_landscape.h
new file mode 100644
index 0000000..e023599
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_landscape.h
@@ -0,0 +1,39 @@
+
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 480.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 272.000000;
+
+const PROGMEM uint16_t logo_fill[] = {0x419D, 0x546F, 0x3D05, 0x5615, 0x3942, 0x5A92, 0x36B7, 0x6136, 0x35C8, 0x6950, 0x35C8, 0x96B0, 0x36B7, 0x9ECA, 0x3942, 0xA56E, 0x3D05, 0xA9EB, 0x419D, 0xAB91, 0xBE60, 0xAB91, 0xC2F8, 0xA9EB, 0xC6BB, 0xA56E, 0xC946, 0x9ECA, 0xCA35, 0x96B0, 0xCA32, 0x546C, 0x419D, 0x546F};
+
+const PROGMEM uint16_t logo_stroke[] = {0xADF3, 0x546C, 0x419D, 0x546F, 0x3D05, 0x5615, 0x3942, 0x5A92, 0x36B7, 0x6136, 0x35C8, 0x6950, 0x35C8, 0x96B0, 0x36B7, 0x9ECA, 0x3942, 0xA56E, 0x3D05, 0xA9EB, 0x419D, 0xAB91, 0xBE60, 0xAB91, 0xC2F8, 0xA9EB, 0xC6BB, 0xA56E, 0xC946, 0x9ECA, 0xCA35, 0x96B0, 0xCA32, 0x546C, 0xADF3, 0x546C, 0xFFFF, 0x419D, 0x5913, 0xB08C, 0x5913, 0xC794, 0x8250, 0xC794, 0x96B0, 0xC6DA, 0x9CFF, 0xC4E1, 0xA229, 0xC1F4, 0xA5A5, 0xBE60, 0xA6ED, 0x419D, 0xA6ED, 0x3E09, 0xA5A5, 0x3B1C, 0xA229, 0x3923, 0x9CFF, 0x3869, 0x96B0, 0x3869, 0x6950, 0x3923, 0x6301, 0x3B1C, 0x5DD7, 0x3E09, 0x5A5B, 0x419D, 0x5913, 0xFFFF, 0xAC7A, 0x8620, 0xAC7A, 0x9373, 0xA767, 0x9373, 0xA767, 0x75CB, 0xA1C6, 0x75CB, 0xA1C6, 0x9373, 0xA1C6, 0x9C8E, 0xA767, 0x9C8E, 0xAC7A, 0x9C8E, 0xB21C, 0x9C8E, 0xB21C, 0x9373, 0xB21C, 0x85E7, 0xB350, 0x8093, 0xB65F, 0x7E86, 0xB9D5, 0x8165, 0xBA83, 0x85E7, 0xBA83, 0x9C8E, 0xBEFE, 0x9C8E, 0xC024, 0x99E1, 0xC024, 0x8620, 0xBF7B, 0x7F22, 0xBD8F, 0x79A9, 0xBA7E, 0x7617, 0xB65F, 0x74D0, 0xB24F, 0x7622, 0xAF30, 0x79C6, 0xAD2F, 0x7F43, 0xAC7A, 0x8620, 0xAC7A, 0x8620, 0xAC7A, 0x8620, 0xFFFF, 0x8179, 0x9C8E, 0x7CE9, 0x9C8E, 0x7747, 0x9C8E, 0x7747, 0x92EC, 0x7747, 0x8949, 0x75A2, 0x81A3, 0x71A6, 0x7E73, 0x6DAB, 0x818B, 0x6C05, 0x88FC, 0x6DAF, 0x9019, 0x71C7, 0x92EC, 0x7505, 0x92EC, 0x7505, 0x9C8E, 0x7118, 0x9C8E, 0x6CD3, 0x9B06, 0x696B, 0x96D6, 0x6729, 0x909E, 0x6658, 0x88FC, 0x672D, 0x8133, 0x6980, 0x7AC7, 0x6D13, 0x766C, 0x71A6, 0x74D0, 0x7632, 0x766D, 0x79C2, 0x7AD1, 0x7C14, 0x8153, 0x7CE9, 0x8949, 0x7CE9, 0x92EC, 0x8179, 0x92EC, 0x8179, 0x8620, 0x822E, 0x7F43, 0x842E, 0x79C6, 0x874E, 0x7622, 0x8B5E, 0x74D0, 0x8F7C, 0x7617, 0x928E, 0x79A9, 0x9479, 0x7F22, 0x9523, 0x8620, 0x9523, 0x87DB, 0x8F81, 0x87DB, 0x8F81, 0x85E7, 0x8ED4, 0x8165, 0x8B5E, 0x7E86, 0x884F, 0x8093, 0x871A, 0x85E7, 0x871A, 0x92EC, 0x871A, 0x9C8F, 0x8179, 0x9C8F, 0x8179, 0x9C8E, 0x8179, 0x9C8E, 0xFFFF, 0x6515, 0x79DB, 0x644C, 0x7281, 0x6218, 0x6C86, 0x5EB2, 0x6882, 0x5A56, 0x670A, 0x55D9, 0x68E0, 0x5272, 0x6DD0, 0x4F0B, 0x68E0, 0x4A8E, 0x670A, 0x4638, 0x6882, 0x42D5, 0x6C86, 0x40A2, 0x7281, 0x3FD9, 0x79DB, 0x3FD9, 0x9AC9, 0x40E4, 0x9C8E, 0x456F, 0x9C8E, 0x456F, 0x79B5, 0x46D4, 0x735D, 0x4A8E, 0x70C0, 0x4E3E, 0x735D, 0x4FA1, 0x79B5, 0x4FA1, 0x9C8E, 0x554D, 0x9C8E, 0x554D, 0x79B5, 0x56A7, 0x735D, 0x5A56, 0x70C0, 0x5E0C, 0x735D, 0x5F74, 0x79B5, 0x5F74, 0x9C8E, 0x6515, 0x9C8E, 0x6515, 0x79DB, 0x6515, 0x79DB, 0x6515, 0x79DB, 0xFFFF, 0x9672, 0x8C4C, 0x9714, 0x9379, 0x98F5, 0x98D2, 0x9C0B, 0x9BF4, 0xA04C, 0x9C7B, 0xA04C, 0x9373, 0x9D2B, 0x920C, 0x9C1E, 0x8C4C, 0x9C1E, 0x648E, 0x9672, 0x648E, 0x9672, 0x8C4C, 0x9672, 0x8C4C, 0x9672, 0x8C4C, 0xFFFF, 0xA767, 0x7194, 0xA767, 0x6C02, 0xA692, 0x687A, 0xA496, 0x670A, 0xA291, 0x687A, 0xA1BB, 0x6C02, 0xA1BB, 0x7194, 0xA767, 0x7194, 0xA767, 0x7194, 0xA767, 0x7194};
+
+#define LOGO_BACKGROUND logo_bg_rgb
+#define LOGO_PAINT_PATHS \
+ LOGO_PAINT_PATH(logo_fill_rgb, logo_fill) \
+ LOGO_PAINT_PATH(logo_stroke_rgb, logo_stroke)
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_portrait.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_portrait.h
new file mode 100644
index 0000000..e3a30a6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_portrait.h
@@ -0,0 +1,39 @@
+
+/****************************************************************************
+ * 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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 272.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 480.000000;
+
+const PROGMEM uint16_t logo_fill[] = {0x3C19, 0x70C5, 0x371A, 0x7159, 0x3302, 0x72EA, 0x303D, 0x753C, 0x2F39, 0x7811, 0x2F39, 0x87ED, 0x303D, 0x8AC2, 0x3302, 0x8D14, 0x371A, 0x8EA5, 0x3C19, 0x8F39, 0xC3E4, 0x8F39, 0xC8E3, 0x8EA5, 0xCCFB, 0x8D14, 0xCFC0, 0x8AC2, 0xD0C4, 0x87ED, 0xD0C0, 0x70C4, 0x3C19, 0x70C5};
+
+const PROGMEM uint16_t logo_stroke[] = {0x3C19, 0x70C5, 0x371A, 0x7159, 0x3302, 0x72EA, 0x303D, 0x753C, 0x2F39, 0x7811, 0x2F39, 0x87ED, 0x303D, 0x8AC2, 0x3302, 0x8D14, 0x371A, 0x8EA5, 0x3C19, 0x8F39, 0xC3E4, 0x8F39, 0xC8E3, 0x8EA5, 0xCCFB, 0x8D14, 0xCFC0, 0x8AC2, 0xD0C4, 0x87ED, 0xD0C0, 0x70C4, 0x3C19, 0x70C5, 0xFFFF, 0x3C19, 0x7264, 0xB4D6, 0x7264, 0xCDE7, 0x80CE, 0xCDE7, 0x87ED, 0xCD1D, 0x8A21, 0xCAF7, 0x8BEF, 0xC7C8, 0x8D27, 0xC3E4, 0x8D9A, 0x3C19, 0x8D9A, 0x3835, 0x8D27, 0x3506, 0x8BEF, 0x32E0, 0x8A21, 0x3216, 0x87ED, 0x3216, 0x7811, 0x32E0, 0x75DD, 0x3506, 0x740F, 0x3835, 0x72D7, 0x3C19, 0x7264, 0xFFFF, 0xB069, 0x8223, 0xB069, 0x86CB, 0xAAE2, 0x86CB, 0xAAE2, 0x7C6E, 0xA4C2, 0x7C6E, 0xA4C2, 0x86CB, 0xA4C2, 0x89FA, 0xAAE2, 0x89FA, 0xB069, 0x89FA, 0xB689, 0x89FA, 0xB689, 0x86CB, 0xB689, 0x820F, 0xB7D9, 0x8033, 0xBB2E, 0x7F7B, 0xBEF2, 0x807C, 0xBFAE, 0x820F, 0xBFAE, 0x89FA, 0xC48F, 0x89FA, 0xC5CF, 0x890A, 0xC5CF, 0x8223, 0xC517, 0x7FB2, 0xC300, 0x7DC8, 0xBFA9, 0x7C88, 0xBB2E, 0x7C16, 0xB6C1, 0x7C8C, 0xB35B, 0x7DD2, 0xB12D, 0x7FBD, 0xB069, 0x8223, 0xB069, 0x8223, 0xB069, 0x8223, 0xFFFF, 0x819B, 0x89FA, 0x7CA3, 0x89FA, 0x7682, 0x89FA, 0x7682, 0x869C, 0x7682, 0x833E, 0x74B7, 0x8092, 0x7062, 0x7F74, 0x6C0C, 0x8089, 0x6A41, 0x8323, 0x6C10, 0x859F, 0x7085, 0x869C, 0x740C, 0x869C, 0x740C, 0x89FA, 0x6FC7, 0x89FA, 0x6B21, 0x8971, 0x676C, 0x87FA, 0x64F8, 0x85CE, 0x6414, 0x8323, 0x64FC, 0x806A, 0x6784, 0x7E2C, 0x6B67, 0x7CA6, 0x7062, 0x7C16, 0x7555, 0x7CA6, 0x7935, 0x7E2F, 0x7BBC, 0x8076, 0x7CA3, 0x833E, 0x7CA3, 0x869C, 0x819A, 0x869C, 0x819A, 0x8223, 0x825F, 0x7FBD, 0x848D, 0x7DD2, 0x87F3, 0x7C8C, 0x8C60, 0x7C16, 0x90DB, 0x7C88, 0x9432, 0x7DC8, 0x9648, 0x7FB2, 0x9701, 0x8223, 0x9701, 0x82BE, 0x90E0, 0x82BE, 0x90E0, 0x820F, 0x9024, 0x807C, 0x8C60, 0x7F7B, 0x890B, 0x8033, 0x87BB, 0x820F, 0x87BB, 0x869C, 0x87BB, 0x89FA, 0x819B, 0x89FA, 0x819B, 0x89FA, 0x819B, 0x89FA, 0xFFFF, 0x62B5, 0x7DD9, 0x61DA, 0x7B47, 0x5F73, 0x7931, 0x5BC1, 0x77C9, 0x5702, 0x7746, 0x521F, 0x77EA, 0x4E6B, 0x79A4, 0x4AB8, 0x77EA, 0x45D5, 0x7746, 0x411D, 0x77C9, 0x3D6E, 0x7931, 0x3B09, 0x7B47, 0x3A2E, 0x7DD9, 0x3A2E, 0x895C, 0x3B51, 0x89FA, 0x4043, 0x89FA, 0x4043, 0x7DCC, 0x41C6, 0x7B95, 0x45D5, 0x7AAB, 0x49D9, 0x7B95, 0x4B5B, 0x7DCC, 0x4B5B, 0x89FA, 0x5188, 0x89FA, 0x5188, 0x7DCC, 0x52FF, 0x7B95, 0x5702, 0x7AAB, 0x5B0C, 0x7B95, 0x5C94, 0x7DCC, 0x5C94, 0x89FA, 0x62B5, 0x89FA, 0x62B5, 0x7DD9, 0x62B5, 0x7DD9, 0x62B5, 0x7DD9, 0xFFFF, 0x986E, 0x844B, 0x991E, 0x86CD, 0x9B2A, 0x88AC, 0x9E85, 0x89C4, 0xA327, 0x89F3, 0xA327, 0x86CB, 0x9FBF, 0x864E, 0x9E9A, 0x844B, 0x9E9A, 0x7668, 0x986E, 0x7668, 0x986E, 0x844B, 0x986E, 0x844B, 0x986E, 0x844B, 0xFFFF, 0xAAE2, 0x7AF5, 0xAAE2, 0x7902, 0xA9FB, 0x77C7, 0xA7D2, 0x7746, 0xA59F, 0x77C7, 0xA4B6, 0x7902, 0xA4B6, 0x7AF5, 0xAAE2, 0x7AF5, 0xAAE2, 0x7AF5, 0xAAE2, 0x7AF5};
+
+#define LOGO_BACKGROUND logo_bg_rgb
+#define LOGO_PAINT_PATHS \
+ LOGO_PAINT_PATH(logo_fill_rgb, logo_fill) \
+ LOGO_PAINT_PATH(logo_stroke_rgb, logo_stroke)
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.cpp
new file mode 100644
index 0000000..afbed0c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.cpp
@@ -0,0 +1,410 @@
+/**************
+ * sounds.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../compat.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "../ftdi_eve_lib/ftdi_eve_lib.h"
+
+#include "sounds.h"
+
+namespace Theme {
+ using namespace FTDI;
+
+ const PROGMEM SoundPlayer::sound_t chimes[] = {
+ {CHIMES, NOTE_G3, 5},
+ {CHIMES, NOTE_E4, 5},
+ {CHIMES, NOTE_C4, 5},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t sad_trombone[] = {
+ {TRUMPET, NOTE_A3S, 10},
+ {TRUMPET, NOTE_A3 , 10},
+ {TRUMPET, NOTE_G3S, 10},
+ {TRUMPET, NOTE_G3, 20},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t twinkle[] = {
+ {GLOCKENSPIEL, NOTE_C4, 1},
+ {GLOCKENSPIEL, NOTE_E4, 1},
+ {GLOCKENSPIEL, NOTE_G4, 16},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t fanfare[] = {
+ {TRUMPET, NOTE_A3, 4},
+ {SILENCE, REST, 1},
+ {TRUMPET, NOTE_A3, 2},
+ {SILENCE, REST, 1},
+ {TRUMPET, NOTE_A3, 2},
+ {SILENCE, REST, 1},
+ {TRUMPET, NOTE_E4, 10},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t media_inserted[] = {
+ {MUSIC_BOX, NOTE_C4, 2},
+ {MUSIC_BOX, NOTE_E4, 2},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t media_removed[] = {
+ {MUSIC_BOX, NOTE_E4, 2},
+ {MUSIC_BOX, NOTE_C4, 2},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t js_bach_toccata[] = {
+ {ORGAN, NOTE_A4, 2},
+ {ORGAN, NOTE_G4, 2},
+ {ORGAN, NOTE_A4, 35},
+ {SILENCE, REST, 12},
+ {ORGAN, NOTE_G4, 4},
+ {ORGAN, NOTE_F4, 4},
+ {ORGAN, NOTE_E4, 4},
+ {ORGAN, NOTE_D4, 4},
+ {ORGAN, NOTE_C4S, 16},
+ {ORGAN, NOTE_D4, 32},
+ {SILENCE, REST, 42},
+
+ {ORGAN, NOTE_A3, 2},
+ {ORGAN, NOTE_G3, 2},
+ {ORGAN, NOTE_A3, 35},
+ {SILENCE, REST, 9},
+ {ORGAN, NOTE_E3, 8},
+ {ORGAN, NOTE_F3, 8},
+ {ORGAN, NOTE_C3S, 16},
+ {ORGAN, NOTE_D3, 27},
+ {SILENCE, REST, 42},
+
+ {ORGAN, NOTE_A2, 2},
+ {ORGAN, NOTE_G2, 2},
+ {ORGAN, NOTE_A2, 35},
+ {SILENCE, REST, 12},
+ {ORGAN, NOTE_G2, 4},
+ {ORGAN, NOTE_F2, 4},
+ {ORGAN, NOTE_E2, 4},
+ {ORGAN, NOTE_D2, 4},
+ {ORGAN, NOTE_C2S, 16},
+ {ORGAN, NOTE_D2, 32},
+ {SILENCE, REST, 52},
+
+ //{ORGAN, NOTE_D1, 28},
+ {ORGAN, NOTE_C3S, 9},
+ {ORGAN, NOTE_E3, 9},
+ {ORGAN, NOTE_G3, 9},
+ {ORGAN, NOTE_A3S, 9},
+ {ORGAN, NOTE_C4S, 9},
+ {ORGAN, NOTE_E4, 9},
+ {ORGAN, NOTE_D4, 20},
+ {SILENCE, REST, 30},
+
+ {ORGAN, NOTE_C4S, 4},
+ {ORGAN, NOTE_D4, 2},
+ {ORGAN, NOTE_E4, 2},
+
+ {ORGAN, NOTE_C4S, 2},
+ {ORGAN, NOTE_D4, 2},
+ {ORGAN, NOTE_E4, 2},
+
+ {ORGAN, NOTE_C4S, 2},
+ {ORGAN, NOTE_D4, 2},
+ {ORGAN, NOTE_E4, 2},
+
+ {ORGAN, NOTE_C4S, 2},
+ {ORGAN, NOTE_D4, 4},
+ {ORGAN, NOTE_E4, 4},
+ {ORGAN, NOTE_F4, 2},
+ {ORGAN, NOTE_G4, 2},
+
+ {ORGAN, NOTE_E4, 2},
+ {ORGAN, NOTE_F4, 2},
+ {ORGAN, NOTE_G4, 2},
+
+ {ORGAN, NOTE_E4, 2},
+ {ORGAN, NOTE_F4, 2},
+ {ORGAN, NOTE_G4, 2},
+
+ {ORGAN, NOTE_E4, 2},
+ {ORGAN, NOTE_F4, 4},
+ {ORGAN, NOTE_G4, 4},
+ {ORGAN, NOTE_A4, 2},
+ {ORGAN, NOTE_A4S, 2},
+
+ {ORGAN, NOTE_G4, 2},
+ {ORGAN, NOTE_A4, 2},
+ {ORGAN, NOTE_A4S, 2},
+
+ {ORGAN, NOTE_G4, 2},
+ {ORGAN, NOTE_A4, 2},
+ {ORGAN, NOTE_A4S, 2},
+
+ {ORGAN, NOTE_G4, 2},
+ {ORGAN, NOTE_A4, 4},
+ {SILENCE, REST, 36},
+
+
+ {ORGAN, NOTE_C5S, 4},
+ {ORGAN, NOTE_D5, 2},
+ {ORGAN, NOTE_E5, 2},
+
+ {ORGAN, NOTE_C5S, 2},
+ {ORGAN, NOTE_D5, 2},
+ {ORGAN, NOTE_E5, 2},
+
+ {ORGAN, NOTE_C5S, 2},
+ {ORGAN, NOTE_D5, 2},
+ {ORGAN, NOTE_E5, 2},
+
+ {ORGAN, NOTE_C5S, 2},
+ {ORGAN, NOTE_D5, 4},
+ {ORGAN, NOTE_E5, 4},
+ {ORGAN, NOTE_F5, 2},
+ {ORGAN, NOTE_G5, 2},
+
+ {ORGAN, NOTE_E5, 2},
+ {ORGAN, NOTE_F5, 2},
+ {ORGAN, NOTE_G5, 2},
+
+ {ORGAN, NOTE_E5, 2},
+ {ORGAN, NOTE_F5, 2},
+ {ORGAN, NOTE_G5, 2},
+
+ {ORGAN, NOTE_E5, 2},
+ {ORGAN, NOTE_F5, 4},
+ {ORGAN, NOTE_G5, 4},
+ {ORGAN, NOTE_A5, 2},
+ {ORGAN, NOTE_A5S, 2},
+
+ {ORGAN, NOTE_G5, 2},
+ {ORGAN, NOTE_A5, 2},
+ {ORGAN, NOTE_A5S, 2},
+
+ {ORGAN, NOTE_G5, 2},
+ {ORGAN, NOTE_A5, 2},
+ {ORGAN, NOTE_A5S, 2},
+
+ {ORGAN, NOTE_G5, 2},
+ {ORGAN, NOTE_A5, 4},
+ {SILENCE, REST, 32},
+
+ {ORGAN, NOTE_A5, 4},
+ {ORGAN, NOTE_G5, 2},
+ {ORGAN, NOTE_A5S, 2},
+
+ {ORGAN, NOTE_E5, 2},
+ {ORGAN, NOTE_G5, 2},
+ {ORGAN, NOTE_A5S, 2},
+
+ {ORGAN, NOTE_E5, 2},
+ {ORGAN, NOTE_F5, 2},
+ {ORGAN, NOTE_A5, 2},
+
+ {ORGAN, NOTE_D5, 2},
+ {ORGAN, NOTE_F5, 2},
+ {ORGAN, NOTE_G5, 2},
+
+ {ORGAN, NOTE_D5, 2},
+ {ORGAN, NOTE_E5, 2},
+ {ORGAN, NOTE_A5, 2},
+
+ {ORGAN, NOTE_C5, 2},
+ {ORGAN, NOTE_E5, 2},
+ {ORGAN, NOTE_A5, 2},
+
+ {ORGAN, NOTE_C5, 2},
+ {ORGAN, NOTE_D5, 2},
+ {ORGAN, NOTE_F5, 2},
+
+ {ORGAN, NOTE_A4S, 2},
+ {ORGAN, NOTE_D5, 2},
+ {ORGAN, NOTE_E5, 2},
+
+ {ORGAN, NOTE_A4S, 2},
+ {ORGAN, NOTE_C5, 2},
+ {ORGAN, NOTE_E5, 2},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t js_bach_joy[] = {
+ {PIANO, NOTE_G3, 4},
+ {PIANO, NOTE_A3, 4},
+ {PIANO, NOTE_B3, 4},
+ {PIANO, NOTE_D4, 3},
+ {SILENCE, REST, 1},
+
+ {PIANO, NOTE_C4, 3},
+ {SILENCE, REST, 1},
+ {PIANO, NOTE_C4, 4},
+ {PIANO, NOTE_E4, 3},
+ {SILENCE, REST, 1},
+ {PIANO, NOTE_D4, 2},
+ {SILENCE, REST, 2},
+
+ {PIANO, NOTE_D4, 4},
+ {PIANO, NOTE_G4 , 3},
+ {SILENCE, REST, 1},
+ {PIANO, NOTE_F4S, 4},
+ {PIANO, NOTE_G4, 4},
+
+ {PIANO, NOTE_D4, 2},
+ {SILENCE, REST, 2},
+ {PIANO, NOTE_B3, 3},
+ {SILENCE, REST, 1},
+ {PIANO, NOTE_G3, 4},
+ {PIANO, NOTE_A3, 2},
+ {SILENCE, REST, 2},
+
+ {PIANO, NOTE_B3, 2},
+ {SILENCE, REST, 2},
+ {PIANO, NOTE_C4, 4},
+ {PIANO, NOTE_D4, 2},
+ {SILENCE, REST, 2},
+ {PIANO, NOTE_E4, 2},
+ {SILENCE, REST, 2},
+
+ {PIANO, NOTE_D4, 4},
+ {PIANO, NOTE_C4, 2},
+ {SILENCE, REST, 2},
+ {PIANO, NOTE_B3, 2},
+ {SILENCE, REST, 2},
+ {PIANO, NOTE_A3, 4},
+
+ {PIANO, NOTE_B3, 2},
+ {SILENCE, REST, 2},
+ {PIANO, NOTE_G3, 2},
+ {SILENCE, REST, 2},
+ {PIANO, NOTE_G3, 8},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t big_band[] = {
+ {XYLOPHONE, NOTE_F4, 3},
+ {XYLOPHONE, NOTE_G4, 3},
+ {XYLOPHONE, NOTE_F4, 3},
+ {XYLOPHONE, NOTE_D4, 3},
+ {XYLOPHONE, NOTE_A3S, 3},
+ {SILENCE, REST, 3},
+
+ {TRUMPET, NOTE_F4, 3},
+ {TRUMPET, NOTE_G4, 3},
+ {TRUMPET, NOTE_F4, 3},
+ {TRUMPET, NOTE_D4, 3},
+ {TRUMPET, NOTE_A3S, 3},
+ {SILENCE, REST, 3},
+
+ {TUBA, NOTE_A2S, 6},
+ {TUBA, NOTE_A2S, 6},
+ {TUBA, NOTE_A2S, 4},
+ {TUBA, NOTE_A2S, 6},
+ {TUBA, NOTE_A2S, 6},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t beats[] = {
+ {SILENCE, REST, 8},
+ {NOTCH, NOTE_C4, 8},
+ {KICKDRUM, NOTE_C4, 8},
+ {HIHAT, NOTE_C4, 8},
+ {COWBELL, NOTE_C4, 8},
+ {SILENCE, REST, 8},
+ {NOTCH, NOTE_C4, 8},
+ {KICKDRUM, NOTE_C4, 8},
+ {HIHAT, NOTE_C4, 8},
+ {COWBELL, NOTE_C4, 8},
+ {SILENCE, REST, 8},
+ {NOTCH, NOTE_C4, 8},
+ {KICKDRUM, NOTE_C4, 8},
+ {HIHAT, NOTE_C4, 8},
+ {COWBELL, NOTE_C4, 8},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t beeping[] = {
+ {BEEPING, NOTE_C4, 64},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t alarm[] = {
+ {ALARM, NOTE_C4, 64},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t warble[] = {
+ {WARBLE, NOTE_C4, 64},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t carousel[] = {
+ {CAROUSEL, NOTE_C4, 64},
+ {SILENCE, END_SONG, 0}
+ };
+
+ const PROGMEM SoundPlayer::sound_t all_instruments[] = {
+ {HARP},
+ {XYLOPHONE},
+ {TUBA},
+ {GLOCKENSPIEL},
+ {ORGAN},
+ {TRUMPET},
+ {PIANO},
+ {CHIMES},
+ {MUSIC_BOX},
+ {BELL},
+ {CLICK},
+ {SWITCH},
+ {COWBELL},
+ {NOTCH},
+ {HIHAT},
+ {KICKDRUM},
+ {SWITCH},
+ {POP},
+ {CLACK},
+ {CHACK},
+ {SILENCE, END_SONG, 0}
+ };
+}; // namespace Theme
+
+#define N_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
+
+const SoundList::list_t SoundList::list[] = {
+ {"Silence", FTDI::silence},
+ {"Twinkle", Theme::twinkle},
+ {"Chimes", Theme::chimes},
+ {"Fanfare", Theme::fanfare},
+ {"Sad Trombone", Theme::sad_trombone},
+ {"Big Band", Theme::big_band},
+ {"Beeping", Theme::beeping},
+ {"Alarm", Theme::alarm},
+ {"Warble", Theme::warble},
+ {"Carousel", Theme::carousel},
+ {"Beats", Theme::beats},
+ {"Bach Joy", Theme::js_bach_joy},
+ {"Bach Toccata", Theme::js_bach_toccata}
+};
+
+const uint8_t SoundList::n = N_ELEMENTS(SoundList::list);
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.h
new file mode 100644
index 0000000..66c1cb8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.h
@@ -0,0 +1,43 @@
+/************
+ * sounds.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+namespace Theme {
+ using namespace FTDI;
+
+ extern const PROGMEM SoundPlayer::sound_t chimes[];
+ extern const PROGMEM SoundPlayer::sound_t sad_trombone[];
+ extern const PROGMEM SoundPlayer::sound_t twinkle[];
+ extern const PROGMEM SoundPlayer::sound_t fanfare[];
+ extern const PROGMEM SoundPlayer::sound_t media_inserted[];
+ extern const PROGMEM SoundPlayer::sound_t media_removed[];
+ extern const PROGMEM SoundPlayer::sound_t js_bach_toccata[];
+ extern const PROGMEM SoundPlayer::sound_t js_bach_joy[];
+ extern const PROGMEM SoundPlayer::sound_t big_band[];
+ extern const PROGMEM SoundPlayer::sound_t beats[];
+ extern const PROGMEM SoundPlayer::sound_t beeping[];
+ extern const PROGMEM SoundPlayer::sound_t alarm[];
+ extern const PROGMEM SoundPlayer::sound_t warble[];
+ extern const PROGMEM SoundPlayer::sound_t carousel[];
+ extern const PROGMEM SoundPlayer::sound_t all_instruments[];
+}; // namespace Theme
diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/theme.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/theme.h
new file mode 100644
index 0000000..e0f0f31
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/theme.h
@@ -0,0 +1,28 @@
+/***********
+ * theme.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#pragma once
+
+#include "bitmaps.h"
+#include "colors.h"
+#include "fonts.h"
+#include "sounds.h"
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp
new file mode 100644
index 0000000..8685bf1
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp
@@ -0,0 +1,303 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "../../../../inc/MarlinConfig.h"
+#include "SPIFlashStorage.h"
+
+extern W25QXXFlash W25QXX;
+
+uint8_t SPIFlashStorage::m_pageData[SPI_FLASH_PageSize];
+uint32_t SPIFlashStorage::m_currentPage;
+uint16_t SPIFlashStorage::m_pageDataUsed;
+uint32_t SPIFlashStorage::m_startAddress;
+
+#if HAS_SPI_FLASH_COMPRESSION
+
+ uint8_t SPIFlashStorage::m_compressedData[SPI_FLASH_PageSize];
+ uint16_t SPIFlashStorage::m_compressedDataUsed;
+
+ template <typename T>
+ static uint32_t rle_compress(T *output, uint32_t outputLength, T *input, uint32_t inputLength, uint32_t& inputProcessed) {
+ uint32_t count = 0, out = 0, index, i;
+ T pixel;
+ //32767 for uint16_t
+ //127 for uint16_t
+ //calculated at compile time
+ constexpr T max = (0xFFFFFFFF >> (8 * (4 - sizeof(T)))) / 2;
+
+ inputProcessed = 0;
+ while (count < inputLength && out < outputLength) {
+ index = count;
+ pixel = input[index++];
+ while (index < inputLength && index - count < max && input[index] == pixel)
+ index++;
+ if (index - count == 1) {
+ /*
+ * Failed to "replicate" the current pixel. See how many to copy.
+ * Avoid a replicate run of only 2-pixels after a literal run. There
+ * is no gain in this, and there is a risK of loss if the run after
+ * the two identical pixels is another literal run. So search for
+ * 3 identical pixels.
+ */
+ while (index < inputLength && index - count < max && (input[index] != input[index - 1] || (index > 1 && input[index] != input[index - 2])))
+ index++;
+ /*
+ * Check why this run stopped. If it found two identical pixels, reset
+ * the index so we can add a run. Do this twice: the previous run
+ * tried to detect a replicate run of at least 3 pixels. So we may be
+ * able to back up two pixels if such a replicate run was found.
+ */
+ while (index < inputLength && input[index] == input[index - 1])
+ index--;
+ // If the output buffer could overflow, stop at the remaining bytes
+ NOMORE(index, count + outputLength - out - 1);
+ output[out++] = (uint16_t)(count - index);
+ for (i = count; i < index; i++)
+ output[out++] = input[i];
+ }
+ else {
+ // Need at least more 2 spaces
+ if (out > outputLength - 2) break;
+ output[out++] = (uint16_t)(index - count);
+ output[out++] = pixel;
+ }
+ count = index;
+ }
+ inputProcessed = count;
+
+ // Padding
+ if (out == outputLength - 1) output[out++] = 0;
+
+ return out;
+ }
+
+ template <typename UT, typename T>
+ static uint32_t rle_uncompress(UT *output, uint32_t outputLength, UT *input, uint32_t inputLength, uint32_t &outputFilled) {
+ T count;
+ UT i;
+ uint32_t processedBytes = 0;
+ outputFilled = 0;
+
+ while (outputLength > 0 && inputLength > 0) {
+ processedBytes++;
+ count = static_cast<T>(*input++);
+ inputLength--;
+ if (count > 0) { // Replicate run
+ for (i = 0; i < count && outputLength > i; i++)
+ output[i] = *input;
+ outputFilled += i;
+ // If copy incomplete, change the input buffer to start with remaining data in the next call
+ if (i < count) {
+ // Change to process the difference in the next call
+ *(input - 1) = static_cast<UT>(count - i);
+ return processedBytes - 1;
+ }
+ input++;
+ inputLength--;
+ processedBytes++;
+ }
+ else if (count < 0) { // literal run
+ count = static_cast<T>(-count);
+ // Copy, validating if the output have enough space
+ for (i = 0; i < count && outputLength > i; i++)
+ output[i] = input[i];
+ outputFilled += i;
+ // If copy incomplete, change the input buffer to start with remaining data in the next call
+ if (i < count) {
+ input[i - 1] = static_cast<UT>((count - i) * -1);
+ // Back one
+ return processedBytes + i - 1;
+ }
+ input += count;
+ inputLength -= count;
+ processedBytes += count;
+ }
+ output += count;
+ outputLength -= count;
+ }
+
+ return processedBytes;
+ }
+
+#endif // HAS_SPI_FLASH_COMPRESSION
+
+void SPIFlashStorage::beginWrite(uint32_t startAddress) {
+ m_pageDataUsed = 0;
+ m_currentPage = 0;
+ m_startAddress = startAddress;
+ #if HAS_SPI_FLASH_COMPRESSION
+ // Restart the compressed buffer, keep the pointers of the uncompressed buffer
+ m_compressedDataUsed = 0;
+ #endif
+}
+
+
+void SPIFlashStorage::endWrite() {
+ // Flush remaining data
+ #if HAS_SPI_FLASH_COMPRESSION
+ if (m_compressedDataUsed > 0) {
+ flushPage();
+ savePage(m_compressedData);
+ }
+ #else
+ if (m_pageDataUsed > 0) flushPage();
+ #endif
+}
+
+void SPIFlashStorage::savePage(uint8_t* buffer) {
+ W25QXX.SPI_FLASH_BufferWrite(buffer, m_startAddress + (SPI_FLASH_PageSize * m_currentPage), SPI_FLASH_PageSize);
+}
+
+void SPIFlashStorage::loadPage(uint8_t* buffer) {
+ W25QXX.SPI_FLASH_BufferRead(buffer, m_startAddress + (SPI_FLASH_PageSize * m_currentPage), SPI_FLASH_PageSize);
+}
+
+void SPIFlashStorage::flushPage() {
+ #if HAS_SPI_FLASH_COMPRESSION
+ // Work com with compressed in memory
+ uint32_t inputProcessed;
+ uint32_t compressedSize = rle_compress<uint16_t>((uint16_t *)(m_compressedData + m_compressedDataUsed), compressedDataFree() / 2, (uint16_t *)m_pageData, m_pageDataUsed / 2, inputProcessed) * 2;
+ inputProcessed *= 2;
+ m_compressedDataUsed += compressedSize;
+
+ // Space remaining in the compressed buffer?
+ if (compressedDataFree() > 0) {
+ // Free the uncompressed buffer
+ m_pageDataUsed = 0;
+ return;
+ }
+
+ // Part of the m_pageData was compressed, so ajust the pointers, freeing what was processed, shift the buffer
+ // TODO: To avoid this copy, use a circular buffer
+ memmove(m_pageData, m_pageData + inputProcessed, m_pageDataUsed - inputProcessed);
+ m_pageDataUsed -= inputProcessed;
+
+ // No? So flush page with compressed data!!
+ uint8_t *buffer = m_compressedData;
+ #else
+ uint8_t *buffer = m_pageData;
+ #endif
+
+ savePage(buffer);
+
+ #if HAS_SPI_FLASH_COMPRESSION
+ // Restart the compressed buffer, keep the pointers of the uncompressed buffer
+ m_compressedDataUsed = 0;
+ #else
+ m_pageDataUsed = 0;
+ #endif
+ m_currentPage++;
+}
+
+void SPIFlashStorage::readPage() {
+ #if HAS_SPI_FLASH_COMPRESSION
+ if (compressedDataFree() == 0) {
+ loadPage(m_compressedData);
+ m_currentPage++;
+ m_compressedDataUsed = 0;
+ }
+
+ // Need to uncompress data
+ if (pageDataFree() == 0) {
+ m_pageDataUsed = 0;
+ uint32_t outpuProcessed = 0;
+ uint32_t inputProcessed = rle_uncompress<uint16_t, int16_t>((uint16_t *)(m_pageData + m_pageDataUsed), pageDataFree() / 2, (uint16_t *)(m_compressedData + m_compressedDataUsed), compressedDataFree() / 2, outpuProcessed);
+ inputProcessed *= 2;
+ outpuProcessed *= 2;
+ if (outpuProcessed < pageDataFree()) {
+ m_pageDataUsed = SPI_FLASH_PageSize - outpuProcessed;
+ // TODO: To avoid this copy, use a circular buffer
+ memmove(m_pageData + m_pageDataUsed, m_pageData, outpuProcessed);
+ }
+
+ m_compressedDataUsed += inputProcessed;
+ }
+ #else
+ loadPage(m_pageData);
+ m_pageDataUsed = 0;
+ m_currentPage++;
+ #endif
+}
+
+uint16_t SPIFlashStorage::inData(uint8_t* data, uint16_t size) {
+ // Don't write more than we can
+ NOMORE(size, pageDataFree());
+ memcpy(m_pageData + m_pageDataUsed, data, size);
+ m_pageDataUsed += size;
+ return size;
+}
+
+void SPIFlashStorage::writeData(uint8_t* data, uint16_t size) {
+ // Flush a page if needed
+ if (pageDataFree() == 0) flushPage();
+
+ while (size > 0) {
+ uint16_t written = inData(data, size);
+ size -= written;
+ // Need to write more? Flush page and continue!
+ if (size > 0) {
+ flushPage();
+ data += written;
+ }
+ }
+}
+
+void SPIFlashStorage::beginRead(uint32_t startAddress) {
+ m_startAddress = startAddress;
+ m_currentPage = 0;
+ // Nothing in memory now
+ m_pageDataUsed = SPI_FLASH_PageSize;
+ #if HAS_SPI_FLASH_COMPRESSION
+ m_compressedDataUsed = sizeof(m_compressedData);
+ #endif
+}
+
+uint16_t SPIFlashStorage::outData(uint8_t* data, uint16_t size) {
+ // Don't read more than we have
+ NOMORE(size, pageDataFree());
+ memcpy(data, m_pageData + m_pageDataUsed, size);
+ m_pageDataUsed += size;
+ return size;
+}
+
+void SPIFlashStorage::readData(uint8_t* data, uint16_t size) {
+ // Read a page if needed
+ if (pageDataFree() == 0) readPage();
+
+ while (size > 0) {
+ uint16_t read = outData(data, size);
+ size -= read;
+ // Need to write more? Flush page and continue!
+ if (size > 0) {
+ readPage();
+ data += read;
+ }
+ }
+}
+
+SPIFlashStorage SPIFlash;
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h
new file mode 100644
index 0000000..98c8067
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h
@@ -0,0 +1,108 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../../../../libs/W25Qxx.h"
+
+#define HAS_SPI_FLASH_COMPRESSION 1
+
+/**
+ * This class manages and optimizes SPI Flash data storage,
+ * keeping an internal buffer to write and save full SPI flash
+ * pages as needed.
+ *
+ * Since the data is always in the buffer, the class is also
+ * able to support fast on-the-fly RLE compression/decompression.
+ *
+ * In testing with the current LVGL_UI it compacts 2.9MB of icons
+ * (which have lots of runs) down to 370kB!!! As a result the UI
+ * refresh rate becomes faster and now all LVGL UI can fit into a
+ * tiny 2MB SPI Flash, such as the Chitu Board.
+ *
+ * == Usage ==
+ *
+ * Writing:
+ *
+ * The class keeps an internal buffer that caches data until it
+ * fits into a full SPI Flash page. Each time the buffer fills up
+ * the page is saved to SPI Flash. Sequential writes are optimal.
+ *
+ * SPIFlashStorage.beginWrite(myStartAddress);
+ * while (there is data to write)
+ * SPIFlashStorage.addData(myBuffer, bufferSize);
+ * SPIFlashStorage.endWrite(); // Flush remaining buffer data
+ *
+ * Reading:
+ *
+ * When reading, it loads a full page from SPI Flash at once and
+ * keeps it in a private SRAM buffer. Data is loaded as needed to
+ * fullfill requests. Sequential reads are optimal.
+ *
+ * SPIFlashStorage.beginRead(myStartAddress);
+ * while (there is data to read)
+ * SPIFlashStorage.readData(myBuffer, bufferSize);
+ *
+ * Compression:
+ *
+ * The biggest advantage of this class is the RLE compression.
+ * With compression activated a second buffer holds the compressed
+ * data, so when writing data, as this buffer becomes full it is
+ * flushed to SPI Flash.
+ *
+ * The same goes for reading: A compressed page is read from SPI
+ * flash, and the data is uncompressed as needed to provide the
+ * requested amount of data.
+ */
+class SPIFlashStorage {
+public:
+ // Write operation
+ static void beginWrite(uint32_t startAddress);
+ static void endWrite();
+ static void writeData(uint8_t* data, uint16_t size);
+
+ // Read operation
+ static void beginRead(uint32_t startAddress);
+ static void readData(uint8_t* data, uint16_t size);
+
+ static uint32_t getCurrentPage() { return m_currentPage; }
+
+private:
+ static void flushPage();
+ static void savePage(uint8_t* buffer);
+ static void loadPage(uint8_t* buffer);
+ static void readPage();
+ static uint16_t inData(uint8_t* data, uint16_t size);
+ static uint16_t outData(uint8_t* data, uint16_t size);
+
+ static uint8_t m_pageData[SPI_FLASH_PageSize];
+ static uint32_t m_currentPage;
+ static uint16_t m_pageDataUsed;
+ static inline uint16_t pageDataFree() { return SPI_FLASH_PageSize - m_pageDataUsed; }
+ static uint32_t m_startAddress;
+ #if HAS_SPI_FLASH_COMPRESSION
+ static uint8_t m_compressedData[SPI_FLASH_PageSize];
+ static uint16_t m_compressedDataUsed;
+ static inline uint16_t compressedDataFree() { return SPI_FLASH_PageSize - m_compressedDataUsed; }
+ #endif
+};
+
+extern SPIFlashStorage SPIFlash;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.cpp b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.cpp
new file mode 100644
index 0000000..242944b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.cpp
@@ -0,0 +1,83 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "SPI_TFT.h"
+#include "pic_manager.h"
+#include "tft_lvgl_configuration.h"
+
+#include "../../../../inc/MarlinConfig.h"
+
+#include <SPI.h>
+
+#include "draw_ui.h"
+
+TFT SPI_TFT;
+
+// use SPI1 for the spi tft.
+void TFT::spi_init(uint8_t spiRate) {
+ tftio.Init();
+}
+
+void TFT::SetPoint(uint16_t x, uint16_t y, uint16_t point) {
+ if ((x > 480) || (y > 320)) return;
+
+ setWindow(x, y, 1, 1);
+ tftio.WriteMultiple(point, (uint16_t)1);
+}
+
+void TFT::setWindow(uint16_t x, uint16_t y, uint16_t with, uint16_t height) {
+ tftio.set_window(x, y, (x + with - 1), (y + height - 1));
+}
+
+void TFT::LCD_init() {
+ tftio.InitTFT();
+ #if PIN_EXISTS(TFT_BACKLIGHT)
+ OUT_WRITE(TFT_BACKLIGHT_PIN, LOW);
+ #endif
+ delay(100);
+ LCD_clear(0x0000);
+ LCD_Draw_Logo();
+ #if PIN_EXISTS(TFT_BACKLIGHT)
+ OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH);
+ #endif
+}
+
+void TFT::LCD_clear(uint16_t color) {
+ setWindow(0, 0, (TFT_WIDTH), (TFT_HEIGHT));
+ tftio.WriteMultiple(color, (uint32_t)(TFT_WIDTH) * (TFT_HEIGHT));
+}
+
+void TFT::LCD_Draw_Logo() {
+ #if HAS_LOGO_IN_FLASH
+ setWindow(0, 0, TFT_WIDTH, TFT_HEIGHT);
+ for (uint16_t i = 0; i < (TFT_HEIGHT); i ++) {
+ Pic_Logo_Read((uint8_t *)"", (uint8_t *)bmp_public_buf, (TFT_WIDTH) * 2);
+ tftio.WriteSequence((uint16_t *)bmp_public_buf, TFT_WIDTH);
+ }
+ #endif
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.h b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.h
new file mode 100644
index 0000000..f3be3dc
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.h
@@ -0,0 +1,43 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "../../../tft_io/tft_io.h"
+
+class TFT {
+public:
+ TFT_IO tftio;
+ void spi_init(uint8_t spiRate);
+ void SetPoint(uint16_t x, uint16_t y, uint16_t point);
+ void setWindow(uint16_t x, uint16_t y, uint16_t with, uint16_t height);
+ void LCD_init();
+ void LCD_clear(uint16_t color);
+ void LCD_Draw_Logo();
+};
+
+extern TFT SPI_TFT;
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_about.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.cpp
new file mode 100644
index 0000000..4634c5a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.cpp
@@ -0,0 +1,65 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *fw_type, *board;
+
+enum { ID_A_RETURN = 1 };
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_A_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_about(void) {
+ scr = lv_screen_create(ABOUT_UI);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_A_RETURN);
+
+ fw_type = lv_label_create(scr, "Firmware: Marlin " SHORT_BUILD_VERSION);
+ lv_obj_align(fw_type, nullptr, LV_ALIGN_CENTER, 0, -20);
+
+ board = lv_label_create(scr, "Board: " BOARD_INFO_NAME);
+ lv_obj_align(board, nullptr, LV_ALIGN_CENTER, 0, -60);
+}
+
+void lv_clear_about() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_about.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.h
new file mode 100644
index 0000000..9eae2b0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_about(void);
+extern void lv_clear_about();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.cpp
new file mode 100644
index 0000000..9e5dd4f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.cpp
@@ -0,0 +1,155 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+#include "../../../../MarlinCore.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_ACCE_RETURN = 1,
+ ID_ACCE_PRINT,
+ ID_ACCE_RETRA,
+ ID_ACCE_TRAVEL,
+ ID_ACCE_X,
+ ID_ACCE_Y,
+ ID_ACCE_Z,
+ ID_ACCE_E0,
+ ID_ACCE_E1,
+ ID_ACCE_UP,
+ ID_ACCE_DOWN
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_ACCE_RETURN:
+ uiCfg.para_ui_page = 0;
+ lv_clear_acceleration_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_ACCE_PRINT:
+ value = PrintAcceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_RETRA:
+ value = RetractAcceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_TRAVEL:
+ value = TravelAcceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_X:
+ value = XAcceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_Y:
+ value = YAcceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_Z:
+ value = ZAcceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_E0:
+ value = E0Acceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_E1:
+ value = E1Acceleration;
+ lv_clear_acceleration_settings();
+ lv_draw_number_key();
+ break;
+ case ID_ACCE_UP:
+ uiCfg.para_ui_page = 0;
+ lv_clear_acceleration_settings();
+ lv_draw_acceleration_settings();
+ break;
+ case ID_ACCE_DOWN:
+ uiCfg.para_ui_page = 1;
+ lv_clear_acceleration_settings();
+ lv_draw_acceleration_settings();
+ break;
+ }
+}
+
+void lv_draw_acceleration_settings(void) {
+ scr = lv_screen_create(ACCELERATION_UI, machine_menu.AccelerationConfTitle);
+ char str_1[16];
+ if (uiCfg.para_ui_page != 1) {
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.acceleration, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.PrintAcceleration, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_ACCE_PRINT, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.retract_acceleration, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.RetractAcceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_ACCE_RETRA, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.travel_acceleration, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.TravelAcceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_ACCE_TRAVEL, 2, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[X_AXIS]);
+ lv_screen_menu_item_1_edit(scr, machine_menu.X_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_ACCE_X, 3, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_ACCE_DOWN);
+ }
+ else {
+ sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Y_AXIS]);
+ lv_screen_menu_item_1_edit(scr, machine_menu.Y_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_ACCE_Y, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Z_AXIS]);
+ lv_screen_menu_item_1_edit(scr, machine_menu.Z_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_ACCE_Z, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS]);
+ lv_screen_menu_item_1_edit(scr, machine_menu.E0_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_ACCE_E0, 2, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)]);
+ lv_screen_menu_item_1_edit(scr, machine_menu.E1_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_ACCE_E1, 3, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_ACCE_UP);
+ }
+
+ lv_screen_menu_item_return(scr, event_handler, ID_ACCE_RETURN);
+}
+
+void lv_clear_acceleration_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.h
new file mode 100644
index 0000000..6ab4971
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_acceleration_settings(void);
+extern void lv_clear_acceleration_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.cpp
new file mode 100644
index 0000000..973fa10
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.cpp
@@ -0,0 +1,96 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_ADVANCE_RETURN = 1,
+ ID_PAUSE_POS,
+ ID_WIFI_PARA,
+ ID_FILAMENT_SETTINGS,
+ ID_ENCODER_SETTINGS
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_ADVANCE_RETURN:
+ lv_clear_advance_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_PAUSE_POS:
+ lv_clear_advance_settings();
+ lv_draw_pause_position();
+ break;
+ case ID_FILAMENT_SETTINGS:
+ lv_clear_advance_settings();
+ lv_draw_filament_settings();
+ break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case ID_WIFI_PARA:
+ lv_clear_advance_settings();
+ lv_draw_wifi_settings();
+ break;
+ #endif
+ #if HAS_ROTARY_ENCODER
+ case ID_ENCODER_SETTINGS:
+ lv_clear_advance_settings();
+ lv_draw_encoder_settings();
+ break;
+ #endif
+ }
+}
+
+void lv_draw_advance_settings(void) {
+ scr = lv_screen_create(ADVANCED_UI, machine_menu.AdvancedConfTitle);
+
+ int index = 0;
+ lv_screen_menu_item(scr, machine_menu.PausePosition, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_PAUSE_POS, index++);
+ lv_screen_menu_item(scr, machine_menu.FilamentConf, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_FILAMENT_SETTINGS, index++);
+ #if ENABLED(MKS_WIFI_MODULE)
+ lv_screen_menu_item(scr, machine_menu.WifiSettings, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_WIFI_PARA, index++);
+ #endif
+ #if HAS_ROTARY_ENCODER
+ lv_screen_menu_item(scr, machine_menu.EncoderSettings, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_ENCODER_SETTINGS, index);
+ index++;
+ #endif
+
+ lv_screen_menu_item_return(scr, event_handler, ID_ADVANCE_RETURN);
+}
+
+void lv_clear_advance_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.h
new file mode 100644
index 0000000..84e4a4d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_advance_settings(void);
+extern void lv_clear_advance_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.cpp
new file mode 100644
index 0000000..0f2a527
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.cpp
@@ -0,0 +1,90 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, HAS_BED_PROBE)
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/probe.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_OFFSET_RETURN = 1,
+ ID_OFFSET_X,
+ ID_OFFSET_Y,
+ ID_OFFSET_Z
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_OFFSET_RETURN:
+ lv_clear_auto_level_offset_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_OFFSET_X:
+ value = x_offset;
+ lv_clear_auto_level_offset_settings();
+ lv_draw_number_key();
+ break;
+ case ID_OFFSET_Y:
+ value = y_offset;
+ lv_clear_auto_level_offset_settings();
+ lv_draw_number_key();
+ break;
+ case ID_OFFSET_Z:
+ value = z_offset;
+ lv_clear_auto_level_offset_settings();
+ lv_draw_number_key();
+ break;
+ }
+}
+
+void lv_draw_auto_level_offset_settings(void) {
+ char str_1[16];
+ scr = lv_screen_create(NOZZLE_PROBE_OFFSET_UI, machine_menu.OffsetConfTitle);
+
+ sprintf_P(public_buf_l, PSTR("%s"), TERN(HAS_PROBE_XY_OFFSET,dtostrf(probe.offset.x, 1, 3, str_1) , 0));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Xoffset, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_OFFSET_X, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), TERN(HAS_PROBE_XY_OFFSET,dtostrf(probe.offset.y, 1, 3, str_1) , 0));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Yoffset, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_OFFSET_Y, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), TERN(HAS_PROBE_XY_OFFSET,dtostrf(probe.offset.z, 1, 3, str_1) , 0));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Zoffset, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_OFFSET_Z, 2, public_buf_l);
+
+ lv_screen_menu_item_return(scr, event_handler, ID_OFFSET_RETURN);
+}
+
+void lv_clear_auto_level_offset_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI && HAS_BED_PROBE
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.h
new file mode 100644
index 0000000..688cd20
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_auto_level_offset_settings(void);
+extern void lv_clear_auto_level_offset_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.cpp
new file mode 100644
index 0000000..a94d1c1
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.cpp
@@ -0,0 +1,179 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../gcode/queue.h"
+#include "../../../../gcode/gcode.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(EEPROM_SETTINGS)
+ #include "../../../../module/settings.h"
+#endif
+
+#if HAS_BED_PROBE
+ #include "../../../../module/probe.h"
+#endif
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+static lv_obj_t *labelV, *buttonV, *zOffsetText;
+
+enum {
+ ID_BABY_STEP_X_P = 1,
+ ID_BABY_STEP_X_N,
+ ID_BABY_STEP_Y_P,
+ ID_BABY_STEP_Y_N,
+ ID_BABY_STEP_Z_P,
+ ID_BABY_STEP_Z_N,
+ ID_BABY_STEP_DIST,
+ ID_BABY_STEP_RETURN
+};
+
+static float babystep_dist=0.01;
+static uint8_t has_adjust_z = 0;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ char baby_buf[30] = { 0 };
+ char str_1[16];
+ switch (obj->mks_obj_id) {
+ case ID_BABY_STEP_X_P:
+ sprintf_P(baby_buf, PSTR("M290 X%s"), dtostrf(babystep_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BABY_STEP_X_N:
+ sprintf_P(baby_buf, PSTR("M290 X%s"), dtostrf(-babystep_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BABY_STEP_Y_P:
+ sprintf_P(baby_buf, PSTR("M290 Y%s"), dtostrf(babystep_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BABY_STEP_Y_N:
+ sprintf_P(baby_buf, PSTR("M290 Y%s"), dtostrf(-babystep_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BABY_STEP_Z_P:
+ sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(babystep_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BABY_STEP_Z_N:
+ sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(-babystep_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BABY_STEP_DIST:
+ if (abs((int)(100 * babystep_dist)) == 1)
+ babystep_dist = 0.05;
+ else if (abs((int)(100 * babystep_dist)) == 5)
+ babystep_dist = 0.1;
+ else
+ babystep_dist = 0.01;
+ disp_baby_step_dist();
+ break;
+ case ID_BABY_STEP_RETURN:
+ if (has_adjust_z == 1) {
+ TERN_(EEPROM_SETTINGS, (void)settings.save());
+ has_adjust_z = 0;
+ }
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_baby_stepping(void) {
+ scr = lv_screen_create(BABY_STEP_UI);
+ lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_V, titleHeight, event_handler, ID_BABY_STEP_X_P);
+ lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_X_N);
+ lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_BABY_STEP_Y_P);
+ lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_Y_N);
+ lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_BABY_STEP_Z_P);
+ lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_Z_N);
+ buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_BABY_STEP_DIST);
+ labelV = lv_label_create_empty(buttonV);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonV);
+ }
+ #endif
+
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_RETURN);
+
+ disp_baby_step_dist();
+
+ zOffsetText = lv_label_create(scr, 290, TITLE_YPOS, nullptr);
+ disp_z_offset_value();
+}
+
+void disp_baby_step_dist() {
+ if ((int)(100 * babystep_dist) == 1)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_01.bin");
+ else if ((int)(100 * babystep_dist) == 5)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_05.bin");
+ else if ((int)(100 * babystep_dist) == 10)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_1.bin");
+
+ if (gCfgItems.multiple_language) {
+ if ((int)(100 * babystep_dist) == 1) {
+ lv_label_set_text(labelV, move_menu.step_001mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if ((int)(100 * babystep_dist) == 5) {
+ lv_label_set_text(labelV, move_menu.step_005mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if ((int)(100 * babystep_dist) == 10) {
+ lv_label_set_text(labelV, move_menu.step_01mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void disp_z_offset_value() {
+ char buf[20];
+ #if HAS_BED_PROBE
+ char str_1[16];
+ #endif
+ sprintf_P(buf, PSTR("offset Z: %s mm"), TERN(HAS_BED_PROBE, dtostrf(probe.offset.z, 1, 3, str_1), "0"));
+ lv_label_set_text(zOffsetText, buf);
+}
+
+void lv_clear_baby_stepping() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.h
new file mode 100644
index 0000000..5886a20
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.h
@@ -0,0 +1,35 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_baby_stepping(void);
+extern void lv_clear_baby_stepping();
+extern void disp_baby_step_dist();
+extern void disp_z_offset_value();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.cpp
new file mode 100644
index 0000000..7fec704
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.cpp
@@ -0,0 +1,184 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "../../../../MarlinCore.h"
+#include "draw_ui.h"
+
+#include "../../../../module/temperature.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../gcode/gcode.h"
+
+#include "../../../../module/probe.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr, *labelV, *buttonV, *zOffsetText;
+static lv_obj_t *labelExt1, *labelBed;
+
+static uint8_t has_adjust_z = 0;
+static float step_dist=0.01;
+
+enum {
+ ID_BLTOUCH_INIT = 1,
+ ID_BLTOUCH_ZOFFSETPOS,
+ ID_BLTOUCH_ZOFFSETNEG,
+ ID_BLTOUCH_SAVE,
+ ID_BLTOUCH_TEST,
+ ID_BLTOUCH_STEPS,
+ ID_BLTOUCH_RETURN
+ };
+
+
+static void event_handler(lv_obj_t * obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ char baby_buf[30] = { 0 };
+ char str_1[40];
+ switch (obj->mks_obj_id) {
+ case ID_BLTOUCH_INIT:
+ bltouch_do_init();
+ break;
+ case ID_BLTOUCH_ZOFFSETPOS:
+ sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(step_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BLTOUCH_ZOFFSETNEG:
+ sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(-step_dist, 1, 3, str_1));
+ gcode.process_subcommands_now_P(PSTR(baby_buf));
+ has_adjust_z = 1;
+ break;
+ case ID_BLTOUCH_SAVE:
+ if (queue.length <= (BUFSIZE - 2)) queue.enqueue_now_P(PSTR("M500\nG28 X Y"));
+
+ break;
+ case ID_BLTOUCH_TEST:
+ sprintf_P(str_1, PSTR("G28\nG1 Z10 F2400\nG1 X%d Y%d\nG1 Z0"), X_MAX_POS / 2, Y_MAX_POS / 2);
+ if (!queue.length) queue.enqueue_now_P(PSTR(str_1));
+ break;
+ case ID_BLTOUCH_STEPS:
+ if (abs((int)(100 * step_dist)) == 1)
+ step_dist = 0.05;
+ else if (abs((int)(100 * step_dist)) == 5)
+ step_dist = 0.1;
+ else
+ step_dist = 0.01;
+ disp_step_dist();
+ break;
+ case ID_BLTOUCH_RETURN:
+ TERN_(HAS_SOFTWARE_ENDSTOPS, soft_endstop._enabled = true);
+ lv_clear_bltouch_settings();
+ lv_draw_return_ui();
+ break;
+
+ }
+}
+
+void lv_draw_bltouch_settings(void) {
+ scr = lv_screen_create(BLTOUCH_UI, machine_menu.BLTouchLevelingConfTitle);
+ // Create image buttons
+ lv_big_button_create(scr, "F:/bmp_Add.bin" , machine_menu.BLTouchOffsetpos, INTERVAL_V, titleHeight, event_handler, ID_BLTOUCH_ZOFFSETPOS);
+ lv_obj_t *buttonExt1 = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonExt1 , "F:/bmp_ext1_state.bin");
+ lv_obj_set_pos(buttonExt1 , 171, 50);
+
+ lv_obj_t *buttonBedstate = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonBedstate, "F:/bmp_bed_state.bin");
+ lv_obj_set_pos(buttonBedstate, 266, 50);
+ labelExt1 = lv_label_create(scr, 161, 115, nullptr);
+ labelBed = lv_label_create(scr, 256, 115, nullptr);
+
+ lv_obj_align(labelExt1, buttonExt1 , LV_ALIGN_IN_BOTTOM_MID, 2, 20);
+ lv_obj_align(labelBed , buttonBedstate, LV_ALIGN_IN_BOTTOM_MID, 2, 20);
+
+ zOffsetText = lv_label_create(scr , 170, 140, nullptr);
+ lv_big_button_create(scr, "F:/bmp_Dec.bin" , machine_menu.BLTouchOffsetneg, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_BLTOUCH_ZOFFSETNEG);
+
+ buttonV = lv_imgbtn_create(scr , nullptr , INTERVAL_V , BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_STEPS);
+ labelV = lv_label_create_empty(buttonV);
+
+ lv_big_button_create(scr, "F:/bmp_in.bin" , machine_menu.BLTouchTest , BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_TEST);
+ lv_big_button_create(scr, "F:/bmp_set.bin" , machine_menu.BLTouchSave , BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_SAVE);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back , BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_RETURN);
+
+ disp_step_dist();
+ disp_bltouch_z_offset_value();
+}
+
+void disp_step_dist() {
+ if ((int)(100 * step_dist) == 1)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_01.bin");
+ else if ((int)(100 * step_dist) == 5)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_05.bin");
+ else if ((int)(100 * step_dist) == 10)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_1.bin");
+
+ if (gCfgItems.multiple_language) {
+ if ((int)(100 * step_dist) == 1) {
+ lv_label_set_text(labelV, move_menu.step_001mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if ((int)(100 * step_dist) == 5) {
+ lv_label_set_text(labelV, move_menu.step_005mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if ((int)(100 * step_dist) == 10) {
+ lv_label_set_text(labelV, move_menu.step_01mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void disp_bltouch_z_offset_value() {
+ char buf[20];
+ char str_1[16];
+ sprintf_P(buf, PSTR("Z Offset : %s mm"), dtostrf(probe.offset.z, 1, 2, str_1) );
+ lv_label_set_text(zOffsetText, buf);
+
+ sprintf(public_buf_l, printing_menu.temp1, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target);
+ lv_label_set_text(labelExt1, public_buf_l);
+
+ #if HAS_HEATED_BED
+ sprintf(public_buf_l, printing_menu.bed_temp, (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target);
+ lv_label_set_text(labelBed, public_buf_l);
+ #endif
+
+}
+
+void bltouch_do_init() {
+ char str_1[50];
+ TERN_(HAS_BED_PROBE, probe.offset.z = 0);
+ TERN_(HAS_SOFTWARE_ENDSTOPS, soft_endstop._enabled = false);
+ queue.clear();
+ sprintf_P(str_1, PSTR("G28\nG1 Z10 F2400\nG1 X%d Y%d\nG1 Z0"), X_MAX_POS / 2, Y_MAX_POS / 2);
+ queue.enqueue_now_P(PSTR(str_1));
+}
+
+void lv_clear_bltouch_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.h
new file mode 100644
index 0000000..5f33359
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.h
@@ -0,0 +1,37 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_bltouch_settings(void);
+extern void lv_clear_bltouch_settings();
+extern void disp_step_dist();
+extern void bltouch_do_init();
+extern void disp_bltouch_z_offset_value();
+
+//extern void disp_temp_ready_print();
+#ifdef __cplusplus
+} /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.cpp
new file mode 100644
index 0000000..bb3be74
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.cpp
@@ -0,0 +1,225 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *labelStep, *buttonStep, *buttonMov, *buttonExt;
+static lv_obj_t *labelMov, *labelExt;
+static lv_obj_t *printSpeedText;
+
+enum {
+ ID_C_ADD = 1,
+ ID_C_DEC,
+ ID_C_MOVE,
+ ID_C_EXT,
+ ID_C_STEP,
+ ID_C_RETURN
+};
+
+static bool editingFlowrate;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_C_ADD:
+ if (!editingFlowrate) {
+ if (feedrate_percentage < MAX_EXT_SPEED_PERCENT - uiCfg.stepPrintSpeed)
+ feedrate_percentage += uiCfg.stepPrintSpeed;
+ else
+ feedrate_percentage = MAX_EXT_SPEED_PERCENT;
+ }
+ else {
+ if (planner.flow_percentage[0] < MAX_EXT_SPEED_PERCENT - uiCfg.stepPrintSpeed)
+ planner.flow_percentage[0] += uiCfg.stepPrintSpeed;
+ else
+ planner.flow_percentage[0] = MAX_EXT_SPEED_PERCENT;
+ planner.refresh_e_factor(0);
+ #if HAS_MULTI_EXTRUDER
+ planner.flow_percentage[1] = planner.flow_percentage[0];
+ planner.refresh_e_factor(1);
+ #endif
+ }
+ disp_print_speed();
+ break;
+ case ID_C_DEC:
+ if (!editingFlowrate) {
+ if (feedrate_percentage > MIN_EXT_SPEED_PERCENT + uiCfg.stepPrintSpeed)
+ feedrate_percentage -= uiCfg.stepPrintSpeed;
+ else
+ feedrate_percentage = MIN_EXT_SPEED_PERCENT;
+ }
+ else {
+ if (planner.flow_percentage[0] > MIN_EXT_SPEED_PERCENT + uiCfg.stepPrintSpeed)
+ planner.flow_percentage[0] -= uiCfg.stepPrintSpeed;
+ else
+ planner.flow_percentage[0] = MIN_EXT_SPEED_PERCENT;
+ planner.refresh_e_factor(0);
+ #if HAS_MULTI_EXTRUDER
+ planner.flow_percentage[1] = planner.flow_percentage[0];
+ planner.refresh_e_factor(1);
+ #endif
+ }
+ disp_print_speed();
+ break;
+ case ID_C_MOVE:
+ editingFlowrate = false;
+ disp_speed_type();
+ disp_print_speed();
+ break;
+ case ID_C_EXT:
+ editingFlowrate = true;
+ disp_speed_type();
+ disp_print_speed();
+ break;
+ case ID_C_STEP:
+ if (uiCfg.stepPrintSpeed == 1)
+ uiCfg.stepPrintSpeed = 5;
+ else if (uiCfg.stepPrintSpeed == 5)
+ uiCfg.stepPrintSpeed = 10;
+ else
+ uiCfg.stepPrintSpeed = 1;
+ disp_speed_step();
+ break;
+ case ID_C_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_change_speed(void) {
+ scr = lv_screen_create(CHANGE_SPEED_UI);
+ // Create an Image button
+ lv_big_button_create(scr, "F:/bmp_Add.bin", speed_menu.add, INTERVAL_V, titleHeight, event_handler, ID_C_ADD);
+ lv_big_button_create(scr, "F:/bmp_Dec.bin", speed_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_C_DEC);
+ buttonMov = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_MOVE);
+ buttonExt = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_EXT);
+ buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_STEP);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonMov);
+ lv_group_add_obj(g, buttonExt);
+ lv_group_add_obj(g, buttonStep);
+ }
+ #endif
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_RETURN);
+
+ // Create labels on the image buttons
+ labelMov = lv_label_create_empty(buttonMov);
+ labelExt = lv_label_create_empty(buttonExt);
+ labelStep = lv_label_create_empty(buttonStep);
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonMov);
+ lv_group_add_obj(g, buttonExt);
+ lv_group_add_obj(g, buttonStep);
+ }
+ #endif
+
+ disp_speed_type();
+ disp_speed_step();
+
+ printSpeedText = lv_label_create_empty(scr);
+ lv_obj_set_style(printSpeedText, &tft_style_label_rel);
+ disp_print_speed();
+}
+
+void disp_speed_step() {
+ if (uiCfg.stepPrintSpeed == 1)
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step1_percent.bin");
+ else if (uiCfg.stepPrintSpeed == 5)
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step5_percent.bin");
+ else if (uiCfg.stepPrintSpeed == 10)
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step10_percent.bin");
+
+ if (gCfgItems.multiple_language) {
+ if (uiCfg.stepPrintSpeed == 1) {
+ lv_label_set_text(labelStep, speed_menu.step_1percent);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if (uiCfg.stepPrintSpeed == 5) {
+ lv_label_set_text(labelStep, speed_menu.step_5percent);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if (uiCfg.stepPrintSpeed == 10) {
+ lv_label_set_text(labelStep, speed_menu.step_10percent);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void disp_print_speed() {
+ char buf[30] = { 0 };
+
+ public_buf_l[0] = '\0';
+
+ int16_t val;
+ const char *lbl;
+ if (editingFlowrate) {
+ lbl = speed_menu.extrude_speed;
+ val = planner.flow_percentage[0];
+ }
+ else {
+ lbl = speed_menu.move_speed;
+ val = feedrate_percentage;
+ }
+ strcpy(public_buf_l, lbl);
+ strcat_P(public_buf_l, PSTR(": "));
+ sprintf_P(buf, PSTR("%d%%"), val);
+ strcat(public_buf_l, buf);
+ lv_label_set_text(printSpeedText, public_buf_l);
+ lv_obj_align(printSpeedText, nullptr, LV_ALIGN_CENTER, 0, -65);
+}
+
+void disp_speed_type() {
+ lv_imgbtn_set_src_both(buttonMov, editingFlowrate ? "F:/bmp_mov_changeSpeed.bin" : "F:/bmp_mov_sel.bin");
+ lv_imgbtn_set_src_both(buttonExt, editingFlowrate ? "F:/bmp_extruct_sel.bin" : "F:/bmp_speed_extruct.bin");
+ lv_obj_refresh_ext_draw_pad(buttonExt);
+ lv_obj_refresh_ext_draw_pad(buttonMov);
+
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelMov, speed_menu.move);
+ lv_obj_align(labelMov, buttonMov, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+
+ lv_label_set_text(labelExt, speed_menu.extrude);
+ lv_obj_align(labelExt, buttonExt, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+}
+
+void lv_clear_change_speed() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.h
new file mode 100644
index 0000000..8fa4c80
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.h
@@ -0,0 +1,39 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+#define MIN_EXT_SPEED_PERCENT 10
+#define MAX_EXT_SPEED_PERCENT 999
+
+extern void lv_draw_change_speed(void);
+extern void lv_clear_change_speed();
+extern void disp_speed_step();
+extern void disp_print_speed();
+extern void disp_speed_type();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.cpp
new file mode 100644
index 0000000..38c3ebf
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.cpp
@@ -0,0 +1,205 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, MKS_WIFI_MODULE)
+
+#include "lv_conf.h"
+#include "draw_ui.h"
+
+#include "../../../../MarlinCore.h"
+#include "../../../../module/temperature.h"
+
+#include "QR_Encode.h"
+
+extern lv_group_t * g;
+static lv_obj_t * scr;
+static lv_obj_t *button_bind_or_not = NULL, *label_bind_or_not = NULL;
+static lv_obj_t *buttonReleaseBind = NULL, *label_ReleaseBind = NULL;
+static lv_obj_t * text_id;
+
+static uint8_t unbinding_flag = 0;
+static uint8_t id_mark = 0;
+
+#define ID_CLOUD_BIND_RETURN 1
+#define ID_CLOUD_BIND_OR_NOT 2
+#define ID_CLOUD_RELEASE_BIND 3
+
+static void event_handler(lv_obj_t * obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_CLOUD_BIND_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ case ID_CLOUD_RELEASE_BIND:
+ if (cloud_para.state == 0x12) {
+ lv_clear_cur_ui();
+ lv_draw_dialog(DIALOG_TYPE_UNBIND);
+ }
+ break;
+ }
+}
+
+void lv_draw_cloud_bind(void) {
+ lv_obj_t *buttonBack = NULL, *label_Back = NULL;
+ scr = lv_screen_create(BIND_UI);
+
+ button_bind_or_not = lv_btn_create(scr, NULL);
+ lv_obj_set_pos(button_bind_or_not, TFT_WIDTH - 130, TFT_HEIGHT - 80 * 3);
+ lv_obj_set_size(button_bind_or_not, PARA_UI_VALUE_BTN_X_SIZE + 15, PARA_UI_VALUE_BTN_Y_SIZE + 15);
+ lv_obj_set_event_cb_mks(button_bind_or_not, event_handler, ID_CLOUD_BIND_OR_NOT, NULL, 0);
+ lv_btn_set_style(button_bind_or_not, LV_BTN_STYLE_REL, &style_para_value);
+ lv_btn_set_style(button_bind_or_not, LV_BTN_STYLE_PR, &style_para_value);
+ label_bind_or_not = lv_label_create_empty(button_bind_or_not);
+
+ buttonReleaseBind = lv_btn_create(scr, NULL);
+ lv_obj_set_pos(buttonReleaseBind, TFT_WIDTH - 130, TFT_HEIGHT - 80 * 2);
+ lv_obj_set_size(buttonReleaseBind, PARA_UI_VALUE_BTN_X_SIZE + 15, PARA_UI_VALUE_BTN_Y_SIZE + 15);
+ lv_obj_set_event_cb_mks(buttonReleaseBind, event_handler, ID_CLOUD_RELEASE_BIND, NULL, 0);
+ label_ReleaseBind = lv_label_create_empty(buttonReleaseBind);
+ lv_label_set_text(label_ReleaseBind, cloud_menu.unbind);
+ lv_obj_align(label_ReleaseBind, buttonReleaseBind, LV_ALIGN_CENTER, 0, 0);
+
+ buttonBack = lv_btn_create(scr, NULL);
+ lv_obj_set_pos(buttonBack, TFT_WIDTH - 130, TFT_HEIGHT - 80);
+ lv_obj_set_size(buttonBack, PARA_UI_VALUE_BTN_X_SIZE + 15, PARA_UI_VALUE_BTN_Y_SIZE + 15);
+ lv_obj_set_event_cb_mks(buttonBack, event_handler, ID_CLOUD_BIND_RETURN, NULL, 0);
+ lv_btn_set_style(buttonBack, LV_BTN_STYLE_REL, &style_para_back);
+ lv_btn_set_style(buttonBack, LV_BTN_STYLE_PR, &style_para_back);
+ label_Back = lv_label_create_empty(buttonBack);
+ lv_label_set_text(label_Back, common_menu.text_back);
+ lv_obj_align(label_Back, buttonBack, LV_ALIGN_CENTER, 0, 0);
+
+ #if BUTTONS_EXIST(EN1, EN2, ENC)
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonReleaseBind);
+ lv_group_add_obj(g, buttonBack);
+ }
+ #endif
+
+ text_id = lv_label_create_empty(scr);
+ lv_obj_set_pos(text_id, 50, 60 + 200 + 20);
+ lv_obj_set_style(text_id, &tft_style_label_rel);
+ lv_label_set_text(text_id, (char *)cloud_para.id);
+
+ id_mark = 0;
+
+ disp_bind_state();
+}
+
+void disp_bind_state() {
+ if (cloud_para.state != 0x12)
+ unbinding_flag = 0;
+
+ if (unbinding_flag) {
+ lv_label_set_text(label_bind_or_not, cloud_menu.unbinding);
+ lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0);
+ lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_REL, &style_para_value);
+ lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_PR, &style_para_value);
+ }
+ else {
+ if (cloud_para.state == 0x10) {
+ lv_label_set_text(label_bind_or_not, cloud_menu.disconnected);
+ lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0);
+ }
+ else if (cloud_para.state == 0x11) {
+ lv_label_set_text(label_bind_or_not, cloud_menu.unbinded);
+ lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0);
+ }
+ else if (cloud_para.state == 0x12) {
+ lv_label_set_text(label_bind_or_not, cloud_menu.binded);
+ lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0);
+ }
+ else {
+ lv_label_set_text(label_bind_or_not, cloud_menu.disable);
+ lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0);
+ }
+ }
+
+ if (cloud_para.state == 0x12 && !unbinding_flag) {
+ lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_REL, &style_para_back);
+ lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_PR, &style_para_back);
+ }
+ else {
+ lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_REL, &style_para_value);
+ lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_PR, &style_para_value);
+ }
+}
+
+static char last_cloud_state = 0;
+void refresh_bind_ui() {
+ if ((last_cloud_state != cloud_para.state) || unbinding_flag) {
+ disp_bind_state();
+ last_cloud_state = cloud_para.state;
+ }
+ if (cloud_para.id[0]) {
+ if (!id_mark) {
+ display_qrcode((uint8_t *)cloud_para.id);
+ lv_label_set_text(text_id, (char *)cloud_para.id);
+ }
+ }
+ else
+ id_mark = 0;
+}
+
+void display_qrcode(uint8_t *qrcode_data) {
+ uint8_t i, j;
+ uint16_t x, y, p;
+
+ if (!id_mark) {
+ EncodeData((char *)qrcode_data);
+ id_mark = 1;
+ }
+
+ lv_fill_rect(10, QRCODE_Y, 300, QRCODE_Y + 300, LV_COLOR_WHITE);
+
+ if (m_nSymbleSize * 2 > QRCODE_WIDTH) return;
+
+ for (i = 0; i < 40; i++)
+ if ((m_nSymbleSize * i * 2) > QRCODE_WIDTH) break;
+
+ p = (i - 1) * 2;
+
+ x = QRCODE_X + 70;
+ y = QRCODE_Y + 70;
+
+ for (i = 0; i < m_nSymbleSize; i++)
+ for (j = 0; j < m_nSymbleSize; j++)
+ if (m_byModuleData[i][j] == 1)
+ lv_fill_rect(x + p * i, y + p * j, x + p * (i + 1) - 1, y + p * (j + 1) - 1, LV_COLOR_BACKGROUND);
+}
+
+void cloud_unbind() {
+ package_to_wifi(WIFI_CLOUD_UNBIND, (uint8_t *)0, 0);
+ unbinding_flag = 1;
+}
+
+void lv_clear_cloud_bind() {
+ #if BUTTONS_EXIST(EN1, EN2, ENC)
+ if (gCfgItems.encoder_enable)
+ lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.h
new file mode 100644
index 0000000..f0f354a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.h
@@ -0,0 +1,37 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_cloud_bind(void);
+extern void lv_clear_cloud_bind();
+extern void disp_bind_state();
+extern void refresh_bind_ui();
+extern void display_qrcode(uint8_t *qrcode_data);
+extern void cloud_unbind();
+
+#ifdef __cplusplus
+} /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp
new file mode 100644
index 0000000..4b0eebe
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp
@@ -0,0 +1,574 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * draw_dialog.cpp
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../sd/cardreader.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../module/temperature.h"
+#include "../../../../module/planner.h"
+#include "../../../../gcode/gcode.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(EEPROM_SETTINGS)
+ #include "../../../../module/settings.h"
+#endif
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if ENABLED(PARK_HEAD_ON_PAUSE)
+ #include "../../../../feature/pause.h"
+#endif
+
+#if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ #include "../../../tft_io/touch_calibration.h"
+ #include "draw_touch_calibration.h"
+#endif
+
+extern lv_group_t *g;
+static lv_obj_t *scr, *tempText1, *filament_bar;
+
+extern uint8_t sel_id;
+extern bool once_flag, gcode_preview_over;
+extern int upload_result;
+extern uint32_t upload_time;
+extern uint32_t upload_size;
+extern bool temps_update_flag;
+
+static void btn_ok_event_cb(lv_obj_t *btn, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ if (DIALOG_IS(TYPE_PRINT_FILE)) {
+ #if HAS_GCODE_PREVIEW
+ preview_gcode_prehandle(list_file.file_name[sel_id]);
+ #endif
+ reset_print_time();
+ start_print_time();
+
+ uiCfg.print_state = WORKING;
+ lv_clear_dialog();
+ lv_draw_printing();
+
+ #if ENABLED(SDSUPPORT)
+ if (!gcode_preview_over) {
+ //char *cur_name;
+ //cur_name = strrchr(list_file.file_name[sel_id], '/');
+
+ //SdFile file, *curDir;
+ card.endFilePrint();
+ //const char * const fname = card.diveToFile(true, curDir, cur_name);
+ //if (!fname) return;
+ //if (file.open(curDir, fname, O_READ)) {
+ //gCfgItems.curFilesize = file.fileSize();
+ //file.close();
+ //update_spi_flash();
+ //}
+ card.openFileRead(list_file.file_name[sel_id]);
+ if (card.isFileOpen()) {
+ gCfgItems.curFilesize = card.getFileSize();
+ update_spi_flash();
+ feedrate_percentage = 100;
+ planner.flow_percentage[0] = 100;
+ planner.e_factor[0] = planner.flow_percentage[0] * 0.01f;
+ #if HAS_MULTI_EXTRUDER
+ planner.flow_percentage[1] = 100;
+ planner.e_factor[1] = planner.flow_percentage[1] * 0.01f;
+ #endif
+ card.startFileprint();
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ recovery.prepare();
+ #endif
+ once_flag = false;
+ }
+ }
+ #endif
+ }
+ else if (DIALOG_IS(TYPE_STOP)) {
+ wait_for_heatup = false;
+ stop_print_time();
+ lv_clear_dialog();
+ lv_draw_ready_print();
+
+ #if ENABLED(SDSUPPORT)
+ uiCfg.print_state = IDLE;
+ card.flag.abort_sd_printing = true;
+ #endif
+ }
+ else if (DIALOG_IS(TYPE_FINISH_PRINT)) {
+ lv_clear_cur_ui();
+ lv_draw_ready_print();
+ }
+ #if ENABLED(ADVANCED_PAUSE_FEATURE)
+ else if (DIALOG_IS(PAUSE_MESSAGE_WAITING, PAUSE_MESSAGE_INSERT, PAUSE_MESSAGE_HEAT))
+ wait_for_user = false;
+ else if (DIALOG_IS(PAUSE_MESSAGE_OPTION))
+ pause_menu_response = PAUSE_RESPONSE_EXTRUDE_MORE;
+ else if (DIALOG_IS(PAUSE_MESSAGE_RESUME)) {
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ #endif
+ else if (DIALOG_IS(STORE_EEPROM_TIPS)) {
+ TERN_(EEPROM_SETTINGS, (void)settings.save());
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ else if (DIALOG_IS(READ_EEPROM_TIPS)) {
+ TERN_(EEPROM_SETTINGS, (void)settings.load());
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ else if (DIALOG_IS(REVERT_EEPROM_TIPS)) {
+ TERN_(EEPROM_SETTINGS, (void)settings.reset());
+ lv_clear_cur_ui();
+ #if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ const bool do_draw_cal = touch_calibration.need_calibration();
+ if (do_draw_cal) {
+ disp_state_stack._disp_index--; // We are asynchronous from the dialog, so let's remove the dialog from the stack
+ lv_draw_touch_calibration_screen();
+ }
+ #else
+ constexpr bool do_draw_cal = false;
+ #endif
+ if (!do_draw_cal) lv_draw_return_ui();
+ }
+ else if (DIALOG_IS(WIFI_CONFIG_TIPS)) {
+ uiCfg.configWifi = 1;
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_HEAT_LOAD_COMPLETED))
+ uiCfg.filament_heat_completed_load = 1;
+ else if (DIALOG_IS(TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED))
+ uiCfg.filament_heat_completed_unload = 1;
+ else if (DIALOG_IS(TYPE_FILAMENT_LOAD_COMPLETED, TYPE_FILAMENT_UNLOAD_COMPLETED)) {
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ #if ENABLED(MKS_WIFI_MODULE)
+ else if (DIALOG_IS(TYPE_UNBIND)) {
+ cloud_unbind();
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ #endif
+ else {
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+}
+
+static void btn_cancel_event_cb(lv_obj_t *btn, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ if (DIALOG_IS(PAUSE_MESSAGE_OPTION)) {
+ TERN_(ADVANCED_PAUSE_FEATURE, pause_menu_response = PAUSE_RESPONSE_RESUME_PRINT);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT, TYPE_FILAMENT_UNLOAD_HEAT, TYPE_FILAMENT_HEAT_LOAD_COMPLETED, TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED)) {
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target= uiCfg.desireSprayerTempBak;
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_LOADING, TYPE_FILAMENT_UNLOADING)) {
+ queue.enqueue_one_P(PSTR("M410"));
+ uiCfg.filament_rate = 0;
+ uiCfg.filament_loading_completed = 0;
+ uiCfg.filament_unloading_completed = 0;
+ uiCfg.filament_loading_time_flg = 0;
+ uiCfg.filament_loading_time_cnt = 0;
+ uiCfg.filament_unloading_time_flg = 0;
+ uiCfg.filament_unloading_time_cnt = 0;
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = uiCfg.desireSprayerTempBak;
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+ else {
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ }
+}
+
+void lv_draw_dialog(uint8_t type) {
+ lv_obj_t *btnOk = nullptr, *btnCancel = nullptr;
+ uiCfg.dialogType = type;
+ scr = lv_screen_create(DIALOG_UI);
+
+ lv_obj_t *labelDialog = lv_label_create(scr, "");
+
+ if (DIALOG_IS(TYPE_FINISH_PRINT, PAUSE_MESSAGE_RESUME)) {
+ btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb);
+ lv_obj_t *labelOk = lv_label_create_empty(btnOk); // Add a label to the button
+ lv_label_set_text(labelOk, print_file_dialog_menu.confirm); // Set the labels text
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_WAITING, PAUSE_MESSAGE_INSERT, PAUSE_MESSAGE_HEAT)) {
+ btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb);
+ lv_obj_t *labelOk = lv_label_create_empty(btnOk); // Add a label to the button
+ lv_label_set_text(labelOk, print_file_dialog_menu.confirm); // Set the labels text
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_PAUSING, PAUSE_MESSAGE_CHANGING, PAUSE_MESSAGE_UNLOAD, PAUSE_MESSAGE_LOAD, PAUSE_MESSAGE_PURGE, PAUSE_MESSAGE_RESUME, PAUSE_MESSAGE_HEATING)) {
+ // nothing to do
+ }
+ else if (DIALOG_IS(WIFI_ENABLE_TIPS)) {
+ btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb);
+ lv_obj_t *labelCancel = lv_label_create_empty(btnCancel);
+ lv_label_set_text(labelCancel, print_file_dialog_menu.cancel);
+ }
+ else if (DIALOG_IS(TRANSFER_NO_DEVICE)) {
+ btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb);
+ lv_obj_t *labelCancel = lv_label_create_empty(btnCancel);
+ lv_label_set_text(labelCancel, print_file_dialog_menu.cancel);
+ }
+ #if ENABLED(MKS_WIFI_MODULE)
+ else if (DIALOG_IS(TYPE_UPLOAD_FILE)) {
+ if (upload_result == 2) {
+ btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb);
+ lv_obj_t *labelCancel = lv_label_create_empty(btnCancel);
+ lv_label_set_text(labelCancel, print_file_dialog_menu.cancel);
+ }
+ else if (upload_result == 3) {
+ btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb);
+ lv_obj_t *labelOk = lv_label_create_empty(btnOk);
+ lv_label_set_text(labelOk, print_file_dialog_menu.confirm);
+ }
+ }
+ else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMARE)) {
+ // nothing to do
+ }
+ #endif
+ else if (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT, TYPE_FILAMENT_UNLOAD_HEAT)) {
+ btnCancel = lv_button_btn_create(scr, BTN_OK_X+90, BTN_OK_Y, 100, 50, btn_cancel_event_cb);
+ lv_obj_t *labelCancel = lv_label_create_empty(btnCancel);
+ lv_label_set_text(labelCancel, print_file_dialog_menu.cancel);
+
+ tempText1 = lv_label_create_empty(scr);
+ filament_sprayer_temp();
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_LOAD_COMPLETED, TYPE_FILAMENT_UNLOAD_COMPLETED)) {
+ btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb);
+ lv_obj_t *labelOk = lv_label_create_empty(btnOk);
+ lv_label_set_text(labelOk, print_file_dialog_menu.confirm);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_LOADING, TYPE_FILAMENT_UNLOADING)) {
+ btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb);
+ lv_obj_t *labelCancel = lv_label_create_empty(btnCancel);
+ lv_label_set_text(labelCancel, print_file_dialog_menu.cancel);
+
+ filament_bar = lv_bar_create(scr, nullptr);
+ lv_obj_set_pos(filament_bar, (TFT_WIDTH-400)/2, ((TFT_HEIGHT - titleHeight)-40)/2);
+ lv_obj_set_size(filament_bar, 400, 25);
+ lv_bar_set_style(filament_bar, LV_BAR_STYLE_INDIC, &lv_bar_style_indic);
+ lv_bar_set_anim_time(filament_bar, 1000);
+ lv_bar_set_value(filament_bar, 0, LV_ANIM_ON);
+ }
+ else if(DIALOG_IS(TYPE_MACHINE_PAUSING_TIPS)) {
+ //nothing to do
+ }
+ else {
+ btnOk = lv_button_btn_create(scr, BTN_OK_X, BTN_OK_Y, 100, 50, btn_ok_event_cb);
+ lv_obj_t *labelOk = lv_label_create_empty(btnOk); // Add a label to the button
+
+ btnCancel = lv_button_btn_create(scr, BTN_CANCEL_X, BTN_CANCEL_Y, 100, 50, btn_cancel_event_cb);
+ lv_obj_t *labelCancel = lv_label_create_empty(btnCancel); // Add a label to the button
+
+ if (DIALOG_IS(PAUSE_MESSAGE_OPTION)) {
+ lv_label_set_text(labelOk, pause_msg_menu.purgeMore); // Set the labels text
+ lv_label_set_text(labelCancel, pause_msg_menu.continuePrint);
+ }
+ else {
+ lv_label_set_text(labelOk, print_file_dialog_menu.confirm); // Set the labels text
+ lv_label_set_text(labelCancel, print_file_dialog_menu.cancel);
+ }
+ }
+ if (DIALOG_IS(TYPE_PRINT_FILE)) {
+ lv_label_set_text(labelDialog, print_file_dialog_menu.print_file);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+
+ lv_obj_t *labelFile = lv_label_create(scr, list_file.long_name[sel_id]);
+ lv_obj_align(labelFile, nullptr, LV_ALIGN_CENTER, 0, -60);
+ }
+ else if (DIALOG_IS(TYPE_STOP)) {
+ lv_label_set_text(labelDialog, print_file_dialog_menu.cancel_print);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TYPE_FINISH_PRINT)) {
+ lv_label_set_text(labelDialog, print_file_dialog_menu.print_finish);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_PAUSING)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.pausing);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_CHANGING)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.changing);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_UNLOAD)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.unload);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_WAITING)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.waiting);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_INSERT)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.insert);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_LOAD)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.load);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_PURGE)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.purge);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_RESUME)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.resume);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_HEAT)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.heat);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_HEATING)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.heating);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(PAUSE_MESSAGE_OPTION)) {
+ lv_label_set_text(labelDialog, pause_msg_menu.option);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(STORE_EEPROM_TIPS)) {
+ lv_label_set_text(labelDialog, eeprom_menu.storeTips);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(READ_EEPROM_TIPS)) {
+ lv_label_set_text(labelDialog, eeprom_menu.readTips);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(REVERT_EEPROM_TIPS)) {
+ lv_label_set_text(labelDialog, eeprom_menu.revertTips);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(WIFI_CONFIG_TIPS)) {
+ lv_label_set_text(labelDialog, machine_menu.wifiConfigTips);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(WIFI_ENABLE_TIPS)) {
+ lv_label_set_text(labelDialog, print_file_dialog_menu.wifi_enable_tips);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TRANSFER_NO_DEVICE)) {
+ lv_label_set_text(labelDialog, DIALOG_UPDATE_NO_DEVICE_EN);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ #if ENABLED(MKS_WIFI_MODULE)
+ else if (DIALOG_IS(TYPE_UPLOAD_FILE)) {
+ if (upload_result == 1) {
+ lv_label_set_text(labelDialog, DIALOG_UPLOAD_ING_EN);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (upload_result == 2) {
+ lv_label_set_text(labelDialog, DIALOG_UPLOAD_ERROR_EN);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (upload_result == 3) {
+ char buf[200];
+ int _index = 0;
+
+ strcpy(buf, DIALOG_UPLOAD_FINISH_EN);
+ _index = strlen(buf);
+ buf[_index] = '\n';
+ _index++;
+ strcat(buf, DIALOG_UPLOAD_SIZE_EN);
+
+ _index = strlen(buf);
+ buf[_index] = ':';
+ _index++;
+ sprintf(&buf[_index], " %d KBytes\n", (int)(upload_size / 1024));
+
+ strcat(buf, DIALOG_UPLOAD_TIME_EN);
+ _index = strlen(buf);
+ buf[_index] = ':';
+ _index++;
+ sprintf(&buf[_index], " %d s\n", (int)upload_time);
+
+ strcat(buf, DIALOG_UPLOAD_SPEED_EN);
+ _index = strlen(buf);
+ buf[_index] = ':';
+ _index++;
+ sprintf(&buf[_index], " %d KBytes/s\n", (int)(upload_size / upload_time / 1024));
+
+ lv_label_set_text(labelDialog, buf);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ }
+ else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMARE)) {
+ lv_label_set_text(labelDialog, DIALOG_UPDATE_WIFI_FIRMWARE_EN);
+ lv_obj_align(labelDialog, NULL, LV_ALIGN_CENTER, 0, -20);
+ }
+ #endif // MKS_WIFI_MODULE
+ else if (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_load_heat);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_HEAT_LOAD_COMPLETED)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_load_heat_confirm);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_UNLOAD_HEAT)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_unload_heat);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_unload_heat_confirm);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_LOAD_COMPLETED)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_load_completed);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_UNLOAD_COMPLETED)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_unload_completed);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_LOADING)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_loading);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -70);
+ }
+ else if (DIALOG_IS(TYPE_FILAMENT_UNLOADING)) {
+ lv_label_set_text(labelDialog, filament_menu.filament_dialog_unloading);
+ lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -70);
+ }
+ #if ENABLED(MKS_WIFI_MODULE)
+ else if (DIALOG_IS(TYPE_UNBIND)) {
+ lv_label_set_text(labelDialog, common_menu.unbind_printer_tips);
+ lv_obj_align(labelDialog, NULL, LV_ALIGN_CENTER, 0, -70);
+ }
+ #endif
+ else if(DIALOG_IS(TYPE_MACHINE_PAUSING_TIPS)) {
+ lv_label_set_text(labelDialog, print_file_dialog_menu.machinePausingTips);
+ lv_obj_align(labelDialog, NULL, LV_ALIGN_CENTER, 0, 0);
+ }
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ if (btnOk) lv_group_add_obj(g, btnOk);
+ if (btnCancel) lv_group_add_obj(g, btnCancel);
+ }
+ #endif
+}
+
+void filament_sprayer_temp() {
+ char buf[20] = {0};
+ sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target);
+
+ strcpy(public_buf_l, uiCfg.curSprayerChoose < 1 ? extrude_menu.ext1 : extrude_menu.ext2);
+ strcat_P(public_buf_l, PSTR(": "));
+ strcat(public_buf_l, buf);
+ lv_label_set_text(tempText1, public_buf_l);
+ lv_obj_align(tempText1, nullptr, LV_ALIGN_CENTER, 0, -50);
+}
+
+void filament_dialog_handle() {
+ if (temps_update_flag && (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT, TYPE_FILAMENT_UNLOAD_HEAT))) {
+ filament_sprayer_temp();
+ temps_update_flag = false;
+ }
+ if (uiCfg.filament_heat_completed_load == 1) {
+ uiCfg.filament_heat_completed_load = 0;
+ lv_clear_dialog();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOADING);
+ planner.synchronize();
+ uiCfg.filament_loading_time_flg = 1;
+ uiCfg.filament_loading_time_cnt = 0;
+ sprintf_P(public_buf_m, PSTR("T%d\nG91\nG1 E%d F%d\nG90"), uiCfg.curSprayerChoose, gCfgItems.filamentchange_load_length, gCfgItems.filamentchange_load_speed);
+ queue.inject(public_buf_m);
+ }
+ if (uiCfg.filament_heat_completed_unload == 1) {
+ uiCfg.filament_heat_completed_unload = 0;
+ lv_clear_dialog();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOADING);
+ planner.synchronize();
+ uiCfg.filament_unloading_time_flg = 1;
+ uiCfg.filament_unloading_time_cnt = 0;
+ sprintf_P(public_buf_m, PSTR("T%d\nG91\nG1 E-%d F%d\nG90"), uiCfg.curSprayerChoose, gCfgItems.filamentchange_unload_length, gCfgItems.filamentchange_unload_speed);
+ queue.inject(public_buf_m);
+ }
+
+ if (((abs((int)((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius - gCfgItems.filament_limit_temper)) <= 1)
+ || ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius > gCfgItems.filament_limit_temper))
+ && (uiCfg.filament_load_heat_flg == 1)
+ ) {
+ uiCfg.filament_load_heat_flg = 0;
+ lv_clear_dialog();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED);
+ }
+
+ if (uiCfg.filament_loading_completed == 1) {
+ uiCfg.filament_rate = 0;
+ uiCfg.filament_loading_completed = 0;
+ lv_clear_dialog();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOAD_COMPLETED);
+ }
+ if (((abs((int)((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius - gCfgItems.filament_limit_temper)) <= 1)
+ || ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius > gCfgItems.filament_limit_temper))
+ && (uiCfg.filament_unload_heat_flg == 1)
+ ) {
+ uiCfg.filament_unload_heat_flg = 0;
+ lv_clear_dialog();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED);
+ }
+
+ if (uiCfg.filament_unloading_completed == 1) {
+ uiCfg.filament_rate = 0;
+ uiCfg.filament_unloading_completed = 0;
+ lv_clear_dialog();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOAD_COMPLETED);
+ }
+
+ if (DIALOG_IS(TYPE_FILAMENT_LOADING, TYPE_FILAMENT_UNLOADING))
+ lv_filament_setbar();
+}
+
+void lv_filament_setbar() {
+ lv_bar_set_value(filament_bar, uiCfg.filament_rate, LV_ANIM_ON);
+}
+
+void lv_clear_dialog() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.h
new file mode 100644
index 0000000..69b8491
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.h
@@ -0,0 +1,91 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+enum {
+ DIALOG_TYPE_STOP = 0,
+ DIALOG_TYPE_PRINT_FILE,
+ DIALOG_TYPE_REPRINT_NO_FILE,
+
+ DIALOG_TYPE_M80_FAIL,
+ DIALOG_TYPE_MESSAGE_ERR1,
+
+ DIALOG_TYPE_UPDATE_ESP_FIRMARE,
+ DIALOG_TYPE_UPDATE_ESP_DATA,
+ DIALOG_TYPE_UPLOAD_FILE,
+ DIALOG_TYPE_UNBIND,
+
+ DIALOG_TYPE_FILAMENT_LOAD_HEAT,
+ DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED,
+ DIALOG_TYPE_FILAMENT_LOADING,
+ DIALOG_TYPE_FILAMENT_LOAD_COMPLETED,
+ DIALOG_TYPE_FILAMENT_UNLOAD_HEAT,
+ DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED,
+ DIALOG_TYPE_FILAMENT_UNLOADING,
+ DIALOG_TYPE_FILAMENT_UNLOAD_COMPLETED,
+
+ DIALOG_TYPE_FILE_LOADING,
+
+ DIALOG_TYPE_FILAMENT_NO_PRESS,
+ DIALOG_TYPE_FINISH_PRINT,
+
+ DIALOG_WIFI_ENABLE_TIPS,
+
+ DIALOG_PAUSE_MESSAGE_PAUSING,
+ DIALOG_PAUSE_MESSAGE_CHANGING,
+ DIALOG_PAUSE_MESSAGE_UNLOAD,
+ DIALOG_PAUSE_MESSAGE_WAITING,
+ DIALOG_PAUSE_MESSAGE_INSERT,
+ DIALOG_PAUSE_MESSAGE_LOAD,
+ DIALOG_PAUSE_MESSAGE_PURGE,
+ DIALOG_PAUSE_MESSAGE_RESUME,
+ DIALOG_PAUSE_MESSAGE_HEAT,
+ DIALOG_PAUSE_MESSAGE_HEATING,
+ DIALOG_PAUSE_MESSAGE_OPTION,
+
+ DIALOG_STORE_EEPROM_TIPS,
+ DIALOG_READ_EEPROM_TIPS,
+ DIALOG_REVERT_EEPROM_TIPS,
+
+ DIALOG_WIFI_CONFIG_TIPS,
+ DIALOG_TRANSFER_NO_DEVICE,
+ DIALOG_TYPE_MACHINE_PAUSING_TIPS
+};
+
+#define BTN_OK_X 100
+#define BTN_OK_Y 180
+#define BTN_CANCEL_X 280
+#define BTN_CANCEL_Y 180
+
+extern void lv_draw_dialog(uint8_t type);
+extern void lv_clear_dialog();
+extern void filament_sprayer_temp();
+extern void filament_dialog_handle();
+extern void lv_filament_setbar();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.cpp
new file mode 100644
index 0000000..446b942
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.cpp
@@ -0,0 +1,82 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_EEPROM_RETURN = 1,
+ ID_EEPROM_STORE,
+ ID_EEPROM_STORE_ARROW,
+ ID_EEPROM_READ,
+ ID_EEPROM_READ_ARROW,
+ ID_EEPROM_REVERT,
+ ID_EEPROM_REVERT_ARROW
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_EEPROM_RETURN:
+ lv_clear_eeprom_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_EEPROM_STORE:
+ lv_clear_eeprom_settings();
+ lv_draw_dialog(DIALOG_STORE_EEPROM_TIPS);
+ break;
+ #if 0
+ case ID_EEPROM_READ:
+ lv_clear_eeprom_settings();
+ lv_draw_dialog(DIALOG_READ_EEPROM_TIPS);
+ break;
+ #endif
+ case ID_EEPROM_REVERT:
+ lv_clear_eeprom_settings();
+ lv_draw_dialog(DIALOG_REVERT_EEPROM_TIPS);
+ break;
+ }
+}
+
+void lv_draw_eeprom_settings(void) {
+ scr = lv_screen_create(EEPROM_SETTINGS_UI);
+ lv_screen_menu_item(scr, eeprom_menu.revert, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_EEPROM_REVERT, 0);
+ lv_screen_menu_item(scr, eeprom_menu.store, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_EEPROM_STORE, 1);
+ lv_screen_menu_item_return(scr, event_handler, ID_EEPROM_RETURN);
+}
+
+void lv_clear_eeprom_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.h
new file mode 100644
index 0000000..6d5ecf0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_eeprom_settings(void);
+extern void lv_clear_eeprom_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.cpp
new file mode 100644
index 0000000..ab48924
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.cpp
@@ -0,0 +1,72 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+#if BUTTONS_EXIST(EN1, EN2)
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *buttonEncoderState = nullptr;
+
+enum {
+ ID_ENCODER_RETURN = 1,
+ ID_ENCODER_STATE
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_ENCODER_RETURN:
+ lv_clear_encoder_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_ENCODER_STATE:
+ gCfgItems.encoder_enable ^= true;
+ lv_screen_menu_item_onoff_update(buttonEncoderState, gCfgItems.encoder_enable);
+ update_spi_flash();
+ break;
+ }
+}
+
+void lv_draw_encoder_settings(void) {
+ scr = lv_screen_create(ENCODER_SETTINGS_UI, machine_menu.EncoderConfTitle);
+ buttonEncoderState = lv_screen_menu_item_onoff(scr, machine_menu.EncoderConfText, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_ENCODER_STATE, 0, gCfgItems.encoder_enable);
+ lv_screen_menu_item_return(scr, event_handler, ID_ENCODER_RETURN);
+}
+
+void lv_clear_encoder_settings() {
+ #if HAS_ROTARY_ENCODER
+ lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // BUTTONS_EXIST(EN1, EN2)
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.h
new file mode 100644
index 0000000..62892a6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_encoder_settings(void);
+extern void lv_clear_encoder_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.cpp
new file mode 100644
index 0000000..bdae725
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.cpp
@@ -0,0 +1,46 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "tft_lvgl_configuration.h"
+
+#include "SPI_TFT.h"
+#include "mks_hardware_test.h"
+#include "../../../../inc/MarlinConfig.h"
+
+static lv_obj_t *scr;
+
+void lv_draw_error_message(PGM_P const msg) {
+ SPI_TFT.LCD_clear(0x0000);
+ if (msg) disp_string((TFT_WIDTH - strlen(msg) * 16) / 2, 100, msg, 0xFFFF, 0x0000);
+ disp_string((TFT_WIDTH - strlen("PRINTER HALTED") * 16) / 2, 140, "PRINTER HALTED", 0xFFFF, 0x0000);
+ disp_string((TFT_WIDTH - strlen("Please Reset") * 16) / 2, 180, "Please Reset", 0xFFFF, 0x0000);
+}
+
+void lv_clear_error_message() { lv_obj_del(scr); }
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.h
new file mode 100644
index 0000000..35e3bd6
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.h
@@ -0,0 +1,37 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+#ifndef PGM_P
+ #define PGM_P const char *
+#endif
+
+extern void lv_draw_error_message(PGM_P const msg);
+extern void lv_clear_error_message();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.cpp
new file mode 100644
index 0000000..d3574d2
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.cpp
@@ -0,0 +1,266 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/temperature.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../inc/MarlinConfig.h"
+#include "../../../../module/planner.h"
+
+static lv_obj_t *scr;
+extern lv_group_t *g;
+static lv_obj_t *buttonType, *buttonStep, *buttonSpeed;
+static lv_obj_t *labelType;
+static lv_obj_t *labelStep;
+static lv_obj_t *labelSpeed;
+static lv_obj_t *tempText;
+static lv_obj_t *ExtruText;
+
+enum {
+ ID_E_ADD = 1,
+ ID_E_DEC,
+ ID_E_TYPE,
+ ID_E_STEP,
+ ID_E_SPEED,
+ ID_E_RETURN
+};
+
+static int32_t extrudeAmount;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_E_ADD:
+ if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius >= EXTRUDE_MINTEMP) {
+ queue.enqueue_now_P(PSTR("G91"));
+ sprintf_P((char *)public_buf_l, PSTR("G1 E%d F%d"), uiCfg.extruStep, 60 * uiCfg.extruSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G90"));
+ extrudeAmount += uiCfg.extruStep;
+ disp_extru_amount();
+ }
+ break;
+ case ID_E_DEC:
+ if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius >= EXTRUDE_MINTEMP) {
+ queue.enqueue_now_P(PSTR("G91"));
+ sprintf_P((char *)public_buf_l, PSTR("G1 E%d F%d"), 0 - uiCfg.extruStep, 60 * uiCfg.extruSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G90"));
+ extrudeAmount -= uiCfg.extruStep;
+ disp_extru_amount();
+ }
+ break;
+ case ID_E_TYPE:
+ if (ENABLED(HAS_MULTI_EXTRUDER)) {
+ if (uiCfg.curSprayerChoose == 0) {
+ uiCfg.curSprayerChoose = 1;
+ queue.inject_P(PSTR("T1"));
+ }
+ else {
+ uiCfg.curSprayerChoose = 0;
+ queue.inject_P(PSTR("T0"));
+ }
+ }
+ else
+ uiCfg.curSprayerChoose = 0;
+
+ extrudeAmount = 0;
+ disp_hotend_temp();
+ disp_ext_type();
+ disp_extru_amount();
+ break;
+ case ID_E_STEP:
+ switch (abs(uiCfg.extruStep)) {
+ case 1: uiCfg.extruStep = 5; break;
+ case 5: uiCfg.extruStep = 10; break;
+ case 10: uiCfg.extruStep = 1; break;
+ default: break;
+ }
+ disp_ext_step();
+ break;
+ case ID_E_SPEED:
+ switch (uiCfg.extruSpeed) {
+ case 1: uiCfg.extruSpeed = 10; break;
+ case 10: uiCfg.extruSpeed = 20; break;
+ case 20: uiCfg.extruSpeed = 1; break;
+ default: break;
+ }
+ disp_ext_speed();
+ break;
+ case ID_E_RETURN:
+ feedrate_mm_s = (float)uiCfg.moveSpeed_bak;
+ if(uiCfg.print_state == PAUSED)
+ planner.set_e_position_mm((destination.e = current_position.e = uiCfg.current_e_position_bak));
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_extrusion(void) {
+ scr = lv_screen_create(EXTRUSION_UI);
+ // Create image buttons
+ lv_obj_t *buttonAdd = lv_big_button_create(scr, "F:/bmp_in.bin", extrude_menu.in, INTERVAL_V, titleHeight, event_handler, ID_E_ADD);
+ lv_obj_clear_protect(buttonAdd, LV_PROTECT_FOLLOW);
+ lv_big_button_create(scr, "F:/bmp_out.bin", extrude_menu.out, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_E_DEC);
+
+ buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_TYPE);
+ buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_STEP);
+ buttonSpeed = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_SPEED);
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonType);
+ lv_group_add_obj(g, buttonStep);
+ lv_group_add_obj(g, buttonSpeed);
+ }
+ #endif
+
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_RETURN);
+
+ // Create labels on the image buttons
+ labelType = lv_label_create_empty(buttonType);
+ labelStep = lv_label_create_empty(buttonStep);
+ labelSpeed = lv_label_create_empty(buttonSpeed);
+
+ disp_ext_type();
+ disp_ext_step();
+ disp_ext_speed();
+
+ tempText = lv_label_create_empty(scr);
+ lv_obj_set_style(tempText, &tft_style_label_rel);
+ disp_hotend_temp();
+
+ ExtruText = lv_label_create_empty(scr);
+ lv_obj_set_style(ExtruText, &tft_style_label_rel);
+ disp_extru_amount();
+}
+
+void disp_ext_type() {
+ if (uiCfg.curSprayerChoose == 1) {
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru2.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, extrude_menu.ext2);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+ else {
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, extrude_menu.ext1);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void disp_ext_speed() {
+ if (uiCfg.extruSpeed == 20)
+ lv_imgbtn_set_src_both(buttonSpeed, "F:/bmp_speed_high.bin");
+ else if (uiCfg.extruSpeed == 1)
+ lv_imgbtn_set_src_both(buttonSpeed, "F:/bmp_speed_slow.bin");
+ else
+ lv_imgbtn_set_src_both(buttonSpeed, "F:/bmp_speed_normal.bin");
+
+ if (gCfgItems.multiple_language) {
+ if (uiCfg.extruSpeed == 20) {
+ lv_label_set_text(labelSpeed, extrude_menu.high);
+ lv_obj_align(labelSpeed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if (uiCfg.extruSpeed == 1) {
+ lv_label_set_text(labelSpeed, extrude_menu.low);
+ lv_obj_align(labelSpeed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else {
+ lv_label_set_text(labelSpeed, extrude_menu.normal);
+ lv_obj_align(labelSpeed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void disp_hotend_temp() {
+ char buf[20] = {0};
+ #if ENABLED(SINGLENOZZLE)
+ sprintf(buf, extrude_menu.temp_value, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target);
+ #else
+ sprintf(buf, extrude_menu.temp_value, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target);
+ #endif
+ strcpy(public_buf_l, extrude_menu.temper_text);
+ strcat(public_buf_l, buf);
+ lv_label_set_text(tempText, public_buf_l);
+ lv_obj_align(tempText, nullptr, LV_ALIGN_CENTER, 0, -50);
+}
+
+void disp_extru_amount() {
+ char buf1[10] = {0};
+
+ public_buf_l[0] = '\0';
+
+ if (extrudeAmount < 999 && extrudeAmount > -99)
+ sprintf(buf1, extrude_menu.count_value_mm, extrudeAmount);
+ else if (extrudeAmount < 9999 && extrudeAmount > -999)
+ sprintf(buf1, extrude_menu.count_value_cm, extrudeAmount / 10);
+ else
+ sprintf(buf1, extrude_menu.count_value_m, extrudeAmount / 1000);
+ strcat(public_buf_l, uiCfg.curSprayerChoose < 1 ? extrude_menu.ext1 : extrude_menu.ext2);
+ strcat(public_buf_l, buf1);
+
+ lv_label_set_text(ExtruText, public_buf_l);
+ lv_obj_align(ExtruText, nullptr, LV_ALIGN_CENTER, 0, -75);
+}
+
+void disp_ext_step() {
+ if (uiCfg.extruStep == 1)
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step1_mm.bin");
+ else if (uiCfg.extruStep == 5)
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step5_mm.bin");
+ else if (uiCfg.extruStep == 10)
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step10_mm.bin");
+
+ if (gCfgItems.multiple_language) {
+ if (uiCfg.extruStep == 1) {
+ lv_label_set_text(labelStep, extrude_menu.step_1mm);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if (uiCfg.extruStep == 5) {
+ lv_label_set_text(labelStep, extrude_menu.step_5mm);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if (uiCfg.extruStep == 10) {
+ lv_label_set_text(labelStep, extrude_menu.step_10mm);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void lv_clear_extrusion() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.h
new file mode 100644
index 0000000..6178a8e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.h
@@ -0,0 +1,38 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_extrusion(void);
+extern void lv_clear_extrusion();
+extern void disp_ext_type();
+extern void disp_ext_step();
+extern void disp_ext_speed();
+extern void disp_hotend_temp();
+extern void disp_extru_amount();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.cpp
new file mode 100644
index 0000000..ae2f432
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.cpp
@@ -0,0 +1,117 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/temperature.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../gcode/gcode.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *fanText;
+
+enum {
+ ID_F_ADD = 1,
+ ID_F_DEC,
+ ID_F_HIGH,
+ ID_F_MID,
+ ID_F_OFF,
+ ID_F_RETURN
+};
+
+static uint8_t fanSpeed;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+
+ switch (obj->mks_obj_id) {
+ case ID_F_ADD:
+ if (fanSpeed < 254) fanSpeed++;
+ break;
+ case ID_F_DEC:
+ if (fanSpeed > 0) fanSpeed--;
+ break;
+ case ID_F_HIGH:
+ fanSpeed = 255;
+ break;
+ case ID_F_MID:
+ fanSpeed = 127;
+ break;
+ case ID_F_OFF:
+ gcode.process_subcommands_now_P(PSTR("M107"));
+ return;
+ case ID_F_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ return;
+ }
+ sprintf_P(public_buf_l, PSTR("M106 S%d"), fanSpeed);
+ gcode.process_subcommands_now(public_buf_l);
+}
+
+void lv_draw_fan(void) {
+ lv_obj_t *buttonAdd;
+
+ #if HAS_FAN
+ fanSpeed = thermalManager.fan_speed[0];
+ #endif
+
+ scr = lv_screen_create(FAN_UI);
+ // Create an Image button
+ buttonAdd = lv_big_button_create(scr, "F:/bmp_Add.bin", fan_menu.add, INTERVAL_V, titleHeight, event_handler, ID_F_ADD);
+ lv_obj_clear_protect(buttonAdd, LV_PROTECT_FOLLOW);
+ lv_big_button_create(scr, "F:/bmp_Dec.bin", fan_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_F_DEC);
+ lv_big_button_create(scr, "F:/bmp_speed255.bin", fan_menu.full, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_HIGH);
+ lv_big_button_create(scr, "F:/bmp_speed127.bin", fan_menu.half, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_MID);
+ lv_big_button_create(scr, "F:/bmp_speed0.bin", fan_menu.off, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_OFF);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_RETURN);
+
+ fanText = lv_label_create_empty(scr);
+ lv_obj_set_style(fanText, &tft_style_label_rel);
+ disp_fan_value();
+}
+
+void disp_fan_value() {
+ char buf1[10] = {0};
+ public_buf_l[0] = '\0';
+ strcat(public_buf_l, fan_menu.state);
+ strcat_P(public_buf_l, PSTR(": "));
+ sprintf_P(buf1, PSTR("%3d"), thermalManager.fan_speed[0]);
+ strcat(public_buf_l, buf1);
+ lv_label_set_text(fanText, public_buf_l);
+ lv_obj_align(fanText, nullptr, LV_ALIGN_CENTER, 0, -65);
+}
+
+void lv_clear_fan() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.h
new file mode 100644
index 0000000..5a3323e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.h
@@ -0,0 +1,34 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_fan(void);
+extern void lv_clear_fan();
+extern void disp_fan_value();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.cpp
new file mode 100644
index 0000000..d5bdb3f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.cpp
@@ -0,0 +1,216 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/temperature.h"
+#include "../../../../gcode/gcode.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *buttonType;
+static lv_obj_t *labelType;
+static lv_obj_t *tempText1;
+
+enum {
+ ID_FILAMNT_IN = 1,
+ ID_FILAMNT_OUT,
+ ID_FILAMNT_TYPE,
+ ID_FILAMNT_RETURN
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_FILAMNT_IN:
+ uiCfg.filament_load_heat_flg = 1;
+ #if ENABLED(SINGLENOZZLE)
+ if ((abs(thermalManager.temp_hotend[0].target - thermalManager.temp_hotend[0].celsius) <= 1)
+ || (gCfgItems.filament_limit_temper <= thermalManager.temp_hotend[0].celsius)) {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED);
+ }
+ else {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOAD_HEAT);
+ if (thermalManager.temp_hotend[0].target < gCfgItems.filament_limit_temper) {
+ thermalManager.temp_hotend[0].target = gCfgItems.filament_limit_temper;
+ thermalManager.start_watching_hotend(0);
+ }
+ }
+ #else
+ if ((abs(thermalManager.temp_hotend[uiCfg.curSprayerChoose].target - thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius) <= 1)
+ || (gCfgItems.filament_limit_temper <= thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius)) {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED);
+ }
+ else {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOAD_HEAT);
+ if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].target < gCfgItems.filament_limit_temper) {
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = gCfgItems.filament_limit_temper;
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+ }
+ }
+ #endif
+ break;
+ case ID_FILAMNT_OUT:
+ uiCfg.filament_unload_heat_flg=1;
+ #if ENABLED(SINGLENOZZLE)
+ if ((thermalManager.temp_hotend[0].target > 0)
+ && ((abs((int)((int)thermalManager.temp_hotend[0].target - thermalManager.temp_hotend[0].celsius)) <= 1)
+ || ((int)thermalManager.temp_hotend[0].celsius >= gCfgItems.filament_limit_temper))
+ ) {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED);
+ }
+ else {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOAD_HEAT);
+ if (thermalManager.temp_hotend[0].target < gCfgItems.filament_limit_temper) {
+ thermalManager.temp_hotend[0].target = gCfgItems.filament_limit_temper;
+ thermalManager.start_watching_hotend(0);
+ }
+ filament_sprayer_temp();
+ }
+ #else
+ if ((thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > 0)
+ && ((abs((int)((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target - thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius)) <= 1)
+ || ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius >= gCfgItems.filament_limit_temper))
+ ) {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED);
+ }
+ else {
+ lv_clear_filament_change();
+ lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOAD_HEAT);
+ if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].target < gCfgItems.filament_limit_temper) {
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = gCfgItems.filament_limit_temper;
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+ }
+ filament_sprayer_temp();
+ }
+ #endif
+ break;
+ case ID_FILAMNT_TYPE:
+ #if HAS_MULTI_EXTRUDER
+ uiCfg.curSprayerChoose = !uiCfg.curSprayerChoose;
+ #endif
+ disp_filament_type();
+ break;
+ case ID_FILAMNT_RETURN:
+ #if HAS_MULTI_EXTRUDER
+ if (uiCfg.print_state != IDLE && uiCfg.print_state != REPRINTED)
+ gcode.process_subcommands_now_P(uiCfg.curSprayerChoose_bak == 1 ? PSTR("T1") : PSTR("T0"));
+ #endif
+ feedrate_mm_s = (float)uiCfg.moveSpeed_bak;
+ if (uiCfg.print_state == PAUSED)
+ planner.set_e_position_mm((destination.e = current_position.e = uiCfg.current_e_position_bak));
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = uiCfg.desireSprayerTempBak;
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+
+ //Reset filament flag
+ uiCfg.filament_heat_completed_load = 0;
+ uiCfg.filament_heat_completed_unload = 0;
+ uiCfg.filament_load_heat_flg = 0;
+ uiCfg.filament_unload_heat_flg = 0;
+ uiCfg.filament_loading_completed = 0;
+ uiCfg.filament_unloading_completed = 0;
+
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_filament_change(void) {
+ scr = lv_screen_create(FILAMENTCHANGE_UI);
+ // Create an Image button
+ lv_obj_t *buttonIn = lv_big_button_create(scr, "F:/bmp_in.bin", filament_menu.in, INTERVAL_V, titleHeight, event_handler, ID_FILAMNT_IN);
+ lv_obj_clear_protect(buttonIn, LV_PROTECT_FOLLOW);
+ lv_big_button_create(scr, "F:/bmp_out.bin", filament_menu.out, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_FILAMNT_OUT);
+
+ buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_TYPE);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonType);
+ }
+ #endif
+
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_RETURN);
+
+ // Create labels on the image buttons
+ labelType = lv_label_create_empty(buttonType);
+
+ disp_filament_type();
+
+ tempText1 = lv_label_create_empty(scr);
+ lv_obj_set_style(tempText1, &tft_style_label_rel);
+ disp_filament_temp();
+}
+
+void disp_filament_type() {
+ if (uiCfg.curSprayerChoose == 1) {
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru2.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, preheat_menu.ext2);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+ else {
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, preheat_menu.ext1);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void disp_filament_temp() {
+ char buf[20] = {0};
+
+ public_buf_l[0] = '\0';
+
+ strcat(public_buf_l, uiCfg.curSprayerChoose < 1 ? preheat_menu.ext1 : preheat_menu.ext2);
+ sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target);
+
+ strcat_P(public_buf_l, PSTR(": "));
+ strcat(public_buf_l, buf);
+ lv_label_set_text(tempText1, public_buf_l);
+ lv_obj_align(tempText1, nullptr, LV_ALIGN_CENTER, 0, -50);
+}
+
+void lv_clear_filament_change() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.h
new file mode 100644
index 0000000..18efe58
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.h
@@ -0,0 +1,35 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_filament_change(void);
+extern void lv_clear_filament_change();
+extern void disp_filament_type();
+extern void disp_filament_temp();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.cpp
new file mode 100644
index 0000000..ab87fed
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.cpp
@@ -0,0 +1,126 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_FILAMENT_SET_RETURN = 1,
+ ID_FILAMENT_SET_IN_LENGTH,
+ ID_FILAMENT_SET_IN_SPEED,
+ ID_FILAMENT_SET_OUT_LENGTH,
+ ID_FILAMENT_SET_OUT_SPEED,
+ ID_FILAMENT_SET_TEMP,
+ ID_FILAMENT_SET_DOWN,
+ ID_FILAMENT_SET_UP
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_FILAMENT_SET_RETURN:
+ uiCfg.para_ui_page = 0;
+ lv_clear_filament_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_FILAMENT_SET_IN_LENGTH:
+ value = load_length;
+ lv_clear_filament_settings();
+ lv_draw_number_key();
+ break;
+ case ID_FILAMENT_SET_IN_SPEED:
+ value = load_speed;
+ lv_clear_filament_settings();
+ lv_draw_number_key();
+ break;
+ case ID_FILAMENT_SET_OUT_LENGTH:
+ value = unload_length;
+ lv_clear_filament_settings();
+ lv_draw_number_key();
+ break;
+ case ID_FILAMENT_SET_OUT_SPEED:
+ value = unload_speed;
+ lv_clear_filament_settings();
+ lv_draw_number_key();
+ break;
+ case ID_FILAMENT_SET_TEMP:
+ value = filament_temp;
+ lv_clear_filament_settings();
+ lv_draw_number_key();
+ break;
+ case ID_FILAMENT_SET_UP:
+ uiCfg.para_ui_page = 0;
+ lv_clear_filament_settings();
+ lv_draw_filament_settings();
+ break;
+ case ID_FILAMENT_SET_DOWN:
+ uiCfg.para_ui_page = 1;
+ lv_clear_filament_settings();
+ lv_draw_filament_settings();
+ break;
+ }
+}
+
+void lv_draw_filament_settings(void) {
+ scr = lv_screen_create(FILAMENT_SETTINGS_UI, machine_menu.FilamentConfTitle);
+
+ if (uiCfg.para_ui_page != 1) {
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_load_length);
+ lv_screen_menu_item_1_edit(scr, machine_menu.InLength, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FILAMENT_SET_IN_LENGTH, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_load_speed);
+ lv_screen_menu_item_1_edit(scr, machine_menu.InSpeed, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_FILAMENT_SET_IN_SPEED, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_unload_length);
+ lv_screen_menu_item_1_edit(scr, machine_menu.OutLength, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_FILAMENT_SET_OUT_LENGTH, 2, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_unload_speed);
+ lv_screen_menu_item_1_edit(scr, machine_menu.OutSpeed, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_FILAMENT_SET_OUT_SPEED, 3, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_FILAMENT_SET_DOWN);
+ }
+ else {
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filament_limit_temper);
+ lv_screen_menu_item_1_edit(scr, machine_menu.FilamentTemperature, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FILAMENT_SET_TEMP, 0, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_FILAMENT_SET_UP);
+ }
+
+ lv_screen_menu_item_return(scr, event_handler, ID_FILAMENT_SET_RETURN);
+}
+
+void lv_clear_filament_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.h
new file mode 100644
index 0000000..a5ae542
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_filament_settings(void);
+extern void lv_clear_filament_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp
new file mode 100644
index 0000000..1b0a07b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp
@@ -0,0 +1,93 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ready_print.h"
+#include "draw_set.h"
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../gcode/queue.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_H_ALL = 1,
+ ID_H_X,
+ ID_H_Y,
+ ID_H_Z,
+ ID_H_RETURN,
+ ID_H_OFF_ALL,
+ ID_H_OFF_XY
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_H_ALL:
+ queue.inject_P(PSTR("G28"));
+ break;
+ case ID_H_X:
+ queue.inject_P(PSTR("G28 X0"));
+ break;
+ case ID_H_Y:
+ queue.inject_P(PSTR("G28 Y0"));
+ break;
+ case ID_H_Z:
+ queue.inject_P(PSTR("G28 Z0"));
+ break;
+ case ID_H_OFF_ALL:
+ queue.inject_P(PSTR("M84"));
+ break;
+ case ID_H_OFF_XY:
+ queue.inject_P(PSTR("M84 X Y"));
+ break;
+ case ID_H_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_home(void) {
+ scr = lv_screen_create(ZERO_UI);
+ lv_big_button_create(scr, "F:/bmp_zeroAll.bin", home_menu.home_all, INTERVAL_V, titleHeight, event_handler, ID_H_ALL);
+ lv_big_button_create(scr, "F:/bmp_zeroX.bin", home_menu.home_x, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_H_X);
+ lv_big_button_create(scr, "F:/bmp_zeroY.bin", home_menu.home_y, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_H_Y);
+ lv_big_button_create(scr, "F:/bmp_zeroZ.bin", home_menu.home_z, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_H_Z);
+ lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroff, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_ALL);
+ lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroffXY, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_XY);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_RETURN);
+}
+
+void lv_clear_home() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_home.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.h
new file mode 100644
index 0000000..a8f11d9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_home(void);
+extern void lv_clear_home();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.cpp
new file mode 100644
index 0000000..71a0657
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.cpp
@@ -0,0 +1,104 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfig.h"
+
+#if HAS_TFT_LVGL_UI && USE_SENSORLESS
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../module/probe.h"
+#include "../../../../module/stepper/indirection.h"
+#include "../../../../feature/tmc_util.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_SENSITIVITY_RETURN = 1,
+ ID_SENSITIVITY_X,
+ ID_SENSITIVITY_Y,
+ ID_SENSITIVITY_Z,
+ ID_SENSITIVITY_Z2
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_SENSITIVITY_RETURN:
+ lv_clear_homing_sensitivity_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_SENSITIVITY_X:
+ value = x_sensitivity;
+ lv_clear_homing_sensitivity_settings();
+ lv_draw_number_key();
+ break;
+ case ID_SENSITIVITY_Y:
+ value = y_sensitivity;
+ lv_clear_homing_sensitivity_settings();
+ lv_draw_number_key();
+ break;
+ case ID_SENSITIVITY_Z:
+ value = z_sensitivity;
+ lv_clear_homing_sensitivity_settings();
+ lv_draw_number_key();
+ break;
+ #if Z2_SENSORLESS
+ case ID_SENSITIVITY_Z2:
+ value = z2_sensitivity;
+ lv_clear_homing_sensitivity_settings();
+ lv_draw_number_key();
+ break;
+ #endif
+ }
+}
+
+void lv_draw_homing_sensitivity_settings(void) {
+ scr = lv_screen_create(HOMING_SENSITIVITY_UI, machine_menu.HomingSensitivityConfTitle);
+
+ sprintf_P(public_buf_l, PSTR("%d"), TERN(X_SENSORLESS, stepperX.homing_threshold(), 0));
+ lv_screen_menu_item_1_edit(scr, machine_menu.X_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_SENSITIVITY_X, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), TERN(Y_SENSORLESS, stepperY.homing_threshold(), 0));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Y_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_SENSITIVITY_Y, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), TERN(Z_SENSORLESS, stepperZ.homing_threshold(), 0));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Z_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_SENSITIVITY_Z, 2, public_buf_l);
+
+ #if Z2_SENSORLESS
+ sprintf_P(public_buf_l, PSTR("%d"), TERN(Z2_SENSORLESS, stepperZ2.homing_threshold(), 0));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Z2_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_SENSITIVITY_Z2, 3, public_buf_l);
+ #endif
+
+ lv_screen_menu_item_return(scr, event_handler, ID_SENSITIVITY_RETURN);
+}
+
+void lv_clear_homing_sensitivity_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI && USE_SENSORLESS
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.h
new file mode 100644
index 0000000..0c55470
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_homing_sensitivity_settings(void);
+extern void lv_clear_homing_sensitivity_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.cpp
new file mode 100644
index 0000000..38db624
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.cpp
@@ -0,0 +1,99 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, HAS_CLASSIC_JERK)
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_JERK_RETURN = 1,
+ ID_JERK_X,
+ ID_JERK_Y,
+ ID_JERK_Z,
+ ID_JERK_E
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_JERK_RETURN:
+ lv_clear_jerk_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_JERK_X:
+ value = XJerk;
+ lv_clear_jerk_settings();
+ lv_draw_number_key();
+ break;
+ case ID_JERK_Y:
+ value = YJerk;
+ lv_clear_jerk_settings();
+ lv_draw_number_key();
+ break;
+ case ID_JERK_Z:
+ value = ZJerk;
+ lv_clear_jerk_settings();
+ lv_draw_number_key();
+ break;
+ case ID_JERK_E:
+ value = EJerk;
+ lv_clear_jerk_settings();
+ lv_draw_number_key();
+ break;
+ }
+}
+
+void lv_draw_jerk_settings(void) {
+ char str_1[16];
+ scr = lv_screen_create(JERK_UI, machine_menu.JerkConfTitle);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[X_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.X_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_JERK_X, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[Y_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Y_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_JERK_Y, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[Z_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Z_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_JERK_Z, 2, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[E_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.E_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_JERK_E, 3, public_buf_l);
+
+ lv_screen_menu_item_return(scr, event_handler, ID_JERK_RETURN);
+}
+
+void lv_clear_jerk_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI && HAS_CLASSIC_JERK
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.h
new file mode 100644
index 0000000..0531dae
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_jerk_settings(void);
+extern void lv_clear_jerk_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp
new file mode 100644
index 0000000..08615dc
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp
@@ -0,0 +1,289 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+#define LV_KB_CTRL_BTN_FLAGS (LV_BTNM_CTRL_NO_REPEAT | LV_BTNM_CTRL_CLICK_TRIG)
+
+#ifdef FRENCH_KEYBOARD
+static const char * kb_map_lc[] = {"1#", "a", "z", "e", "r", "t", "y", "u", "i", "o", "p", LV_SYMBOL_BACKSPACE, "\n",
+ "ABC", "q", "s", "d", "f", "g", "h", "j", "k", "l", "m", LV_SYMBOL_NEW_LINE, "\n",
+ "_", "-", "w", "x", "c", "v", "b", "n", ",", ";", ":", "!", "\n",
+ LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
+
+static const lv_btnm_ctrl_t kb_ctrl_lc_map[] = {
+ LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7,
+ LV_KB_CTRL_BTN_FLAGS | 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2};
+
+static const char * kb_map_uc[] = {"1#", "A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P", LV_SYMBOL_BACKSPACE, "\n",
+ "abc", "Q", "S", "D", "F", "G", "H", "J", "K", "L", "M", LV_SYMBOL_NEW_LINE, "\n",
+ "_", "-", "W", "X", "C", "V", "B", "N", "?", ".", "/", "^", "\n",
+ LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
+
+static const lv_btnm_ctrl_t kb_ctrl_uc_map[] = {
+ LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7,
+ LV_KB_CTRL_BTN_FLAGS | 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2};
+
+#else
+static const char * kb_map_lc[] = {"1#", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", LV_SYMBOL_BACKSPACE, "\n",
+ "ABC", "a", "s", "d", "f", "g", "h", "j", "k", "l", LV_SYMBOL_NEW_LINE, "\n",
+ "_", "-", "z", "x", "c", "v", "b", "n", "m", ".", ",", ":", "\n",
+ LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
+
+static const lv_btnm_ctrl_t kb_ctrl_lc_map[] = {
+ LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7,
+ LV_KB_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2};
+
+static const char * kb_map_uc[] = {"1#", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", LV_SYMBOL_BACKSPACE, "\n",
+ "abc", "A", "S", "D", "F", "G", "H", "J", "K", "L", LV_SYMBOL_NEW_LINE, "\n",
+ "_", "-", "Z", "X", "C", "V", "B", "N", "M", ".", ",", "^", "\n",
+ LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
+
+static const lv_btnm_ctrl_t kb_ctrl_uc_map[] = {
+ LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7,
+ LV_KB_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2};
+
+#endif
+
+static const char * kb_map_spec[] = {"0", "1", "2", "3", "4" ,"5", "6", "7", "8", "9", ".", LV_SYMBOL_BACKSPACE, "\n",
+ "abc", "+", "-", "/", "*", "=", "%", "!", "?", "#", "<", ">", "\n",
+ "\\", "@", "$", "(", ")", "{", "}", "[", "]", ";", "\"", "'", "\n",
+ LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
+
+static const lv_btnm_ctrl_t kb_ctrl_spec_map[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
+ LV_KB_CTRL_BTN_FLAGS | 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2};
+
+static const lv_btnm_ctrl_t kb_ctrl_num_map[] = {
+ 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
+ 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
+ 1, 1, 1, 2,
+ 1, 1, 1, 1, 1};
+
+static void lv_kb_event_cb(lv_obj_t *kb, lv_event_t event) {
+ if (event != LV_EVENT_VALUE_CHANGED) return;
+
+ lv_kb_ext_t * ext = (lv_kb_ext_t * )lv_obj_get_ext_attr(kb);
+ const uint16_t btn_id = lv_btnm_get_active_btn(kb);
+ if (btn_id == LV_BTNM_BTN_NONE) return;
+ if (lv_btnm_get_btn_ctrl(kb, btn_id, LV_BTNM_CTRL_HIDDEN | LV_BTNM_CTRL_INACTIVE)) return;
+ if (lv_btnm_get_btn_ctrl(kb, btn_id, LV_BTNM_CTRL_NO_REPEAT) && event == LV_EVENT_LONG_PRESSED_REPEAT) return;
+
+ const char * txt = lv_btnm_get_active_btn_text(kb);
+ if (!txt) return;
+
+ // Do the corresponding action according to the text of the button
+ if (strcmp(txt, "abc") == 0) {
+ lv_btnm_set_map(kb, kb_map_lc);
+ lv_btnm_set_ctrl_map(kb, kb_ctrl_lc_map);
+ return;
+ }
+ else if (strcmp(txt, "ABC") == 0) {
+ lv_btnm_set_map(kb, kb_map_uc);
+ lv_btnm_set_ctrl_map(kb, kb_ctrl_uc_map);
+ return;
+ }
+ else if (strcmp(txt, "1#") == 0) {
+ lv_btnm_set_map(kb, kb_map_spec);
+ lv_btnm_set_ctrl_map(kb, kb_ctrl_spec_map);
+ return;
+ }
+ else if (strcmp(txt, LV_SYMBOL_CLOSE) == 0) {
+ if (kb->event_cb != lv_kb_def_event_cb) {
+ lv_clear_keyboard();
+ lv_draw_return_ui();
+ }
+ else {
+ lv_kb_set_ta(kb, nullptr); // De-assign the text area to hide it cursor if needed
+ lv_obj_del(kb);
+ return;
+ }
+ return;
+ }
+ else if (strcmp(txt, LV_SYMBOL_OK) == 0) {
+ if (kb->event_cb != lv_kb_def_event_cb) {
+ const char * ret_ta_txt = lv_ta_get_text(ext->ta);
+ switch (keyboard_value) {
+ #if ENABLED(MKS_WIFI_MODULE)
+ case wifiName:
+ memcpy(uiCfg.wifi_name,ret_ta_txt,sizeof(uiCfg.wifi_name));
+ lv_clear_keyboard();
+ lv_draw_return_ui();
+ break;
+ case wifiPassWord:
+ memcpy(uiCfg.wifi_key,ret_ta_txt,sizeof(uiCfg.wifi_name));
+ lv_clear_keyboard();
+ lv_draw_return_ui();
+ break;
+ case wifiConfig:
+ ZERO(uiCfg.wifi_name);
+ memcpy((void *)uiCfg.wifi_name, wifi_list.wifiName[wifi_list.nameIndex], 32);
+
+ ZERO(uiCfg.wifi_key);
+ memcpy((void *)uiCfg.wifi_key, ret_ta_txt, sizeof(uiCfg.wifi_key));
+
+ gCfgItems.wifi_mode_sel = STA_MODEL;
+
+ package_to_wifi(WIFI_PARA_SET, (uint8_t *)0, 0);
+
+ public_buf_l[0] = 0xA5;
+ public_buf_l[1] = 0x09;
+ public_buf_l[2] = 0x01;
+ public_buf_l[3] = 0x00;
+ public_buf_l[4] = 0x01;
+ public_buf_l[5] = 0xFC;
+ public_buf_l[6] = 0x00;
+ raw_send_to_wifi((uint8_t*)public_buf_l, 6);
+
+ last_disp_state = KEY_BOARD_UI;
+ lv_clear_keyboard();
+ wifi_tips_type = TIPS_TYPE_JOINING;
+ lv_draw_wifi_tips();
+ break;
+ #endif // MKS_WIFI_MODULE
+ case gcodeCommand:
+ uint8_t buf[100];
+ strncpy((char *)buf,ret_ta_txt,sizeof(buf));
+ update_gcode_command(AUTO_LEVELING_COMMAND_ADDR,buf);
+ lv_clear_keyboard();
+ lv_draw_return_ui();
+ break;
+ default: break;
+ }
+ }
+ else
+ lv_kb_set_ta(kb, nullptr); // De-assign the text area to hide it cursor if needed
+ return;
+ }
+
+ // Add the characters to the text area if set
+ if (!ext->ta) return;
+
+ if (strcmp(txt, "Enter") == 0 || strcmp(txt, LV_SYMBOL_NEW_LINE) == 0)
+ lv_ta_add_char(ext->ta, '\n');
+ else if (strcmp(txt, LV_SYMBOL_LEFT) == 0)
+ lv_ta_cursor_left(ext->ta);
+ else if (strcmp(txt, LV_SYMBOL_RIGHT) == 0)
+ lv_ta_cursor_right(ext->ta);
+ else if (strcmp(txt, LV_SYMBOL_BACKSPACE) == 0)
+ lv_ta_del_char(ext->ta);
+ else if (strcmp(txt, "+/-") == 0) {
+ uint16_t cur = lv_ta_get_cursor_pos(ext->ta);
+ const char * ta_txt = lv_ta_get_text(ext->ta);
+ if (ta_txt[0] == '-') {
+ lv_ta_set_cursor_pos(ext->ta, 1);
+ lv_ta_del_char(ext->ta);
+ lv_ta_add_char(ext->ta, '+');
+ lv_ta_set_cursor_pos(ext->ta, cur);
+ }
+ else if (ta_txt[0] == '+') {
+ lv_ta_set_cursor_pos(ext->ta, 1);
+ lv_ta_del_char(ext->ta);
+ lv_ta_add_char(ext->ta, '-');
+ lv_ta_set_cursor_pos(ext->ta, cur);
+ }
+ else {
+ lv_ta_set_cursor_pos(ext->ta, 0);
+ lv_ta_add_char(ext->ta, '-');
+ lv_ta_set_cursor_pos(ext->ta, cur + 1);
+ }
+ }
+ else {
+ lv_ta_add_text(ext->ta, txt);
+ }
+}
+
+void lv_draw_keyboard() {
+ scr = lv_screen_create(KEY_BOARD_UI, "");
+
+ // Create styles for the keyboard
+ static lv_style_t rel_style, pr_style;
+
+ lv_style_copy(&rel_style, &lv_style_btn_rel);
+ rel_style.body.radius = 0;
+ rel_style.body.border.width = 1;
+ rel_style.body.main_color = lv_color_make(0xA9, 0x62, 0x1D);
+ rel_style.body.grad_color = lv_color_make(0xA7, 0x59, 0x0E);
+
+ lv_style_copy(&pr_style, &lv_style_btn_pr);
+ pr_style.body.radius = 0;
+ pr_style.body.border.width = 1;
+ pr_style.body.main_color = lv_color_make(0x72, 0x42, 0x15);
+ pr_style.body.grad_color = lv_color_make(0x6A, 0x3A, 0x0C);
+
+ // Create a keyboard and apply the styles
+ lv_obj_t *kb = lv_kb_create(scr, nullptr);
+ lv_btnm_set_map(kb, kb_map_lc);
+ lv_btnm_set_ctrl_map(kb, kb_ctrl_lc_map);
+ lv_obj_set_base_dir(kb, LV_BIDI_DIR_LTR);
+
+ lv_obj_set_event_cb(kb, lv_kb_event_cb);
+ lv_kb_set_cursor_manage(kb, true);
+ lv_kb_set_style(kb, LV_KB_STYLE_BG, &lv_style_transp_tight);
+ lv_kb_set_style(kb, LV_KB_STYLE_BTN_REL, &rel_style);
+ lv_kb_set_style(kb, LV_KB_STYLE_BTN_PR, &pr_style);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ }
+ #endif
+
+ // Create a text area. The keyboard will write here
+ lv_obj_t *ta = lv_ta_create(scr, nullptr);
+ lv_obj_align(ta, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10);
+ if (keyboard_value == gcodeCommand) {
+ get_gcode_command(AUTO_LEVELING_COMMAND_ADDR,(uint8_t *)public_buf_m);
+ public_buf_m[sizeof(public_buf_m)-1] = 0;
+ lv_ta_set_text(ta, public_buf_m);
+ }
+ else {
+ lv_ta_set_text(ta, "");
+ }
+
+ // Assign the text area to the keyboard
+ lv_kb_set_ta(kb, ta);
+}
+
+void lv_clear_keyboard() {
+ lv_obj_del(scr);
+}
+
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.h
new file mode 100644
index 0000000..0013dc4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_keyboard();
+extern void lv_clear_keyboard();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_language.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.cpp
new file mode 100644
index 0000000..7edb73b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.cpp
@@ -0,0 +1,208 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+#include <string.h>
+
+enum {
+ ID_CN = 1,
+ ID_T_CN,
+ ID_EN,
+ ID_RU,
+ ID_ES,
+ ID_FR,
+ ID_IT,
+ ID_L_RETURN
+};
+
+#define SELECTED 1
+#define UNSELECTED 0
+
+static void disp_language(uint8_t language, uint8_t state);
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *buttonCN, *buttonT_CN, *buttonEN, *buttonRU;
+static lv_obj_t *buttonES, *buttonFR, *buttonIT;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_CN:
+ disp_language(gCfgItems.language, UNSELECTED);
+ lv_imgbtn_set_src_both(buttonCN, "F:/bmp_simplified_cn_sel.bin");
+ lv_obj_refresh_ext_draw_pad(buttonCN);
+ gCfgItems.language = LANG_SIMPLE_CHINESE;
+ update_spi_flash();
+ disp_language_init();
+ break;
+ case ID_T_CN:
+ disp_language(gCfgItems.language, UNSELECTED);
+ lv_imgbtn_set_src_both(buttonT_CN, "F:/bmp_traditional_cn_sel.bin");
+ lv_obj_refresh_ext_draw_pad(buttonT_CN);
+ gCfgItems.language = LANG_COMPLEX_CHINESE;
+ update_spi_flash();
+ disp_language_init();
+ break;
+ case ID_EN:
+ disp_language(gCfgItems.language, UNSELECTED);
+ lv_imgbtn_set_src_both(buttonEN, "F:/bmp_english_sel.bin");
+ lv_obj_refresh_ext_draw_pad(buttonEN);
+ gCfgItems.language = LANG_ENGLISH;
+ update_spi_flash();
+ disp_language_init();
+ break;
+ case ID_RU:
+ disp_language(gCfgItems.language, UNSELECTED);
+ lv_imgbtn_set_src_both(buttonRU, "F:/bmp_russian_sel.bin");
+ lv_obj_refresh_ext_draw_pad(buttonRU);
+ gCfgItems.language = LANG_RUSSIAN;
+ update_spi_flash();
+ disp_language_init();
+ break;
+ case ID_ES:
+ disp_language(gCfgItems.language, UNSELECTED);
+ lv_imgbtn_set_src_both(buttonES, "F:/bmp_spanish_sel.bin");
+ lv_obj_refresh_ext_draw_pad(buttonES);
+ gCfgItems.language = LANG_SPANISH;
+ update_spi_flash();
+ disp_language_init();
+ break;
+ case ID_FR:
+ disp_language(gCfgItems.language, UNSELECTED);
+ lv_imgbtn_set_src_both(buttonFR, "F:/bmp_french_sel.bin");
+ lv_obj_refresh_ext_draw_pad(buttonFR);
+ gCfgItems.language = LANG_FRENCH;
+ update_spi_flash();
+ disp_language_init();
+ break;
+ case ID_IT:
+ disp_language(gCfgItems.language, UNSELECTED);
+ lv_imgbtn_set_src_both(buttonIT, "F:/bmp_italy_sel.bin");
+ lv_obj_refresh_ext_draw_pad(buttonIT);
+ gCfgItems.language = LANG_ITALY;
+ update_spi_flash();
+ disp_language_init();
+ break;
+ case ID_L_RETURN:
+ buttonCN = nullptr;
+ buttonT_CN = nullptr;
+ buttonEN = nullptr;
+ buttonRU = nullptr;
+ buttonES = nullptr;
+ buttonFR = nullptr;
+ buttonFR = nullptr;
+ buttonIT = nullptr;
+ lv_clear_language();
+ lv_draw_set();
+ break;
+ }
+}
+
+static void disp_language(uint8_t language, uint8_t state) {
+ uint16_t id;
+ lv_obj_t *obj;
+
+ public_buf_l[0] = '\0';
+
+ switch (language) {
+ case LANG_SIMPLE_CHINESE:
+ id = ID_CN;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_simplified_cn"));
+ obj = buttonCN;
+ break;
+ case LANG_COMPLEX_CHINESE:
+ id = ID_T_CN;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_traditional_cn"));
+ obj = buttonT_CN;
+ break;
+ case LANG_ENGLISH:
+ id = ID_EN;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_english"));
+ obj = buttonEN;
+ break;
+ case LANG_RUSSIAN:
+ id = ID_RU;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_russian"));
+ obj = buttonRU;
+ break;
+ case LANG_SPANISH:
+ id = ID_ES;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_spanish"));
+ obj = buttonES;
+ break;
+ case LANG_FRENCH:
+ id = ID_FR;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_french"));
+ obj = buttonFR;
+ break;
+ case LANG_ITALY:
+ id = ID_IT;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_italy"));
+ obj = buttonIT;
+ break;
+ default:
+ id = ID_CN;
+ strcpy_P(public_buf_l, PSTR("F:/bmp_simplified_cn"));
+ obj = buttonCN;
+ break;
+ }
+
+ if (state == SELECTED) strcat_P(public_buf_l, PSTR("_sel"));
+
+ strcat_P(public_buf_l, PSTR(".bin"));
+
+ lv_obj_set_event_cb_mks(obj, event_handler, id, "", 0);
+ lv_imgbtn_set_src_both(obj, public_buf_l);
+
+ if (state == UNSELECTED) lv_obj_refresh_ext_draw_pad(obj);
+}
+
+void lv_draw_language(void) {
+ scr = lv_screen_create(LANGUAGE_UI);
+ // Create image buttons
+ buttonCN = lv_big_button_create(scr, "F:/bmp_simplified_cn.bin", language_menu.chinese_s, INTERVAL_V, titleHeight, event_handler, ID_CN);
+ lv_obj_clear_protect(buttonCN, LV_PROTECT_FOLLOW);
+ buttonT_CN = lv_big_button_create(scr, "F:/bmp_traditional_cn.bin", language_menu.chinese_t, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_T_CN);
+ buttonEN = lv_big_button_create(scr, "F:/bmp_english.bin", language_menu.english, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_EN);
+ buttonRU = lv_big_button_create(scr, "F:/bmp_russian.bin", language_menu.russian, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_RU);
+ buttonES = lv_big_button_create(scr, "F:/bmp_spanish.bin", language_menu.spanish, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_ES);
+ buttonFR = lv_big_button_create(scr, "F:/bmp_french.bin", language_menu.french, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FR);
+ buttonIT = lv_big_button_create(scr, "F:/bmp_italy.bin", language_menu.italy, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_IT);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_L_RETURN);
+ disp_language(gCfgItems.language, SELECTED);
+}
+
+void lv_clear_language() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_language.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.h
new file mode 100644
index 0000000..d4ee14f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_language(void);
+extern void lv_clear_language();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp
new file mode 100644
index 0000000..c1f3c57
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp
@@ -0,0 +1,104 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_LEVEL_RETURN = 1,
+ ID_LEVEL_POSITION,
+ ID_LEVEL_COMMAND,
+ ID_LEVEL_ZOFFSET,
+ ID_LEVEL_BLTOUCH,
+ ID_LEVEL_TOUCHMI
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_LEVEL_RETURN:
+ lv_clear_level_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_LEVEL_POSITION:
+ lv_clear_level_settings();
+ lv_draw_manual_level_pos_settings();
+ break;
+ case ID_LEVEL_COMMAND:
+ keyboard_value = gcodeCommand;
+ lv_clear_level_settings();
+ lv_draw_keyboard();
+ break;
+ #if HAS_BED_PROBE
+ case ID_LEVEL_ZOFFSET:
+ lv_clear_level_settings();
+ lv_draw_auto_level_offset_settings();
+ break;
+ #endif
+ #if ENABLED(BLTOUCH)
+ case ID_LEVEL_BLTOUCH:
+ lv_clear_level_settings();
+ bltouch_do_init();
+ lv_draw_bltouch_settings();
+ break;
+ #endif
+ #if ENABLED(TOUCH_MI_PROBE)
+ case ID_LEVEL_TOUCHMI:
+ lv_clear_level_settings();
+ lv_draw_touchmi_settings();
+ break;
+ #endif
+ }
+}
+
+void lv_draw_level_settings(void) {
+
+ scr = lv_screen_create(LEVELING_PARA_UI, machine_menu.LevelingParaConfTitle);
+ lv_screen_menu_item(scr, machine_menu.LevelingManuPosConf, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_LEVEL_POSITION, 0);
+ lv_screen_menu_item(scr, machine_menu.LevelingAutoCommandConf, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_LEVEL_COMMAND, 1);
+ #if HAS_BED_PROBE
+ lv_screen_menu_item(scr, machine_menu.LevelingAutoZoffsetConf, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_LEVEL_ZOFFSET, 2);
+ #endif
+ #if ENABLED(BLTOUCH)
+ lv_screen_menu_item(scr, machine_menu.BLTouchLevelingConf, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_LEVEL_BLTOUCH, 3);
+ #endif
+ #if ENABLED(TOUCH_MI_PROBE)
+ lv_screen_menu_item(scr, machine_menu.LevelingTouchmiConf, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_LEVEL_TOUCHMI, 3);
+ #endif
+ lv_screen_menu_item_return(scr, event_handler, ID_LEVEL_RETURN);
+}
+
+void lv_clear_level_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.h
new file mode 100644
index 0000000..cdca9c8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.h
@@ -0,0 +1,35 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_level_settings(void);
+extern void lv_draw_bltouch_settings(void);
+extern void lv_draw_touchmi_settings(void);
+extern void lv_clear_level_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.cpp
new file mode 100644
index 0000000..ed98dca
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.cpp
@@ -0,0 +1,84 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_PARA_RETURN = 1,
+ ID_PARA_MACHINE,
+ ID_PARA_MOTOR,
+ ID_PARA_LEVEL,
+ ID_PARA_ADVANCE
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_PARA_RETURN:
+ lv_clear_machine_para();
+ lv_draw_return_ui();
+ break;
+ case ID_PARA_MACHINE:
+ lv_clear_machine_para();
+ lv_draw_machine_settings();
+ break;
+ case ID_PARA_MOTOR:
+ lv_clear_machine_para();
+ lv_draw_motor_settings();
+ break;
+ case ID_PARA_LEVEL:
+ lv_clear_machine_para();
+ lv_draw_level_settings();
+ break;
+ case ID_PARA_ADVANCE:
+ lv_clear_machine_para();
+ lv_draw_advance_settings();
+ break;
+ }
+}
+
+void lv_draw_machine_para(void) {
+ scr = lv_screen_create(MACHINE_PARA_UI);
+ lv_screen_menu_item(scr, MachinePara_menu.MachineSetting, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_PARA_MACHINE, 0);
+ lv_screen_menu_item(scr, MachinePara_menu.MotorSetting, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_PARA_MOTOR, 1);
+ lv_screen_menu_item(scr, MachinePara_menu.leveling, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_PARA_LEVEL, 2);
+ lv_screen_menu_item(scr, MachinePara_menu.AdvanceSetting, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_PARA_ADVANCE, 3);
+ lv_screen_menu_item_return(scr, event_handler, ID_PARA_RETURN);
+}
+
+void lv_clear_machine_para() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.h
new file mode 100644
index 0000000..e830f75
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_machine_para(void);
+extern void lv_clear_machine_para();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.cpp
new file mode 100644
index 0000000..7b7cc1e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.cpp
@@ -0,0 +1,82 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_MACHINE_RETURN = 1,
+ ID_MACHINE_ACCELERATION,
+ ID_MACHINE_FEEDRATE,
+ ID_MACHINE_JERK
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_MACHINE_RETURN:
+ lv_clear_machine_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_MACHINE_ACCELERATION:
+ lv_clear_machine_settings();
+ lv_draw_acceleration_settings();
+ break;
+ case ID_MACHINE_FEEDRATE:
+ lv_clear_machine_settings();
+ lv_draw_max_feedrate_settings();
+ break;
+ #if HAS_CLASSIC_JERK
+ case ID_MACHINE_JERK:
+ lv_clear_machine_settings();
+ lv_draw_jerk_settings();
+ break;
+ #endif
+ }
+}
+
+void lv_draw_machine_settings(void) {
+ scr = lv_screen_create(MACHINE_SETTINGS_UI, machine_menu.MachineConfigTitle);
+ lv_screen_menu_item(scr, machine_menu.AccelerationConf, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MACHINE_ACCELERATION, 0);
+ lv_screen_menu_item(scr, machine_menu.MaxFeedRateConf, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_MACHINE_FEEDRATE, 1);
+ #if HAS_CLASSIC_JERK
+ lv_screen_menu_item(scr, machine_menu.JerkConf, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_MACHINE_JERK, 2);
+ #endif
+ lv_screen_menu_item_return(scr, event_handler, ID_MACHINE_RETURN);
+}
+
+void lv_clear_machine_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.h
new file mode 100644
index 0000000..38d02e7
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_machine_settings(void);
+extern void lv_clear_machine_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp
new file mode 100644
index 0000000..338cb1f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp
@@ -0,0 +1,135 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../gcode/queue.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_M_POINT1 = 1,
+ ID_M_POINT2,
+ ID_M_POINT3,
+ ID_M_POINT4,
+ ID_M_POINT5,
+ ID_MANUAL_RETURN
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+
+ switch (obj->mks_obj_id) {
+ case ID_M_POINT1:
+ if (queue.length == 0) {
+ if (uiCfg.leveling_first_time) {
+ queue.enqueue_now_P(PSTR("G28"));
+ uiCfg.leveling_first_time = 0;
+ }
+ queue.enqueue_now_P(PSTR("G1 Z10"));
+ sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[0][0], (int)gCfgItems.levelingPos[0][1]);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G1 Z0"));
+ }
+ break;
+ case ID_M_POINT2:
+ if (queue.length == 0) {
+ if (uiCfg.leveling_first_time) {
+ queue.enqueue_now_P(PSTR("G28"));
+ uiCfg.leveling_first_time = 0;
+ }
+ queue.enqueue_now_P(PSTR("G1 Z10"));
+ sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[1][0], (int)gCfgItems.levelingPos[1][1]);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G1 Z0"));
+ }
+ break;
+ case ID_M_POINT3:
+ if (queue.length == 0) {
+ if (uiCfg.leveling_first_time) {
+ queue.enqueue_now_P(PSTR("G28"));
+ uiCfg.leveling_first_time = 0;
+ }
+ queue.enqueue_now_P(PSTR("G1 Z10"));
+ sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[2][0], (int)gCfgItems.levelingPos[2][1]);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G1 Z0"));
+ }
+
+ break;
+ case ID_M_POINT4:
+ if (queue.length == 0) {
+ if (uiCfg.leveling_first_time) {
+ queue.enqueue_now_P(PSTR("G28"));
+ uiCfg.leveling_first_time = 0;
+ }
+ queue.enqueue_now_P(PSTR("G1 Z10"));
+ sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[3][0], (int)gCfgItems.levelingPos[3][1]);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G1 Z0"));
+ }
+ break;
+ case ID_M_POINT5:
+ if (queue.length == 0) {
+ if (uiCfg.leveling_first_time) {
+ queue.enqueue_now_P(PSTR("G28"));
+ uiCfg.leveling_first_time = 0;
+ }
+ queue.enqueue_now_P(PSTR("G1 Z10"));
+ sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[4][0], (int)gCfgItems.levelingPos[4][1]);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G1 Z0"));
+ }
+ break;
+ case ID_MANUAL_RETURN:
+ lv_clear_manualLevel();
+ lv_draw_tool();
+ break;
+ }
+}
+
+void lv_draw_manualLevel(void) {
+ scr = lv_screen_create(LEVELING_UI);
+ // Create an Image button
+ lv_obj_t *buttonPoint1 = lv_big_button_create(scr, "F:/bmp_leveling1.bin", leveling_menu.position1, INTERVAL_V, titleHeight, event_handler, ID_M_POINT1);
+ lv_obj_clear_protect(buttonPoint1, LV_PROTECT_FOLLOW);
+ lv_big_button_create(scr, "F:/bmp_leveling2.bin", leveling_menu.position2, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_M_POINT2);
+ lv_big_button_create(scr, "F:/bmp_leveling3.bin", leveling_menu.position3, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_M_POINT3);
+ lv_big_button_create(scr, "F:/bmp_leveling4.bin", leveling_menu.position4, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_M_POINT4);
+ lv_big_button_create(scr, "F:/bmp_leveling5.bin", leveling_menu.position5, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_POINT5);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_MANUAL_RETURN);
+}
+
+void lv_clear_manualLevel() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.h
new file mode 100644
index 0000000..60de0b4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_manualLevel(void);
+extern void lv_clear_manualLevel();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.cpp
new file mode 100644
index 0000000..60defc7
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.cpp
@@ -0,0 +1,146 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_MANUAL_POS_RETURN = 1,
+ ID_MANUAL_POS_X1,
+ ID_MANUAL_POS_Y1,
+ ID_MANUAL_POS_X2,
+ ID_MANUAL_POS_Y2,
+ ID_MANUAL_POS_X3,
+ ID_MANUAL_POS_Y3,
+ ID_MANUAL_POS_X4,
+ ID_MANUAL_POS_Y4,
+ ID_MANUAL_POS_X5,
+ ID_MANUAL_POS_Y5,
+ ID_MANUAL_POS_DOWN,
+ ID_MANUAL_POS_UP
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_MANUAL_POS_RETURN:
+ uiCfg.para_ui_page = 0;
+ lv_clear_manual_level_pos_settings();
+ lv_draw_return_ui();
+ return;
+ case ID_MANUAL_POS_X1:
+ value = level_pos_x1;
+ break;
+ case ID_MANUAL_POS_Y1:
+ value = level_pos_y1;
+ break;
+ case ID_MANUAL_POS_X2:
+ value = level_pos_x2;
+ break;
+ case ID_MANUAL_POS_Y2:
+ value = level_pos_y2;
+ break;
+ case ID_MANUAL_POS_X3:
+ value = level_pos_x3;
+ break;
+ case ID_MANUAL_POS_Y3:
+ value = level_pos_y3;
+ break;
+ case ID_MANUAL_POS_X4:
+ value = level_pos_x4;
+ break;
+ case ID_MANUAL_POS_Y4:
+ value = level_pos_y4;
+ break;
+ case ID_MANUAL_POS_X5:
+ value = level_pos_x5;
+ break;
+ case ID_MANUAL_POS_Y5:
+ value = level_pos_y5;
+ break;
+ case ID_MANUAL_POS_UP:
+ uiCfg.para_ui_page = 0;
+ lv_clear_manual_level_pos_settings();
+ lv_draw_manual_level_pos_settings();
+ return;
+ case ID_MANUAL_POS_DOWN:
+ uiCfg.para_ui_page = 1;
+ lv_clear_manual_level_pos_settings();
+ lv_draw_manual_level_pos_settings();
+ return;
+ }
+ lv_clear_manual_level_pos_settings();
+ lv_draw_number_key();
+}
+
+void lv_draw_manual_level_pos_settings(void) {
+ char buf2[50];
+
+ scr = lv_screen_create(MANUAL_LEVELING_POSIGION_UI, machine_menu.LevelingParaConfTitle);
+
+ if (uiCfg.para_ui_page != 1) {
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[0][0]);
+ sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[0][1]);
+ lv_screen_menu_item_2_edit(scr, leveling_menu.position1, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MANUAL_POS_Y1, 0, buf2, ID_MANUAL_POS_X1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[1][0]);
+ sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[1][1]);
+ lv_screen_menu_item_2_edit(scr, leveling_menu.position2, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_MANUAL_POS_Y2, 1, buf2, ID_MANUAL_POS_X2, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[2][0]);
+ sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[2][1]);
+ lv_screen_menu_item_2_edit(scr, leveling_menu.position3, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_MANUAL_POS_Y3, 2, buf2, ID_MANUAL_POS_X3, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[3][0]);
+ sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[3][1]);
+ lv_screen_menu_item_2_edit(scr, leveling_menu.position4, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_MANUAL_POS_Y4, 3, buf2, ID_MANUAL_POS_X4, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_MANUAL_POS_DOWN);
+ }
+ else {
+ sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[4][0]);
+ sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[4][1]);
+ lv_screen_menu_item_2_edit(scr, leveling_menu.position5, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MANUAL_POS_Y5, 0, buf2, ID_MANUAL_POS_X5, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_MANUAL_POS_UP);
+ }
+
+ lv_screen_menu_item_return(scr, event_handler, ID_MANUAL_POS_RETURN);
+}
+
+void lv_clear_manual_level_pos_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.h
new file mode 100644
index 0000000..8e89ecf
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_manual_level_pos_settings(void);
+extern void lv_clear_manual_level_pos_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.cpp
new file mode 100644
index 0000000..0877cf9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.cpp
@@ -0,0 +1,119 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_FEED_RETURN = 1,
+ ID_FEED_X,
+ ID_FEED_Y,
+ ID_FEED_Z,
+ ID_FEED_E0,
+ ID_FEED_E1,
+ ID_FEED_DOWN,
+ ID_FEED_UP
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+
+ lv_clear_max_feedrate_settings();
+ switch (obj->mks_obj_id) {
+ case ID_FEED_RETURN:
+ uiCfg.para_ui_page = 0;
+ lv_draw_return_ui();
+ return;
+ case ID_FEED_X:
+ value = XMaxFeedRate;
+ break;
+ case ID_FEED_Y:
+ value = YMaxFeedRate;
+ break;
+ case ID_FEED_Z:
+ value = ZMaxFeedRate;
+ break;
+ case ID_FEED_E0:
+ value = E0MaxFeedRate;
+ break;
+ case ID_FEED_E1:
+ value = E1MaxFeedRate;
+ break;
+ case ID_FEED_UP:
+ uiCfg.para_ui_page = 0;
+ lv_draw_max_feedrate_settings();
+ return;
+ case ID_FEED_DOWN:
+ uiCfg.para_ui_page = 1;
+ lv_draw_max_feedrate_settings();
+ return;
+ }
+ lv_draw_number_key();
+
+}
+
+void lv_draw_max_feedrate_settings(void) {
+ char str_1[16];
+ scr = lv_screen_create(MAXFEEDRATE_UI, machine_menu.MaxFeedRateConfTitle);
+
+ if (uiCfg.para_ui_page != 1) {
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[X_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.XMaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FEED_X, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Y_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.YMaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_FEED_Y, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Z_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.ZMaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_FEED_Z, 2, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.E0MaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_FEED_E0, 3, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_FEED_DOWN);
+ }
+ else {
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.E1MaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FEED_E1, 0, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_FEED_UP);
+ }
+
+ lv_screen_menu_item_return(scr, event_handler, ID_FEED_RETURN);
+}
+
+void lv_clear_max_feedrate_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.h
new file mode 100644
index 0000000..78caca5
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_max_feedrate_settings(void);
+extern void lv_clear_max_feedrate_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp
new file mode 100644
index 0000000..dbc218b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp
@@ -0,0 +1,119 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "../../../../MarlinCore.h"
+#include "../../../../gcode/queue.h"
+
+#include "lv_conf.h"
+#include "draw_ui.h"
+
+extern lv_group_t * g;
+static lv_obj_t * scr;
+
+enum {
+ ID_CUSTOM_1 = 1,
+ ID_CUSTOM_2,
+ ID_CUSTOM_3,
+ ID_CUSTOM_4,
+ ID_CUSTOM_5,
+ ID_CUSTOM_6,
+ ID_CUSTOM_7,
+ ID_M_RETURN
+};
+
+static void event_handler(lv_obj_t * obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ #if ENABLED(USER_CMD_1_ENABLE)
+ case ID_CUSTOM_1: queue.inject_P(PSTR(USER_GCODE_1)); break;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ case ID_CUSTOM_2: queue.inject_P(PSTR(USER_GCODE_2)); break;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ case ID_CUSTOM_3: queue.inject_P(PSTR(USER_GCODE_3)); break;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ case ID_CUSTOM_4: queue.inject_P(PSTR(USER_GCODE_4)); break;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ case ID_CUSTOM_5: queue.inject_P(PSTR(USER_GCODE_5)); break;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ case ID_CUSTOM_6: queue.inject_P(PSTR(USER_GCODE_6)); break;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ case ID_CUSTOM_7: queue.inject_P(PSTR(USER_GCODE_7)); break;
+ #endif
+ case ID_M_RETURN:
+ lv_clear_more();
+ lv_draw_tool();
+ break;
+ }
+}
+
+void lv_draw_more(void) {
+ scr = lv_screen_create(MORE_UI);
+
+ #if ENABLED(USER_CMD_1_ENABLE)
+ lv_big_button_create(scr, "F:/bmp_custom1.bin", more_menu.custom1, INTERVAL_V, titleHeight, event_handler, ID_CUSTOM_1);
+ #endif
+
+ #if ENABLED(USER_CMD_2_ENABLE)
+ lv_big_button_create(scr, "F:/bmp_custom2.bin", more_menu.custom2, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_CUSTOM_2);
+ #endif
+
+ #if ENABLED(USER_CMD_3_ENABLE)
+ lv_big_button_create(scr, "F:/bmp_custom3.bin", more_menu.custom3, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_CUSTOM_3);
+ #endif
+
+ #if ENABLED(USER_CMD_4_ENABLE)
+ lv_big_button_create(scr, "F:/bmp_custom4.bin", more_menu.custom4, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_CUSTOM_4);
+ #endif
+
+ #if ENABLED(USER_CMD_5_ENABLE)
+ lv_big_button_create(scr, "F:/bmp_custom5.bin", more_menu.custom5, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_5);
+ #endif
+
+ #if ENABLED(USER_CMD_6_ENABLE)
+ lv_big_button_create(scr, "F:/bmp_custom6.bin", more_menu.custom6, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_6);
+ #endif
+
+ #if ENABLED(USER_CMD_7_ENABLE)
+ lv_big_button_create(scr, "F:/bmp_custom7.bin", more_menu.custom7, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_7);
+ #endif
+
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN);
+
+}
+
+void lv_clear_more() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_more.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.h
new file mode 100644
index 0000000..9dfa705
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_more(void);
+extern void lv_clear_more();
+
+#ifdef __cplusplus
+} /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.cpp
new file mode 100644
index 0000000..219ea5a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.cpp
@@ -0,0 +1,98 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_MOTOR_RETURN = 1,
+ ID_MOTOR_STEPS,
+ ID_MOTOR_TMC_CURRENT,
+ ID_MOTOR_STEP_MODE,
+ ID_HOME_SENSE
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ lv_clear_motor_settings();
+ switch (obj->mks_obj_id) {
+ case ID_MOTOR_RETURN:
+ lv_draw_return_ui();
+ break;
+ case ID_MOTOR_STEPS:
+ lv_draw_step_settings();
+ break;
+ #if USE_SENSORLESS
+ case ID_HOME_SENSE:
+ lv_draw_homing_sensitivity_settings();
+ break;
+ #endif
+
+ #if HAS_TRINAMIC_CONFIG
+ case ID_MOTOR_TMC_CURRENT:
+ lv_draw_tmc_current_settings();
+ break;
+ #if HAS_STEALTHCHOP
+ case ID_MOTOR_STEP_MODE:
+ lv_draw_tmc_step_mode_settings();
+ break;
+ #endif
+ #endif
+ }
+}
+
+void lv_draw_motor_settings(void) {
+ int index = 0;
+
+ scr = lv_screen_create(MOTOR_SETTINGS_UI, machine_menu.MotorConfTitle);
+ lv_screen_menu_item(scr, machine_menu.StepsConf, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MOTOR_STEPS, index++);
+ #if USE_SENSORLESS
+ lv_screen_menu_item(scr, machine_menu.HomingSensitivityConf, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_HOME_SENSE, index);
+ index++;
+ #endif
+ #if HAS_TRINAMIC_CONFIG
+ lv_screen_menu_item(scr, machine_menu.TMCcurrentConf, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_MOTOR_TMC_CURRENT, index);
+ index++;
+ #if HAS_STEALTHCHOP
+ lv_screen_menu_item(scr, machine_menu.TMCStepModeConf, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_MOTOR_STEP_MODE, index);
+ index++;
+ #endif
+ #endif
+ lv_screen_menu_item_return(scr, event_handler, ID_MOTOR_RETURN);
+}
+
+void lv_clear_motor_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.h
new file mode 100644
index 0000000..9a1c7a4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_motor_settings(void);
+extern void lv_clear_motor_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp
new file mode 100644
index 0000000..2b76829
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp
@@ -0,0 +1,211 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../gcode/queue.h"
+#include "../../../../module/motion.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+static lv_obj_t *labelV, *buttonV, *labelP;
+static lv_task_t *updatePosTask;
+static char cur_label = 'Z';
+static float cur_pos = 0;
+
+void disp_cur_pos();
+
+enum {
+ ID_M_X_P = 1,
+ ID_M_X_N,
+ ID_M_Y_P,
+ ID_M_Y_N,
+ ID_M_Z_P,
+ ID_M_Z_N,
+ ID_M_STEP,
+ ID_M_RETURN
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ char str_1[16];
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_M_X_P:
+ if (queue.length <= (BUFSIZE - 3)) {
+ queue.enqueue_one_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 X%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_one_P(PSTR("G90"));
+ cur_label = 'X';
+ }
+ break;
+ case ID_M_X_N:
+ if (queue.length <= (BUFSIZE - 3)) {
+ queue.enqueue_now_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 X-%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G90"));
+ cur_label = 'X';
+ }
+ break;
+ case ID_M_Y_P:
+ if (queue.length <= (BUFSIZE - 3)) {
+ queue.enqueue_now_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 Y%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G90"));
+ cur_label = 'Y';
+ }
+ break;
+ case ID_M_Y_N:
+ if (queue.length <= (BUFSIZE - 3)) {
+ queue.enqueue_now_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 Y-%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G90"));
+ cur_label = 'Y';
+ }
+ break;
+ case ID_M_Z_P:
+ if (queue.length <= (BUFSIZE - 3)) {
+ queue.enqueue_now_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 Z%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G90"));
+ cur_label = 'Z';
+ }
+ break;
+ case ID_M_Z_N:
+ if (queue.length <= (BUFSIZE - 3)) {
+ queue.enqueue_now_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 Z-%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed);
+ queue.enqueue_one_now(public_buf_l);
+ queue.enqueue_now_P(PSTR("G90"));
+ cur_label = 'Z';
+ }
+ break;
+ case ID_M_STEP:
+ if (abs(10 * (int)uiCfg.move_dist) == 100)
+ uiCfg.move_dist = 0.1;
+ else
+ uiCfg.move_dist *= (float)10;
+ disp_move_dist();
+ break;
+ case ID_M_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ return;
+ }
+ disp_cur_pos();
+}
+
+void refresh_pos(lv_task_t *)
+{
+ switch(cur_label) {
+ case 'X': cur_pos = current_position.x; break;
+ case 'Y': cur_pos = current_position.y; break;
+ case 'Z': cur_pos = current_position.z; break;
+ default: return;
+ }
+ disp_cur_pos();
+}
+void lv_draw_move_motor(void) {
+ scr = lv_screen_create(MOVE_MOTOR_UI);
+ lv_obj_t *buttonXI = lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_V, titleHeight, event_handler, ID_M_X_P);
+ lv_obj_clear_protect(buttonXI, LV_PROTECT_FOLLOW);
+ lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_X_N);
+ lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_M_Y_P);
+ lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_Y_N);
+ lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_M_Z_P);
+ lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_Z_N);
+
+ // button with image and label changed dynamically by disp_move_dist
+ buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_M_STEP);
+ labelV = lv_label_create_empty(buttonV);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonV);
+ }
+ #endif
+
+
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN);
+
+ // We need to patch the title to leave some space on the right for displaying the status
+ lv_obj_t * title = lv_obj_get_child_back(scr, NULL);
+ if (title != NULL) lv_obj_set_width(title, TFT_WIDTH - 101);
+ labelP = lv_label_create(scr, TFT_WIDTH - 100, TITLE_YPOS, "Z:0.0mm");
+ if (labelP != NULL) {
+ updatePosTask = lv_task_create(refresh_pos, 300, LV_TASK_PRIO_LOWEST, 0);
+ }
+
+
+ disp_move_dist();
+ disp_cur_pos();
+}
+
+
+void disp_cur_pos() {
+ char str_1[16];
+ sprintf_P(public_buf_l, PSTR("%c:%s mm"), cur_label, dtostrf(cur_pos, 1, 1, str_1));
+ if (labelP) lv_label_set_text(labelP, public_buf_l);
+}
+
+void disp_move_dist() {
+ if ((int)(10 * uiCfg.move_dist) == 1)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_step_move0_1.bin");
+ else if ((int)(10 * uiCfg.move_dist) == 10)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_step_move1.bin");
+ else if ((int)(10 * uiCfg.move_dist) == 100)
+ lv_imgbtn_set_src_both(buttonV, "F:/bmp_step_move10.bin");
+
+ if (gCfgItems.multiple_language) {
+ if ((int)(10 * uiCfg.move_dist) == 1) {
+ lv_label_set_text(labelV, move_menu.step_01mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if ((int)(10 * uiCfg.move_dist) == 10) {
+ lv_label_set_text(labelV, move_menu.step_1mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if ((int)(10 * uiCfg.move_dist) == 100) {
+ lv_label_set_text(labelV, move_menu.step_10mm);
+ lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void lv_clear_move_motor() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_task_del(updatePosTask);
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.h
new file mode 100644
index 0000000..4e41c5f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.h
@@ -0,0 +1,34 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_move_motor(void);
+extern void lv_clear_move_motor();
+extern void disp_move_dist();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.cpp
new file mode 100644
index 0000000..9cacf2f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.cpp
@@ -0,0 +1,772 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../gcode/gcode.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../module/planner.h"
+#include "../../../../module/temperature.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if HAS_TRINAMIC_CONFIG
+ #include "../../../../module/stepper/indirection.h"
+ #include "../../../../feature/tmc_util.h"
+#endif
+
+#if HAS_BED_PROBE
+ #include "../../../../module/probe.h"
+#endif
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *buttonValue = nullptr;
+static lv_obj_t *labelValue = nullptr;
+
+static char key_value[11] = { 0 };
+static uint8_t cnt = 0;
+static bool point_flag = true;
+
+enum {
+ ID_NUM_KEY1 = 1,
+ ID_NUM_KEY2,
+ ID_NUM_KEY3,
+ ID_NUM_KEY4,
+ ID_NUM_KEY5,
+ ID_NUM_KEY6,
+ ID_NUM_KEY7,
+ ID_NUM_KEY8,
+ ID_NUM_KEY9,
+ ID_NUM_KEY0,
+ ID_NUM_BACK,
+ ID_NUM_RESET,
+ ID_NUM_CONFIRM,
+ ID_NUM_POINT,
+ ID_NUM_NEGATIVE
+};
+
+static void disp_key_value() {
+ char *temp;
+ char str_1[16];
+ #if HAS_TRINAMIC_CONFIG
+ float milliamps;
+ #endif
+
+ switch (value) {
+ case PrintAcceleration:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.acceleration, 1, 1, str_1));
+ break;
+ case RetractAcceleration:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.retract_acceleration, 1, 1, str_1));
+ break;
+ case TravelAcceleration:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.travel_acceleration, 1, 1, str_1));
+ break;
+ case XAcceleration:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[X_AXIS]);
+ break;
+ case YAcceleration:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Y_AXIS]);
+ break;
+ case ZAcceleration:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Z_AXIS]);
+ break;
+ case E0Acceleration:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS]);
+ break;
+ case E1Acceleration:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)]);
+ break;
+ case XMaxFeedRate:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[X_AXIS], 1, 1, str_1));
+ break;
+ case YMaxFeedRate:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Y_AXIS], 1, 1, str_1));
+ break;
+ case ZMaxFeedRate:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Z_AXIS], 1, 1, str_1));
+ break;
+ case E0MaxFeedRate:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS], 1, 1, str_1));
+ break;
+ case E1MaxFeedRate:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], 1, 1, str_1));
+ break;
+
+ case XJerk:
+ #if HAS_CLASSIC_JERK
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[X_AXIS], 1, 1, str_1));
+ #endif
+ break;
+ case YJerk:
+ #if HAS_CLASSIC_JERK
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[Y_AXIS], 1, 1, str_1));
+ #endif
+ break;
+ case ZJerk:
+ #if HAS_CLASSIC_JERK
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[Z_AXIS], 1, 1, str_1));
+ #endif
+ break;
+ case EJerk:
+ #if HAS_CLASSIC_JERK
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[E_AXIS], 1, 1, str_1));
+ #endif
+ break;
+
+ case Xstep:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[X_AXIS], 1, 1, str_1));
+ break;
+ case Ystep:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Y_AXIS], 1, 1, str_1));
+
+ break;
+ case Zstep:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Z_AXIS], 1, 1, str_1));
+
+ break;
+ case E0step:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS], 1, 1, str_1));
+
+ break;
+ case E1step:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS_N(1)], 1, 1, str_1));
+ break;
+
+ case Xcurrent:
+ #if AXIS_IS_TMC(X)
+ milliamps = stepperX.getMilliamps();
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ #endif
+ break;
+
+ case Ycurrent:
+ #if AXIS_IS_TMC(Y)
+ milliamps = stepperY.getMilliamps();
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ #endif
+ break;
+
+ case Zcurrent:
+ #if AXIS_IS_TMC(Z)
+ milliamps = stepperZ.getMilliamps();
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ #endif
+ break;
+
+ case E0current:
+ #if AXIS_IS_TMC(E0)
+ milliamps = stepperE0.getMilliamps();
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ #endif
+ break;
+
+ case E1current:
+ #if AXIS_IS_TMC(E1)
+ milliamps = stepperE1.getMilliamps();
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ #endif
+ break;
+
+ case pause_pos_x:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(gCfgItems.pausePosX, 1, 1, str_1));
+ break;
+ case pause_pos_y:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(gCfgItems.pausePosY, 1, 1, str_1));
+ break;
+ case pause_pos_z:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(gCfgItems.pausePosZ, 1, 1, str_1));
+ break;
+ case level_pos_x1:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[0][0]);
+ break;
+ case level_pos_y1:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[0][1]);
+ break;
+ case level_pos_x2:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[1][0]);
+ break;
+ case level_pos_y2:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[1][1]);
+ break;
+ case level_pos_x3:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[2][0]);
+ break;
+ case level_pos_y3:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[2][1]);
+ break;
+ case level_pos_x4:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[3][0]);
+ break;
+ case level_pos_y4:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[3][1]);
+ break;
+ case level_pos_x5:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[4][0]);
+ break;
+ case level_pos_y5:
+ sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[4][1]);
+ break;
+ #if HAS_BED_PROBE
+ case x_offset:
+ #if HAS_PROBE_XY_OFFSET
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(probe.offset.x, 1, 3, str_1));
+ #endif
+ break;
+ case y_offset:
+ #if HAS_PROBE_XY_OFFSET
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(probe.offset.y, 1, 3, str_1));
+ #endif
+ break;
+ case z_offset:
+ sprintf_P(public_buf_m, PSTR("%s"), dtostrf(probe.offset.z, 1, 3, str_1));
+ break;
+ #endif
+ case load_length:
+ sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_load_length);
+ break;
+ case load_speed:
+ sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_load_speed);
+ break;
+ case unload_length:
+ sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_unload_length);
+ break;
+ case unload_speed:
+ sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_unload_speed);
+ break;
+ case filament_temp:
+ sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filament_limit_temper);
+ break;
+ case x_sensitivity:
+ #if X_SENSORLESS
+ sprintf_P(public_buf_m, PSTR("%d"), TERN(X_SENSORLESS, stepperX.homing_threshold(), 0));
+ #endif
+ break;
+ case y_sensitivity:
+ #if Y_SENSORLESS
+ sprintf_P(public_buf_m, PSTR("%d"), TERN(Y_SENSORLESS, stepperY.homing_threshold(), 0));
+ #endif
+ break;
+ case z_sensitivity:
+ #if Z_SENSORLESS
+ sprintf_P(public_buf_m, PSTR("%d"), TERN(Z_SENSORLESS, stepperZ.homing_threshold(), 0));
+ #endif
+ break;
+ case z2_sensitivity:
+ #if Z2_SENSORLESS
+ sprintf_P(public_buf_m, PSTR("%d"), TERN(Z2_SENSORLESS, stepperZ2.homing_threshold(), 0));
+ #endif
+ break;
+ }
+
+ strcpy(key_value, public_buf_m);
+ cnt = strlen(key_value);
+ temp = strchr(key_value, '.');
+ point_flag = !temp;
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+
+}
+
+static void set_value_confirm() {
+ #if HAS_TRINAMIC_CONFIG
+ uint16_t current_mA;
+ #endif
+ switch (value) {
+ case PrintAcceleration:
+ planner.settings.acceleration = atof(key_value);
+ break;
+ case RetractAcceleration:
+ planner.settings.retract_acceleration = atof(key_value);
+ break;
+ case TravelAcceleration:
+ planner.settings.travel_acceleration = atof(key_value);
+ break;
+ case XAcceleration:
+ planner.settings.max_acceleration_mm_per_s2[X_AXIS] = atof(key_value);
+ break;
+ case YAcceleration:
+ planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = atof(key_value);
+ break;
+ case ZAcceleration:
+ planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = atof(key_value);
+ break;
+ case E0Acceleration:
+ planner.settings.max_acceleration_mm_per_s2[E_AXIS] = atof(key_value);
+ break;
+ case E1Acceleration:
+ planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)] = atof(key_value);
+ break;
+ case XMaxFeedRate:
+ planner.settings.max_feedrate_mm_s[X_AXIS] = atof(key_value);
+ break;
+ case YMaxFeedRate:
+ planner.settings.max_feedrate_mm_s[Y_AXIS] = atof(key_value);
+ break;
+ case ZMaxFeedRate:
+ planner.settings.max_feedrate_mm_s[Z_AXIS] = atof(key_value);
+ break;
+ case E0MaxFeedRate:
+ planner.settings.max_feedrate_mm_s[E_AXIS] = atof(key_value);
+ break;
+ case E1MaxFeedRate:
+ planner.settings.max_feedrate_mm_s[E_AXIS_N(1)] = atof(key_value);
+ break;
+ case XJerk:
+ #if HAS_CLASSIC_JERK
+ planner.max_jerk[X_AXIS] = atof(key_value);
+ #endif
+ break;
+ case YJerk:
+ #if HAS_CLASSIC_JERK
+ planner.max_jerk[Y_AXIS] = atof(key_value);
+ #endif
+ break;
+ case ZJerk:
+ #if HAS_CLASSIC_JERK
+ planner.max_jerk[Z_AXIS] = atof(key_value);
+ #endif
+ break;
+ case EJerk:
+ #if HAS_CLASSIC_JERK
+ planner.max_jerk[E_AXIS] = atof(key_value);
+ #endif
+ break;
+ case Xstep:
+ planner.settings.axis_steps_per_mm[X_AXIS] = atof(key_value);
+ planner.refresh_positioning();
+ break;
+ case Ystep:
+ planner.settings.axis_steps_per_mm[Y_AXIS] = atof(key_value);
+ planner.refresh_positioning();
+ break;
+ case Zstep:
+ planner.settings.axis_steps_per_mm[Z_AXIS] = atof(key_value);
+ planner.refresh_positioning();
+ break;
+ case E0step:
+ planner.settings.axis_steps_per_mm[E_AXIS] = atof(key_value);
+ planner.refresh_positioning();
+ break;
+ case E1step:
+ planner.settings.axis_steps_per_mm[E_AXIS_N(1)] = atof(key_value);
+ planner.refresh_positioning();
+ break;
+ case Xcurrent:
+ #if AXIS_IS_TMC(X)
+ current_mA = atoi(key_value);
+ stepperX.rms_current(current_mA);
+ #endif
+ break;
+ case Ycurrent:
+ #if AXIS_IS_TMC(Y)
+ current_mA = atoi(key_value);
+ stepperY.rms_current(current_mA);
+ #endif
+ break;
+ case Zcurrent:
+ #if AXIS_IS_TMC(Z)
+ current_mA = atoi(key_value);
+ stepperZ.rms_current(current_mA);
+ #endif
+ break;
+ case E0current:
+ #if AXIS_IS_TMC(E0)
+ current_mA = atoi(key_value);
+ stepperE0.rms_current(current_mA);
+ #endif
+ break;
+ case E1current:
+ #if AXIS_IS_TMC(E1)
+ current_mA = atoi(key_value);
+ stepperE1.rms_current(current_mA);
+ #endif
+ break;
+ case pause_pos_x:
+ gCfgItems.pausePosX = atof(key_value);
+ update_spi_flash();
+ break;
+ case pause_pos_y:
+ gCfgItems.pausePosY = atof(key_value);
+ update_spi_flash();
+ break;
+ case pause_pos_z:
+ gCfgItems.pausePosZ = atof(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_x1:
+ gCfgItems.levelingPos[0][0] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_y1:
+ gCfgItems.levelingPos[0][1] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_x2:
+ gCfgItems.levelingPos[1][0] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_y2:
+ gCfgItems.levelingPos[1][1] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_x3:
+ gCfgItems.levelingPos[2][0] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_y3:
+ gCfgItems.levelingPos[2][1] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_x4:
+ gCfgItems.levelingPos[3][0] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_y4:
+ gCfgItems.levelingPos[3][1] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_x5:
+ gCfgItems.levelingPos[4][0] = atoi(key_value);
+ update_spi_flash();
+ break;
+ case level_pos_y5:
+ gCfgItems.levelingPos[4][1] = atoi(key_value);
+ update_spi_flash();
+ break;
+ #if HAS_BED_PROBE
+ case x_offset:
+ #if HAS_PROBE_XY_OFFSET
+ float x;
+ x = atof(key_value);
+ if (WITHIN(x, -(X_BED_SIZE), X_BED_SIZE))
+ probe.offset.x = x;
+ #endif
+ break;
+ case y_offset:
+ #if HAS_PROBE_XY_OFFSET
+ float y;
+ y = atof(key_value);
+ if (WITHIN(y, -(Y_BED_SIZE), Y_BED_SIZE))
+ probe.offset.y = y;
+ #endif
+ break;
+ case z_offset:
+ float z;
+ z = atof(key_value);
+ if (WITHIN(z, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX))
+ probe.offset.z = z;
+ break;
+ #endif
+ case load_length:
+ gCfgItems.filamentchange_load_length = atoi(key_value);
+ uiCfg.filament_loading_time = (uint32_t)((gCfgItems.filamentchange_load_length*60.0/gCfgItems.filamentchange_load_speed)+0.5);
+ update_spi_flash();
+ break;
+ case load_speed:
+ gCfgItems.filamentchange_load_speed = atoi(key_value);
+ uiCfg.filament_loading_time = (uint32_t)((gCfgItems.filamentchange_load_length*60.0/gCfgItems.filamentchange_load_speed)+0.5);
+ update_spi_flash();
+ break;
+ case unload_length:
+ gCfgItems.filamentchange_unload_length = atoi(key_value);
+ uiCfg.filament_unloading_time = (uint32_t)((gCfgItems.filamentchange_unload_length*60.0/gCfgItems.filamentchange_unload_speed)+0.5);
+ update_spi_flash();
+ break;
+ case unload_speed:
+ gCfgItems.filamentchange_unload_speed = atoi(key_value);
+ uiCfg.filament_unloading_time = (uint32_t)((gCfgItems.filamentchange_unload_length*60.0/gCfgItems.filamentchange_unload_speed)+0.5);
+ update_spi_flash();
+ break;
+ case filament_temp:
+ gCfgItems.filament_limit_temper = atoi(key_value);
+ update_spi_flash();
+ break;
+ case x_sensitivity:
+ #if X_SENSORLESS
+ stepperX.homing_threshold(atoi(key_value));
+ #endif
+ break;
+ case y_sensitivity:
+ #if Y_SENSORLESS
+ stepperY.homing_threshold(atoi(key_value));
+ #endif
+ break;
+ case z_sensitivity:
+ #if Z_SENSORLESS
+ stepperZ.homing_threshold(atoi(key_value));
+ #endif
+ break;
+ case z2_sensitivity:
+ #if Z2_SENSORLESS
+ stepperZ2.homing_threshold(atoi(key_value));
+ #endif
+ break;
+ }
+ watchdog_refresh();
+ gcode.process_subcommands_now_P(PSTR("M500"));
+}
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_NUM_KEY1:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'1';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY2:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'2';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY3:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'3';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY4:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'4';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY5:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'5';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY6:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'6';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY7:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'7';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY8:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'8';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY9:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'9';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_KEY0:
+ if (cnt <= 10) {
+ key_value[cnt] = (char)'0';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_BACK:
+ if (cnt > 0) cnt--;
+ if (key_value[cnt] == (char)'.') point_flag = true;
+ key_value[cnt] = (char)'\0';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ break;
+ case ID_NUM_RESET:
+ ZERO(key_value);
+ cnt = 0;
+ key_value[cnt] = (char)'0';
+ point_flag = true;
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ break;
+ case ID_NUM_POINT:
+ if (cnt != 0 && point_flag) {
+ point_flag = false;
+ key_value[cnt] = (char)'.';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_NEGATIVE:
+ if (cnt == 0) {
+ key_value[cnt] = (char)'-';
+ lv_label_set_text(labelValue, key_value);
+ lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0);
+ cnt++;
+ }
+ break;
+ case ID_NUM_CONFIRM:
+ last_disp_state = NUMBER_KEY_UI;
+ if (strlen(key_value) != 0) set_value_confirm();
+ lv_clear_number_key();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_number_key(void) {
+ scr = lv_screen_create(NUMBER_KEY_UI, "");
+
+ buttonValue = lv_btn_create(scr, 92, 40, 296, 40, event_handler, 0, &style_num_text);
+ labelValue = lv_label_create_empty(buttonValue);
+
+ lv_obj_t *NumberKey_1 = lv_btn_create(scr, 92, 90, 68, 40, event_handler, ID_NUM_KEY1, &style_num_key_pre);
+ lv_obj_t *labelKey_1 = lv_label_create_empty(NumberKey_1);
+ lv_label_set_text(labelKey_1, machine_menu.key_1);
+ lv_obj_align(labelKey_1, NumberKey_1, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_2 = lv_btn_create(scr, 168, 90, 68, 40, event_handler, ID_NUM_KEY2, &style_num_key_pre);
+ lv_obj_t *labelKey_2 = lv_label_create_empty(NumberKey_2);
+ lv_label_set_text(labelKey_2, machine_menu.key_2);
+ lv_obj_align(labelKey_2, NumberKey_2, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_3 = lv_btn_create(scr, 244, 90, 68, 40, event_handler, ID_NUM_KEY3, &style_num_key_pre);
+ lv_obj_t *labelKey_3 = lv_label_create_empty(NumberKey_3);
+ lv_label_set_text(labelKey_3, machine_menu.key_3);
+ lv_obj_align(labelKey_3, NumberKey_3, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_4 = lv_btn_create(scr, 92, 140, 68, 40, event_handler, ID_NUM_KEY4, &style_num_key_pre);
+ lv_obj_t *labelKey_4 = lv_label_create_empty(NumberKey_4);
+ lv_label_set_text(labelKey_4, machine_menu.key_4);
+ lv_obj_align(labelKey_4, NumberKey_4, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_5 = lv_btn_create(scr, 168, 140, 68, 40, event_handler, ID_NUM_KEY5, &style_num_key_pre);
+ lv_obj_t *labelKey_5 = lv_label_create_empty(NumberKey_5);
+ lv_label_set_text(labelKey_5, machine_menu.key_5);
+ lv_obj_align(labelKey_5, NumberKey_5, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_6 = lv_btn_create(scr, 244, 140, 68, 40, event_handler, ID_NUM_KEY6, &style_num_key_pre);
+ lv_obj_t *labelKey_6 = lv_label_create_empty(NumberKey_6);
+ lv_label_set_text(labelKey_6, machine_menu.key_6);
+ lv_obj_align(labelKey_6, NumberKey_6, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_7 = lv_btn_create(scr, 92, 190, 68, 40, event_handler, ID_NUM_KEY7, &style_num_key_pre);
+ lv_obj_t *labelKey_7 = lv_label_create_empty(NumberKey_7);
+ lv_label_set_text(labelKey_7, machine_menu.key_7);
+ lv_obj_align(labelKey_7, NumberKey_7, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_8 = lv_btn_create(scr, 168, 190, 68, 40, event_handler, ID_NUM_KEY8, &style_num_key_pre);
+ lv_obj_t *labelKey_8 = lv_label_create_empty(NumberKey_8);
+ lv_label_set_text(labelKey_8, machine_menu.key_8);
+ lv_obj_align(labelKey_8, NumberKey_8, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_9 = lv_btn_create(scr, 244, 190, 68, 40, event_handler, ID_NUM_KEY9, &style_num_key_pre);
+ lv_obj_t *labelKey_9 = lv_label_create_empty(NumberKey_9);
+ lv_label_set_text(labelKey_9, machine_menu.key_9);
+ lv_obj_align(labelKey_9, NumberKey_9, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *NumberKey_0 = lv_btn_create(scr, 92, 240, 68, 40, event_handler, ID_NUM_KEY0, &style_num_key_pre);
+ lv_obj_t *labelKey_0 = lv_label_create_empty(NumberKey_0);
+ lv_label_set_text(labelKey_0, machine_menu.key_0);
+ lv_obj_align(labelKey_0, NumberKey_0, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *Minus = lv_btn_create(scr, 168, 240, 68, 40, event_handler, ID_NUM_NEGATIVE, &style_num_key_pre);
+ lv_obj_t *labelMinus = lv_label_create_empty(Minus);
+ lv_label_set_text(labelMinus, machine_menu.negative);
+ lv_obj_align(labelMinus, Minus, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *KeyPoint = lv_btn_create(scr, 244, 240, 68, 40, event_handler, ID_NUM_POINT, &style_num_key_pre);
+ lv_obj_t *labelKeyPoint = lv_label_create_empty(KeyPoint);
+ lv_label_set_text(labelKeyPoint, machine_menu.key_point);
+ lv_obj_align(labelKeyPoint, KeyPoint, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *KeyBack = lv_btn_create(scr, 320, 90, 68, 40, event_handler, ID_NUM_BACK, &style_num_key_pre);
+ lv_obj_t *labelKeyBack = lv_label_create_empty(KeyBack);
+ lv_label_set_text(labelKeyBack, machine_menu.key_back);
+ lv_obj_align(labelKeyBack, KeyBack, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *KeyReset = lv_btn_create(scr, 320, 140, 68, 40, event_handler, ID_NUM_RESET, &style_num_key_pre);
+ lv_obj_t *labelKeyReset = lv_label_create_empty(KeyReset);
+ lv_label_set_text(labelKeyReset, machine_menu.key_reset);
+ lv_obj_align(labelKeyReset, KeyReset, LV_ALIGN_CENTER, 0, 0);
+
+ lv_obj_t *KeyConfirm = lv_btn_create(scr, 320, 190, 68, 90, event_handler, ID_NUM_CONFIRM, &style_num_key_pre);
+ lv_obj_t *labelKeyConfirm = lv_label_create_empty(KeyConfirm);
+ lv_label_set_text(labelKeyConfirm, machine_menu.key_confirm);
+ lv_obj_align(labelKeyConfirm, KeyConfirm, LV_ALIGN_CENTER, 0, 0);
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, NumberKey_1);
+ lv_group_add_obj(g, NumberKey_2);
+ lv_group_add_obj(g, NumberKey_3);
+ lv_group_add_obj(g, KeyBack);
+ lv_group_add_obj(g, NumberKey_4);
+ lv_group_add_obj(g, NumberKey_5);
+ lv_group_add_obj(g, NumberKey_6);
+ lv_group_add_obj(g, KeyReset);
+ lv_group_add_obj(g, NumberKey_7);
+ lv_group_add_obj(g, NumberKey_8);
+ lv_group_add_obj(g, NumberKey_9);
+ lv_group_add_obj(g, NumberKey_0);
+ lv_group_add_obj(g, Minus);
+ lv_group_add_obj(g, KeyPoint);
+ lv_group_add_obj(g, KeyConfirm);
+ }
+ #endif
+
+ disp_key_value();
+}
+
+void lv_clear_number_key() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.h
new file mode 100644
index 0000000..7902da3
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_number_key(void);
+extern void lv_clear_number_key();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.cpp
new file mode 100644
index 0000000..9233991
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.cpp
@@ -0,0 +1,230 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../sd/cardreader.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_O_PRE_HEAT = 1,
+ ID_O_EXTRUCT,
+ ID_O_MOV,
+ ID_O_FILAMENT,
+ ID_O_SPEED,
+ ID_O_RETURN,
+ ID_O_FAN,
+ ID_O_POWER_OFF,
+ ID_O_BABY_STEP
+};
+
+static lv_obj_t *label_PowerOff;
+static lv_obj_t *buttonPowerOff;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_O_PRE_HEAT:
+ lv_clear_operation();
+ lv_draw_preHeat();
+ break;
+ case ID_O_EXTRUCT:
+ uiCfg.moveSpeed_bak = (uint16_t)feedrate_mm_s;
+ lv_clear_operation();
+ lv_draw_extrusion();
+ break;
+ case ID_O_MOV:
+ lv_clear_operation();
+ lv_draw_move_motor();
+ break;
+ case ID_O_FILAMENT:
+ #if HAS_MULTI_EXTRUDER
+ uiCfg.curSprayerChoose_bak = active_extruder;
+ #endif
+ if (uiCfg.print_state == WORKING) {
+ #if ENABLED(SDSUPPORT)
+ card.pauseSDPrint();
+ stop_print_time();
+ uiCfg.print_state = PAUSING;
+ #endif
+ }
+ uiCfg.moveSpeed_bak = (uint16_t)feedrate_mm_s;
+ uiCfg.desireSprayerTempBak = thermalManager.temp_hotend[active_extruder].target;
+ lv_clear_operation();
+ lv_draw_filament_change();
+ break;
+ case ID_O_FAN:
+ lv_clear_operation();
+ lv_draw_fan();
+ break;
+ case ID_O_SPEED:
+ lv_clear_operation();
+ lv_draw_change_speed();
+ break;
+ case ID_O_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ case ID_O_POWER_OFF:
+ if (gCfgItems.finish_power_off) {
+ gCfgItems.finish_power_off = false;
+ lv_imgbtn_set_src_both(buttonPowerOff, "F:/bmp_manual_off.bin");
+ lv_label_set_text(label_PowerOff, printing_more_menu.manual);
+ }
+ else {
+ gCfgItems.finish_power_off = true;
+ lv_imgbtn_set_src_both(buttonPowerOff, "F:/bmp_auto_off.bin");
+ lv_label_set_text(label_PowerOff, printing_more_menu.auto_close);
+ }
+ lv_obj_align(label_PowerOff, buttonPowerOff, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ lv_obj_refresh_ext_draw_pad(label_PowerOff);
+ update_spi_flash();
+ break;
+ case ID_O_BABY_STEP:
+ lv_clear_operation();
+ lv_draw_baby_stepping();
+ break;
+ }
+}
+
+void lv_draw_operation(void) {
+ lv_obj_t *buttonExtrusion = nullptr, *buttonSpeed = nullptr,
+ *buttonBack = nullptr,
+ *labelPreHeat = nullptr, *labelExtrusion = nullptr,
+ *label_Back = nullptr, *label_Speed = nullptr, *label_Fan = nullptr,
+ *buttonMove = nullptr, *label_Move = nullptr,
+ *buttonBabyStep = nullptr, *label_BabyStep = nullptr,
+ *label_Filament = nullptr;
+
+ scr = lv_screen_create(OPERATE_UI);
+
+ // Create image buttons
+ lv_obj_t *buttonPreHeat = lv_imgbtn_create(scr, "F:/bmp_temp.bin", INTERVAL_V, titleHeight, event_handler, ID_O_PRE_HEAT);
+ lv_obj_t *buttonFilament = lv_imgbtn_create(scr, "F:/bmp_filamentchange.bin", BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_O_FILAMENT);
+ lv_obj_t *buttonFan = lv_imgbtn_create(scr, "F:/bmp_fan.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_O_FAN);
+ buttonPowerOff = lv_imgbtn_create(scr, gCfgItems.finish_power_off ? "F:/bmp_auto_off.bin" : "F:/bmp_manual_off.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_O_POWER_OFF);
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonPreHeat);
+ lv_group_add_obj(g, buttonFilament);
+ lv_group_add_obj(g, buttonFan);
+ lv_group_add_obj(g, buttonPowerOff);
+ }
+ #endif
+
+ if (uiCfg.print_state != WORKING) {
+ buttonExtrusion = lv_imgbtn_create(scr, "F:/bmp_extrude_opr.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_EXTRUCT);
+ buttonMove = lv_imgbtn_create(scr, "F:/bmp_move_opr.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_MOV);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonExtrusion);
+ lv_group_add_obj(g, buttonMove);
+ }
+ #endif
+ }
+ else {
+ buttonSpeed = lv_imgbtn_create(scr, "F:/bmp_speed.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_SPEED);
+ buttonBabyStep = lv_imgbtn_create(scr, "F:/bmp_mov.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_BABY_STEP);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonSpeed);
+ lv_group_add_obj(g, buttonBabyStep);
+ }
+ #endif
+ }
+
+ buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_RETURN);
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonBack);
+ #endif
+
+ // Create labels on the image buttons
+ labelPreHeat = lv_label_create_empty(buttonPreHeat);
+ label_Filament = lv_label_create_empty(buttonFilament);
+ label_Fan = lv_label_create_empty(buttonFan);
+ label_PowerOff = lv_label_create_empty(buttonPowerOff);
+
+ if (uiCfg.print_state != WORKING) {
+ labelExtrusion = lv_label_create_empty(buttonExtrusion);
+ label_Move = lv_label_create_empty(buttonMove);
+ }
+ else {
+ label_Speed = lv_label_create_empty(buttonSpeed);
+ label_BabyStep = lv_label_create_empty(buttonBabyStep);
+ }
+ label_Back = lv_label_create_empty(buttonBack);
+
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelPreHeat, operation_menu.temp);
+ lv_obj_align(labelPreHeat, buttonPreHeat, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+
+ lv_label_set_text(label_Filament, operation_menu.filament);
+ lv_obj_align(label_Filament, buttonFilament, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+
+ lv_label_set_text(label_Fan, operation_menu.fan);
+ lv_obj_align(label_Fan, buttonFan, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+
+ if (gCfgItems.finish_power_off)
+ lv_label_set_text(label_PowerOff, printing_more_menu.auto_close);
+ else
+ lv_label_set_text(label_PowerOff, printing_more_menu.manual);
+ lv_obj_align(label_PowerOff, buttonPowerOff, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+
+ if (uiCfg.print_state != WORKING) {
+ lv_label_set_text(labelExtrusion, operation_menu.extr);
+ lv_obj_align(labelExtrusion, buttonExtrusion, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+
+ lv_label_set_text(label_Move, operation_menu.move);
+ lv_obj_align(label_Move, buttonMove, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else {
+ lv_label_set_text(label_Speed, operation_menu.speed);
+ lv_obj_align(label_Speed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+
+ lv_label_set_text(label_BabyStep, operation_menu.babystep);
+ lv_obj_align(label_BabyStep, buttonBabyStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+
+ lv_label_set_text(label_Back, common_menu.text_back);
+ lv_obj_align(label_Back, buttonBack, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+}
+
+void lv_clear_operation() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.h
new file mode 100644
index 0000000..0257812
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_operation(void);
+extern void lv_clear_operation();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.cpp
new file mode 100644
index 0000000..fb7434e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.cpp
@@ -0,0 +1,51 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, ADVANCED_PAUSE_FEATURE)
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../feature/pause.h"
+#include "../../../../inc/MarlinConfig.h"
+
+void lv_draw_pause_message(const PauseMessage msg) {
+ switch (msg) {
+ case PAUSE_MESSAGE_PAUSING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_PAUSING); break;
+ case PAUSE_MESSAGE_CHANGING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_CHANGING); break;
+ case PAUSE_MESSAGE_UNLOAD: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_UNLOAD); break;
+ case PAUSE_MESSAGE_WAITING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_WAITING); break;
+ case PAUSE_MESSAGE_INSERT: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_INSERT); break;
+ case PAUSE_MESSAGE_LOAD: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_LOAD); break;
+ case PAUSE_MESSAGE_PURGE: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_PURGE); break;
+ case PAUSE_MESSAGE_RESUME: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_RESUME); break;
+ case PAUSE_MESSAGE_HEAT: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_HEAT); break;
+ case PAUSE_MESSAGE_HEATING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_HEATING); break;
+ case PAUSE_MESSAGE_OPTION: pause_menu_response = PAUSE_RESPONSE_WAIT_FOR;
+ lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_OPTION); break;
+ case PAUSE_MESSAGE_STATUS:
+ default: break;
+ }
+}
+
+#endif // HAS_TFT_LVGL_UI && ADVANCED_PAUSE_FEATURE
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.h
new file mode 100644
index 0000000..88222f0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.h
@@ -0,0 +1,32 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_pause_message(const PauseMessage msg);
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.cpp
new file mode 100644
index 0000000..be7c81f
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.cpp
@@ -0,0 +1,85 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_PAUSE_RETURN = 1,
+ ID_PAUSE_X,
+ ID_PAUSE_Y,
+ ID_PAUSE_Z
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ lv_clear_pause_position();
+ switch (obj->mks_obj_id) {
+ case ID_PAUSE_RETURN:
+ lv_draw_return_ui();
+ return;
+ case ID_PAUSE_X:
+ value = pause_pos_x;
+ break;
+ case ID_PAUSE_Y:
+ value = pause_pos_y;
+ break;
+ case ID_PAUSE_Z:
+ value = pause_pos_z;
+ break;
+ }
+ lv_draw_number_key();
+}
+
+void lv_draw_pause_position(void) {
+ char str_1[16];
+ scr = lv_screen_create(PAUSE_POS_UI, machine_menu.PausePosText);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(gCfgItems.pausePosX, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.xPos, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_PAUSE_X, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(gCfgItems.pausePosY, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.yPos, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_PAUSE_Y, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(gCfgItems.pausePosZ, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.zPos, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_PAUSE_Z, 2, public_buf_l);
+
+ lv_screen_menu_item_return(scr, event_handler, ID_PAUSE_RETURN);
+}
+
+void lv_clear_pause_position() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.h
new file mode 100644
index 0000000..3e9e079
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_pause_position(void);
+extern void lv_clear_pause_position();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.cpp
new file mode 100644
index 0000000..b38dbf9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.cpp
@@ -0,0 +1,297 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/temperature.h"
+#include "../../../../inc/MarlinConfig.h"
+#include "../../../../module/motion.h"
+
+static lv_obj_t *scr;
+extern lv_group_t* g;
+static lv_obj_t *buttonType, *buttonStep;
+static lv_obj_t *labelType;
+static lv_obj_t *labelStep;
+static lv_obj_t *tempText1;
+
+enum {
+ ID_P_ADD = 1,
+ ID_P_DEC,
+ ID_P_TYPE,
+ ID_P_STEP,
+ ID_P_OFF,
+ ID_P_RETURN
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_P_ADD:
+ if (uiCfg.curTempType == 0) {
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target += uiCfg.stepHeat;
+ if (uiCfg.curSprayerChoose == 0) {
+ if ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > (HEATER_0_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1))) {
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = (float)HEATER_0_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1);
+ }
+ }
+ #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER
+ else if ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > (HEATER_1_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1))) {
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = (float)HEATER_1_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1);
+ }
+ #endif
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+ }
+ #if HAS_HEATED_BED
+ else {
+ thermalManager.temp_bed.target += uiCfg.stepHeat;
+ if ((int)thermalManager.temp_bed.target > BED_MAXTEMP - (WATCH_BED_TEMP_INCREASE + TEMP_BED_HYSTERESIS + 1)) {
+ thermalManager.temp_bed.target = (float)BED_MAXTEMP - (WATCH_BED_TEMP_INCREASE + TEMP_BED_HYSTERESIS + 1);
+ }
+ thermalManager.start_watching_bed();
+ }
+ #endif
+ disp_desire_temp();
+ break;
+ case ID_P_DEC:
+ if (uiCfg.curTempType == 0) {
+ if ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > uiCfg.stepHeat)
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target -= uiCfg.stepHeat;
+ else
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = 0;
+
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+ }
+ #if HAS_HEATED_BED
+ else {
+ if ((int)thermalManager.temp_bed.target > uiCfg.stepHeat)
+ thermalManager.temp_bed.target -= uiCfg.stepHeat;
+ else
+ thermalManager.temp_bed.target = 0;
+
+ thermalManager.start_watching_bed();
+ }
+ #endif
+ disp_desire_temp();
+ break;
+ case ID_P_TYPE:
+ if (uiCfg.curTempType == 0) {
+ if (ENABLED(HAS_MULTI_EXTRUDER)) {
+ #if DISABLED(SINGLENOZZLE)
+ if (uiCfg.curSprayerChoose == 0) {
+ uiCfg.curSprayerChoose = 1;
+ }
+ else if (uiCfg.curSprayerChoose == 1) {
+ if (TEMP_SENSOR_BED != 0) {
+ uiCfg.curTempType = 1;
+ }
+ else {
+ uiCfg.curTempType = 0;
+ uiCfg.curSprayerChoose = 0;
+ }
+ }
+ #else
+ if (TEMP_SENSOR_BED != 0) {
+ uiCfg.curTempType = 1;
+ }
+ else {
+ uiCfg.curTempType = 0;
+ }
+ #endif
+ }
+ else if (uiCfg.curSprayerChoose == 0) {
+ if (TEMP_SENSOR_BED != 0)
+ uiCfg.curTempType = 1;
+ else
+ uiCfg.curTempType = 0;
+ }
+ }
+ else if (uiCfg.curTempType == 1) {
+ uiCfg.curSprayerChoose = 0;
+ uiCfg.curTempType = 0;
+ }
+ disp_temp_type();
+ break;
+ case ID_P_STEP:
+ switch (uiCfg.stepHeat) {
+ case 1: uiCfg.stepHeat = 5; break;
+ case 5: uiCfg.stepHeat = 10; break;
+ case 10: uiCfg.stepHeat = 1; break;
+ default: break;
+ }
+ disp_step_heat();
+ break;
+ case ID_P_OFF:
+ if (uiCfg.curTempType == 0) {
+ thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = 0;
+ thermalManager.start_watching_hotend(uiCfg.curSprayerChoose);
+ }
+ #if HAS_HEATED_BED
+ else {
+ thermalManager.temp_bed.target = 0;
+ thermalManager.start_watching_bed();
+ }
+ #endif
+ disp_desire_temp();
+ break;
+ case ID_P_RETURN:
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_preHeat(void) {
+ scr = lv_screen_create(PRE_HEAT_UI);
+
+ // Create image buttons
+ lv_big_button_create(scr, "F:/bmp_Add.bin", preheat_menu.add, INTERVAL_V, titleHeight, event_handler, ID_P_ADD);
+ lv_big_button_create(scr, "F:/bmp_Dec.bin", preheat_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_DEC);
+
+ buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_TYPE);
+ buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_STEP);
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonType);
+ lv_group_add_obj(g, buttonStep);
+ }
+ #endif
+
+ lv_big_button_create(scr, "F:/bmp_speed0.bin", preheat_menu.off, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_OFF);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_RETURN);
+
+ // Create labels on the image buttons
+ labelType = lv_label_create_empty(buttonType);
+ labelStep = lv_label_create_empty(buttonStep);
+
+ #if ENABLED(SINGLENOZZLE)
+ uiCfg.curSprayerChoose = 0;
+ #else
+ uiCfg.curSprayerChoose = active_extruder;
+ #endif
+
+ disp_temp_type();
+ disp_step_heat();
+
+ tempText1 = lv_label_create_empty(scr);
+ lv_obj_set_style(tempText1, &tft_style_label_rel);
+ disp_desire_temp();
+}
+
+void disp_temp_type() {
+ if (uiCfg.curTempType == 0) {
+ #if DISABLED(SINGLENOZZLE)
+ if (uiCfg.curSprayerChoose == 1) {
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru2.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, preheat_menu.ext2);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+ else {
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, preheat_menu.ext1);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+ #else
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, preheat_menu.ext1);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ #endif
+ }
+ else {
+ lv_imgbtn_set_src_both(buttonType, "F:/bmp_bed.bin");
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelType, preheat_menu.hotbed);
+ lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void disp_desire_temp() {
+ char buf[20] = {0};
+
+ public_buf_l[0] = '\0';
+
+ if (uiCfg.curTempType == 0) {
+ #if DISABLED(SINGLENOZZLE)
+ strcat(public_buf_l, uiCfg.curSprayerChoose < 1 ? preheat_menu.ext1 : preheat_menu.ext2);
+ sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target);
+ #else
+ strcat(public_buf_l, preheat_menu.ext1);
+ sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target);
+ #endif
+ }
+ #if HAS_HEATED_BED
+ else {
+ strcat(public_buf_l, preheat_menu.hotbed);
+ sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target);
+ }
+ #endif
+ strcat_P(public_buf_l, PSTR(": "));
+ strcat(public_buf_l, buf);
+ lv_label_set_text(tempText1, public_buf_l);
+ lv_obj_align(tempText1, nullptr, LV_ALIGN_CENTER, 0, -50);
+}
+
+void disp_step_heat() {
+ if (uiCfg.stepHeat == 1) {
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step1_degree.bin");
+ }
+ else if (uiCfg.stepHeat == 5) {
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step5_degree.bin");
+ }
+ else if (uiCfg.stepHeat == 10) {
+ lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step10_degree.bin");
+ }
+
+ if (gCfgItems.multiple_language) {
+ if (uiCfg.stepHeat == 1) {
+ lv_label_set_text(labelStep, preheat_menu.step_1c);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if (uiCfg.stepHeat == 5) {
+ lv_label_set_text(labelStep, preheat_menu.step_5c);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ else if (uiCfg.stepHeat == 10) {
+ lv_label_set_text(labelStep, preheat_menu.step_10c);
+ lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ }
+}
+
+void lv_clear_preHeat() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.h
new file mode 100644
index 0000000..602f5e9
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.h
@@ -0,0 +1,36 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_preHeat(void);
+extern void lv_clear_preHeat();
+extern void disp_temp_type();
+extern void disp_step_heat();
+extern void disp_desire_temp();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.cpp
new file mode 100644
index 0000000..0d95f14
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.cpp
@@ -0,0 +1,552 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+//#include "../lvgl/src/lv_objx/lv_imgbtn.h"
+//#include "../lvgl/src/lv_objx/lv_img.h"
+//#include "../lvgl/src/lv_core/lv_disp.h"
+//#include "../lvgl/src/lv_core/lv_refr.h"
+
+#include "../../../../sd/cardreader.h"
+#include "../../../../inc/MarlinConfig.h"
+
+static lv_obj_t *scr;
+extern lv_group_t* g;
+
+static lv_obj_t *buttonPageUp, *buttonPageDown, *buttonBack,
+ *buttonGcode[FILE_BTN_CNT], *labelPageUp[FILE_BTN_CNT], *buttonText[FILE_BTN_CNT];
+
+enum {
+ ID_P_UP = 7,
+ ID_P_DOWN,
+ ID_P_RETURN
+};
+
+int8_t curDirLever = 0;
+LIST_FILE list_file;
+DIR_OFFSET dir_offset[10];
+
+extern uint8_t public_buf[513];
+extern char public_buf_m[100];
+
+uint8_t sel_id = 0;
+
+#if ENABLED(SDSUPPORT)
+
+ static uint8_t search_file() {
+ int valid_name_cnt = 0;
+ //char tmp[SHORT_NEME_LEN*MAX_DIR_LEVEL+1];
+
+ list_file.Sd_file_cnt = 0;
+ //list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset;
+
+ //root2.rewind();
+ //SERIAL_ECHOLN(list_file.curDirPath);
+
+ if (curDirLever != 0) card.cd(list_file.curDirPath);
+ else card.cdroot(); // while(card.cdup());
+
+ const uint16_t fileCnt = card.get_num_Files();
+
+ for (uint16_t i = 0; i < fileCnt; i++) {
+ if (list_file.Sd_file_cnt == list_file.Sd_file_offset) {
+ const uint16_t nr = SD_ORDER(i, fileCnt);
+ card.getfilename_sorted(nr);
+
+ list_file.IsFolder[valid_name_cnt] = card.flag.filenameIsDir;
+ strcpy(list_file.file_name[valid_name_cnt], list_file.curDirPath);
+ strcat_P(list_file.file_name[valid_name_cnt], PSTR("/"));
+ strcat(list_file.file_name[valid_name_cnt], card.filename);
+ strcpy(list_file.long_name[valid_name_cnt], card.longest_filename());
+
+ valid_name_cnt++;
+ if (valid_name_cnt == 1)
+ dir_offset[curDirLever].cur_page_first_offset = list_file.Sd_file_offset;
+ if (valid_name_cnt >= FILE_NUM) {
+ dir_offset[curDirLever].cur_page_last_offset = list_file.Sd_file_offset;
+ list_file.Sd_file_offset++;
+ break;
+ }
+ list_file.Sd_file_offset++;
+ }
+ list_file.Sd_file_cnt++;
+ }
+ //card.closefile(false);
+ return valid_name_cnt;
+ }
+
+#endif // SDSUPPORT
+
+bool have_pre_pic(char *path) {
+ #if ENABLED(SDSUPPORT)
+ char *ps1;//, *ps2;//, *cur_name = strrchr(path, '/');
+ card.openFileRead(path);
+ card.read(public_buf, 256);
+ ps1 = strstr((char *)public_buf, ";simage:");
+ //card.read(public_buf, 512);
+ //ps2 = strstr((char *)public_buf, ";simage:");
+ card.closefile();
+ if (ps1) return true;
+ #endif
+
+ return false;
+}
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ uint8_t i, file_count = 0;
+ //switch (obj->mks_obj_id)
+ //{
+ if (obj->mks_obj_id == ID_P_UP) {
+ if (dir_offset[curDirLever].curPage > 0) {
+ // 2015.05.19
+ list_file.Sd_file_cnt = 0;
+
+ if (dir_offset[curDirLever].cur_page_first_offset >= FILE_NUM)
+ list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset - FILE_NUM;
+
+ #if ENABLED(SDSUPPORT)
+ file_count = search_file();
+ #endif
+ if (file_count != 0) {
+ dir_offset[curDirLever].curPage--;
+ lv_clear_print_file();
+ disp_gcode_icon(file_count);
+ }
+ }
+ }
+ else if (obj->mks_obj_id == ID_P_DOWN) {
+ if (dir_offset[curDirLever].cur_page_last_offset > 0) {
+ list_file.Sd_file_cnt = 0;
+ list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_last_offset + 1;
+ #if ENABLED(SDSUPPORT)
+ file_count = search_file();
+ #endif
+ if (file_count != 0) {
+ dir_offset[curDirLever].curPage++;
+ lv_clear_print_file();
+ disp_gcode_icon(file_count);
+ }
+ if (file_count < FILE_NUM)
+ dir_offset[curDirLever].cur_page_last_offset = 0;
+ }
+ }
+ else if (obj->mks_obj_id == ID_P_RETURN) {
+ if (curDirLever > 0) {
+ int8_t *ch = (int8_t *)strrchr(list_file.curDirPath, '/');
+ if (ch) {
+ *ch = 0;
+ #if ENABLED(SDSUPPORT)
+ card.cdup();
+ #endif
+ dir_offset[curDirLever].curPage = 0;
+ dir_offset[curDirLever].cur_page_first_offset = 0;
+ dir_offset[curDirLever].cur_page_last_offset = 0;
+ curDirLever--;
+ list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset;
+ #if ENABLED(SDSUPPORT)
+ file_count = search_file();
+ #endif
+ lv_clear_print_file();
+ disp_gcode_icon(file_count);
+ }
+ }
+ else {
+ lv_clear_print_file();
+ lv_draw_ready_print();
+ }
+ }
+ else {
+ for (i = 0; i < FILE_BTN_CNT; i++) {
+ if (obj->mks_obj_id == (i + 1)) {
+ if (list_file.file_name[i][0] != 0) {
+ if (list_file.IsFolder[i]) {
+ strcpy(list_file.curDirPath, list_file.file_name[i]);
+ curDirLever++;
+ list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset;
+ #if ENABLED(SDSUPPORT)
+ file_count = search_file();
+ #endif
+ lv_clear_print_file();
+ disp_gcode_icon(file_count);
+ }
+ else {
+ sel_id = i;
+ lv_clear_print_file();
+ lv_draw_dialog(DIALOG_TYPE_PRINT_FILE);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+void lv_draw_print_file(void) {
+ //uint8_t i;
+ uint8_t file_count;
+
+ curDirLever = 0;
+ dir_offset[curDirLever].curPage = 0;
+
+ list_file.Sd_file_offset = 0;
+ list_file.Sd_file_cnt = 0;
+
+ ZERO(dir_offset);
+ ZERO(list_file.IsFolder);
+ ZERO(list_file.curDirPath);
+
+ list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset;
+ #if ENABLED(SDSUPPORT)
+ card.mount();
+ file_count = search_file();
+ #endif
+ disp_gcode_icon(file_count);
+
+ //lv_obj_t *labelPageUp = lv_label_create_empty(buttonPageUp);
+ //lv_obj_t *labelPageDown = lv_label_create_empty(buttonPageDown);
+ //lv_obj_t *label_Back = lv_label_create_empty(buttonBack);
+
+ /*
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelPageUp, tool_menu.preheat);
+ lv_obj_align(labelPageUp, buttonPageUp, LV_ALIGN_IN_BOTTOM_MID,0, BUTTON_TEXT_Y_OFFSET);
+
+ lv_label_set_text(labelPageDown, tool_menu.extrude);
+ lv_obj_align(labelPageDown, buttonPageDown, LV_ALIGN_IN_BOTTOM_MID,0, BUTTON_TEXT_Y_OFFSET);
+
+ lv_label_set_text(label_Back, common_menu.text_back);
+ lv_obj_align(label_Back, buttonBack, LV_ALIGN_IN_BOTTOM_MID,0, BUTTON_TEXT_Y_OFFSET);
+ }
+ */
+}
+static char test_public_buf_l[(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + strlen("S:/") + 1];
+void disp_gcode_icon(uint8_t file_num) {
+ uint8_t i;
+
+ scr = lv_screen_create(PRINT_FILE_UI, "");
+
+ // Create image buttons
+ buttonPageUp = lv_imgbtn_create(scr, "F:/bmp_pageUp.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_UP);
+ buttonPageDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL + INTERVAL_H, event_handler, ID_P_DOWN);
+ buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL * 2 + INTERVAL_H * 2, event_handler, ID_P_RETURN);
+
+ // Create labels on the image buttons
+ for (i = 0; i < FILE_BTN_CNT; i++) {
+ /*
+ if (seq) {
+ j = (FILE_BTN_CNT-1) - i;
+ back_flg = 1;
+ }
+ else {
+ j = i;
+ back_flg = 0;
+ }
+ */
+ if (i >= file_num) break;
+
+ #ifdef TFT35
+ buttonGcode[i] = lv_imgbtn_create(scr, nullptr);
+
+ lv_imgbtn_use_label_style(buttonGcode[i]);
+ lv_obj_clear_protect(buttonGcode[i], LV_PROTECT_FOLLOW);
+ lv_btn_set_layout(buttonGcode[i], LV_LAYOUT_OFF);
+
+ ZERO(public_buf_m);
+ cutFileName((char *)list_file.long_name[i], 16, 8, (char *)public_buf_m);
+
+ if (list_file.IsFolder[i]) {
+ lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), "", 0);
+ lv_imgbtn_set_src_both(buttonGcode[i], "F:/bmp_dir.bin");
+ if (i < 3)
+ lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1), titleHeight);
+ else
+ lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1), BTN_Y_PIXEL + INTERVAL_H + titleHeight);
+
+ labelPageUp[i] = lv_label_create(buttonGcode[i], public_buf_m);
+ lv_obj_align(labelPageUp[i], buttonGcode[i], LV_ALIGN_IN_BOTTOM_MID, 0, -5);
+ }
+ else {
+ if (have_pre_pic((char *)list_file.file_name[i])) {
+
+ //lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), list_file.file_name[i], 1);
+
+ strcpy(test_public_buf_l, "S:");
+ strcat(test_public_buf_l, list_file.file_name[i]);
+ char *temp = strstr(test_public_buf_l, ".GCO");
+ if (temp) strcpy(temp, ".bin");
+ lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), test_public_buf_l, 0);
+ lv_imgbtn_set_src_both(buttonGcode[i], buttonGcode[i]->mks_pic_name);
+ if (i < 3) {
+ lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET);
+ buttonText[i] = lv_btn_create(scr, nullptr);
+ //lv_obj_set_event_cb(buttonText[i], event_handler);
+
+ lv_btn_use_label_style(buttonText[i]);
+ lv_obj_clear_protect(buttonText[i], LV_PROTECT_FOLLOW);
+ lv_btn_set_layout(buttonText[i], LV_LAYOUT_OFF);
+ //lv_obj_set_event_cb_mks(buttonText[i], event_handler,(i+10),"", 0);
+ lv_obj_set_pos(buttonText[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET + 100);
+ lv_obj_set_size(buttonText[i], 100, 40);
+ }
+ else {
+ lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_Y_PIXEL + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET);
+ buttonText[i] = lv_btn_create(scr, nullptr);
+ //lv_obj_set_event_cb(buttonText[i], event_handler);
+
+ lv_btn_use_label_style(buttonText[i]);
+ lv_obj_clear_protect(buttonText[i], LV_PROTECT_FOLLOW);
+ lv_btn_set_layout(buttonText[i], LV_LAYOUT_OFF);
+ //lv_obj_set_event_cb_mks(buttonText[i], event_handler,(i+10),"", 0);
+ lv_obj_set_pos(buttonText[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_Y_PIXEL + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET + 100);
+ lv_obj_set_size(buttonText[i], 100, 40);
+ }
+ labelPageUp[i] = lv_label_create(buttonText[i], public_buf_m);
+ lv_obj_align(labelPageUp[i], buttonText[i], LV_ALIGN_IN_BOTTOM_MID, 0, 0);
+ }
+ else {
+ lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), "", 0);
+ lv_imgbtn_set_src_both(buttonGcode[i], "F:/bmp_file.bin");
+ if (i < 3)
+ lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1), titleHeight);
+ else
+ lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1), BTN_Y_PIXEL + INTERVAL_H + titleHeight);
+
+ labelPageUp[i] = lv_label_create(buttonGcode[i], public_buf_m);
+ lv_obj_align(labelPageUp[i], buttonGcode[i], LV_ALIGN_IN_BOTTOM_MID, 0, -5);
+ }
+ }
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonGcode[i]);
+ #endif
+
+ #else // !TFT35
+ #endif // !TFT35
+ }
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonPageUp);
+ lv_group_add_obj(g, buttonPageDown);
+ lv_group_add_obj(g, buttonBack);
+ }
+ #endif
+}
+
+uint32_t lv_open_gcode_file(char *path) {
+ #if ENABLED(SDSUPPORT)
+ uint32_t *ps4;
+ uint32_t pre_sread_cnt = UINT32_MAX;
+ //char *cur_name;
+
+ //cur_name = strrchr(path, '/');
+
+ card.openFileRead(path);
+ card.read(public_buf, 256);
+ ps4 = (uint32_t *)strstr((char *)public_buf, ";simage:");
+ // Ignore the beginning message of gcode file
+ if (ps4) {
+ pre_sread_cnt = (uint32_t)ps4 - (uint32_t)((uint32_t *)(&public_buf[0]));
+ card.setIndex(pre_sread_cnt);
+ }
+ return pre_sread_cnt;
+ #endif // SDSUPPORT
+}
+
+int ascii2dec_test(char *ascii) {
+ int result = 0;
+ if (ascii == 0) return 0;
+
+ if (*(ascii) >= '0' && *(ascii) <= '9')
+ result = *(ascii) - '0';
+ else if (*(ascii) >= 'a' && *(ascii) <= 'f')
+ result = *(ascii) - 'a' + 0x0A;
+ else if (*(ascii) >= 'A' && *(ascii) <= 'F')
+ result = *(ascii) - 'A' + 0x0A;
+ else
+ return 0;
+
+ return result;
+}
+
+void lv_gcode_file_read(uint8_t *data_buf) {
+ #if ENABLED(SDSUPPORT)
+ uint16_t i = 0, j = 0, k = 0;
+ uint16_t row_1 = 0;
+ bool ignore_start = true;
+ char temp_test[200];
+ volatile uint16_t *p_index;
+
+ watchdog_refresh();
+ memset(public_buf, 0, 200);
+
+ while (card.isFileOpen()) {
+ if (ignore_start) card.read(temp_test, 8); // line start -> ignore
+ card.read(temp_test, 200); // data
+ // \r;;gimage: we got the bit img, so stop here
+ if (temp_test[1] == ';') {
+ card.closefile();
+ break;
+ }
+ for (i = 0; i < 200;) {
+ public_buf[row_1 * 200 + 100 * k + j] = (char)(ascii2dec_test(&temp_test[i]) << 4 | ascii2dec_test(&temp_test[i + 1]));
+ j++;
+ i += 2;
+ }
+
+ uint16_t c = card.get();
+ // check for more data or end of line (CR or LF)
+ if (ISEOL(c)) {
+ c = card.get(); // more eol?
+ if (!ISEOL(c)) card.setIndex(card.getIndex() - 1);
+ break;
+ }
+ card.setIndex(card.getIndex() - 1);
+ k++;
+ j = 0;
+ ignore_start = false;
+ if (k > 1) {
+ card.closefile();
+ break;
+ }
+ }
+ #if HAS_TFT_LVGL_UI_SPI
+ for (i = 0; i < 200;) {
+ p_index = (uint16_t *)(&public_buf[i]);
+
+ //Color = (*p_index >> 8);
+ //*p_index = Color | ((*p_index & 0xFF) << 8);
+ i += 2;
+ if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full;
+ }
+ #else // !HAS_TFT_LVGL_UI_SPI
+ for (i = 0; i < 200;) {
+ p_index = (uint16_t *)(&public_buf[i]);
+ //Color = (*p_index >> 8);
+ //*p_index = Color | ((*p_index & 0xFF) << 8);
+ i += 2;
+ if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full; // 0x18C3;
+ }
+ #endif // !HAS_TFT_LVGL_UI_SPI
+ memcpy(data_buf, public_buf, 200);
+ #endif // SDSUPPORT
+}
+
+void lv_close_gcode_file() {TERN_(SDSUPPORT, card.closefile());}
+
+void lv_gcode_file_seek(uint32_t pos) {
+ TERN_(SDSUPPORT, card.setIndex(pos));
+}
+
+void cutFileName(char *path, int len, int bytePerLine, char *outStr) {
+ #if _LFN_UNICODE
+ TCHAR *tmpFile;
+ TCHAR *strIndex1 = 0, *strIndex2 = 0, *beginIndex;
+ TCHAR secSeg[10] = {0};
+ TCHAR gFileTail[4] = {'~', '.', 'g', '\0'};
+ #else
+ char *tmpFile;
+ char *strIndex1 = 0, *strIndex2 = 0, *beginIndex;
+ char secSeg[10] = {0};
+ #endif
+
+ if (path == 0 || len <= 3 || outStr == 0) return;
+
+ tmpFile = path;
+ #if _LFN_UNICODE
+ strIndex1 = (WCHAR *)wcsstr((const WCHAR *)tmpFile, (const WCHAR *)'/');
+ strIndex2 = (WCHAR *)wcsstr((const WCHAR *)tmpFile, (const WCHAR *)'.');
+ #else
+ strIndex1 = (char *)strrchr(tmpFile, '/');
+ strIndex2 = (char *)strrchr(tmpFile, '.');
+ #endif
+
+ beginIndex = (strIndex1 != 0
+ //&& (strIndex2 != 0) && (strIndex1 < strIndex2)
+ ) ? strIndex1 + 1 : tmpFile;
+
+ if (strIndex2 == 0 || (strIndex1 > strIndex2)) { // not gcode file
+ #if _LFN_UNICODE
+ if (wcslen(beginIndex) > len)
+ wcsncpy(outStr, beginIndex, len);
+ else
+ wcscpy(outStr, beginIndex);
+ #else
+ if ((int)strlen(beginIndex) > len)
+ strncpy(outStr, beginIndex, len);
+ else
+ strcpy(outStr, beginIndex);
+ #endif
+ }
+ else { // gcode file
+ if (strIndex2 - beginIndex > (len - 2)) {
+ #if _LFN_UNICODE
+ wcsncpy(outStr, (const WCHAR *)beginIndex, len - 3);
+ wcscat(outStr, (const WCHAR *)gFileTail);
+ #else
+ //strncpy(outStr, beginIndex, len - 3);
+ strncpy(outStr, beginIndex, len - 4);
+ strcat_P(outStr, PSTR("~.g"));
+ #endif
+ }
+ else {
+ #if _LFN_UNICODE
+ wcsncpy(outStr, (const WCHAR *)beginIndex, strIndex2 - beginIndex + 1);
+ wcscat(outStr, (const WCHAR *)&gFileTail[3]);
+ #else
+ strncpy(outStr, beginIndex, strIndex2 - beginIndex + 1);
+ strcat_P(outStr, PSTR("g"));
+ #endif
+ }
+ }
+
+ #if _LFN_UNICODE
+ if (wcslen(outStr) > bytePerLine) {
+ wcscpy(secSeg, (const WCHAR *)&outStr[bytePerLine]);
+ outStr[bytePerLine] = '\n';
+ outStr[bytePerLine + 1] = '\0';
+ wcscat(outStr, (const WCHAR *)secSeg);
+ }
+ #else
+ if ((int)strlen(outStr) > bytePerLine) {
+ strcpy(secSeg, &outStr[bytePerLine]);
+ outStr[bytePerLine] = '\n';
+ outStr[bytePerLine + 1] = '\0';
+ strcat(outStr, secSeg);
+ }
+ else {
+ strcat_P(outStr, PSTR("\n"));
+ }
+ #endif
+}
+
+void lv_clear_print_file() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.h
new file mode 100644
index 0000000..126dab0
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.h
@@ -0,0 +1,64 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+typedef struct {
+ int cur_page_first_offset;
+ int cur_page_last_offset;
+ int curPage;
+} DIR_OFFSET;
+extern DIR_OFFSET dir_offset[10];
+
+#define FILE_NUM 6
+#define SHORT_NAME_LEN 13
+#define NAME_CUT_LEN 23
+
+#define MAX_DIR_LEVEL 10
+
+typedef struct {
+ char file_name[FILE_NUM][(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + 1];
+ char curDirPath[(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + 1];
+ char long_name[FILE_NUM][SHORT_NAME_LEN * 2 + 1];
+ bool IsFolder[FILE_NUM];
+ char Sd_file_cnt;
+ char sd_file_index;
+ char Sd_file_offset;
+} LIST_FILE;
+extern LIST_FILE list_file;
+
+extern void disp_gcode_icon(uint8_t file_num);
+extern void lv_draw_print_file(void);
+extern uint32_t lv_open_gcode_file(char *path);
+extern void lv_gcode_file_read(uint8_t *data_buf);
+extern void lv_close_gcode_file();
+extern void cutFileName(char *path, int len, int bytePerLine, char *outStr);
+extern int ascii2dec_test(char *ascii);
+extern void lv_clear_print_file();
+extern void lv_gcode_file_seek(uint32_t pos);
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.cpp
new file mode 100644
index 0000000..5a474ce
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.cpp
@@ -0,0 +1,290 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../MarlinCore.h" // for marlin_state
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../sd/cardreader.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../gcode/gcode.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if BOTH(LCD_SET_PROGRESS_MANUALLY, USE_M73_REMAINING_TIME)
+ #include "../../../marlinui.h"
+#endif
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *labelExt1, *labelFan, *labelZpos, *labelTime;
+static lv_obj_t *labelPause, *labelStop, *labelOperat;
+static lv_obj_t *bar1, *bar1ValueText;
+static lv_obj_t *buttonPause, *buttonOperat, *buttonStop;
+
+#if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER
+ static lv_obj_t *labelExt2;
+#endif
+
+#if HAS_HEATED_BED
+ static lv_obj_t* labelBed;
+#endif
+
+enum {
+ ID_PAUSE = 1,
+ ID_STOP,
+ ID_OPTION
+};
+
+bool once_flag; // = false
+extern bool flash_preview_begin, default_preview_flg, gcode_preview_over;
+extern uint32_t To_pre_view;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ if (gcode_preview_over) return;
+ switch (obj->mks_obj_id) {
+ case ID_PAUSE:
+ if (uiCfg.print_state == WORKING) {
+ #if ENABLED(SDSUPPORT)
+ card.pauseSDPrint();
+ stop_print_time();
+ uiCfg.print_state = PAUSING;
+ #endif
+ lv_imgbtn_set_src_both(buttonPause, "F:/bmp_resume.bin");
+ lv_label_set_text(labelPause, printing_menu.resume);
+ lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 30, 0);
+ }
+ else if (uiCfg.print_state == PAUSED) {
+ uiCfg.print_state = RESUMING;
+ lv_imgbtn_set_src_both(obj, "F:/bmp_pause.bin");
+ lv_label_set_text(labelPause, printing_menu.pause);
+ lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 30, 0);
+ }
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ else if (uiCfg.print_state == REPRINTING) {
+ uiCfg.print_state = REPRINTED;
+ lv_imgbtn_set_src_both(obj, "F:/bmp_pause.bin");
+ lv_label_set_text(labelPause, printing_menu.pause);
+ lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 30, 0);
+ print_time.minutes = recovery.info.print_job_elapsed / 60;
+ print_time.seconds = recovery.info.print_job_elapsed % 60;
+ print_time.hours = print_time.minutes / 60;
+ }
+ #endif
+ break;
+
+ case ID_STOP:
+ lv_clear_printing();
+ lv_draw_dialog(DIALOG_TYPE_STOP);
+ break;
+ case ID_OPTION:
+ lv_clear_printing();
+ lv_draw_operation();
+ break;
+ }
+}
+
+void lv_draw_printing(void) {
+ disp_state_stack._disp_index = 0;
+ ZERO(disp_state_stack._disp_state);
+ scr = lv_screen_create(PRINTING_UI);
+
+ // Create image buttons
+ lv_obj_t *buttonExt1 = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonExt1, "F:/bmp_ext1_state.bin");
+ lv_obj_set_pos(buttonExt1, 205, 136);
+
+ #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER
+ lv_obj_t *buttonExt2 = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonExt2, "F:/bmp_ext2_state.bin");
+ lv_obj_set_pos(buttonExt2, 350, 136);
+ #endif
+
+ #if HAS_HEATED_BED
+ lv_obj_t *buttonBedstate = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonBedstate, "F:/bmp_bed_state.bin");
+ lv_obj_set_pos(buttonBedstate, 205, 186);
+ #endif
+
+ lv_obj_t *buttonFanstate = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonFanstate, "F:/bmp_fan_state.bin");
+ lv_obj_set_pos(buttonFanstate, 350, 186);
+
+ lv_obj_t *buttonTime = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonTime, "F:/bmp_time_state.bin");
+ lv_obj_set_pos(buttonTime, 205, 86);
+
+ lv_obj_t *buttonZpos = lv_img_create(scr, nullptr);
+ lv_img_set_src(buttonZpos, "F:/bmp_zpos_state.bin");
+ lv_obj_set_pos(buttonZpos, 350, 86);
+
+ buttonPause = lv_imgbtn_create(scr, uiCfg.print_state == WORKING ? "F:/bmp_pause.bin" : "F:/bmp_resume.bin", 5, 240, event_handler, ID_PAUSE);
+ buttonStop = lv_imgbtn_create(scr, "F:/bmp_stop.bin", 165, 240, event_handler, ID_STOP);
+ buttonOperat = lv_imgbtn_create(scr, "F:/bmp_operate.bin", 325, 240, event_handler, ID_OPTION);
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonPause);
+ lv_group_add_obj(g, buttonStop);
+ lv_group_add_obj(g, buttonOperat);
+ }
+ #endif
+
+ labelExt1 = lv_label_create(scr, 250, 146, nullptr);
+
+ #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER
+ labelExt2 = lv_label_create(scr, 395, 146, nullptr);
+ #endif
+
+ #if HAS_HEATED_BED
+ labelBed = lv_label_create(scr, 250, 196, nullptr);
+ #endif
+
+ labelFan = lv_label_create(scr, 395, 196, nullptr);
+ labelTime = lv_label_create(scr, 250, 96, nullptr);
+ labelZpos = lv_label_create(scr, 395, 96, nullptr);
+
+ labelPause = lv_label_create_empty(buttonPause);
+ labelStop = lv_label_create_empty(buttonStop);
+ labelOperat = lv_label_create_empty(buttonOperat);
+
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(labelPause, uiCfg.print_state == WORKING ? printing_menu.pause : printing_menu.resume);
+ lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 20, 0);
+
+ lv_label_set_text(labelStop, printing_menu.stop);
+ lv_obj_align(labelStop, buttonStop, LV_ALIGN_CENTER, 20, 0);
+
+ lv_label_set_text(labelOperat, printing_menu.option);
+ lv_obj_align(labelOperat, buttonOperat, LV_ALIGN_CENTER, 20, 0);
+ }
+
+ bar1 = lv_bar_create(scr, nullptr);
+ lv_obj_set_pos(bar1, 205, 36);
+ lv_obj_set_size(bar1, 270, 40);
+ lv_bar_set_style(bar1, LV_BAR_STYLE_INDIC, &lv_bar_style_indic);
+ lv_bar_set_anim_time(bar1, 1000);
+ lv_bar_set_value(bar1, 0, LV_ANIM_ON);
+ bar1ValueText = lv_label_create_empty(bar1);
+ lv_label_set_text(bar1ValueText,"0%");
+ lv_obj_align(bar1ValueText, bar1, LV_ALIGN_CENTER, 0, 0);
+
+ disp_ext_temp();
+ disp_bed_temp();
+ disp_fan_speed();
+ disp_print_time();
+ disp_fan_Zpos();
+}
+
+void disp_ext_temp() {
+ sprintf(public_buf_l, printing_menu.temp1, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target);
+ lv_label_set_text(labelExt1, public_buf_l);
+
+ #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER
+ sprintf(public_buf_l, printing_menu.temp1, (int)thermalManager.temp_hotend[1].celsius, (int)thermalManager.temp_hotend[1].target);
+ lv_label_set_text(labelExt2, public_buf_l);
+ #endif
+}
+
+void disp_bed_temp() {
+ #if HAS_HEATED_BED
+ sprintf(public_buf_l, printing_menu.bed_temp, (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target);
+ lv_label_set_text(labelBed, public_buf_l);
+ #endif
+}
+
+void disp_fan_speed() {
+ sprintf_P(public_buf_l, PSTR("%3d"), thermalManager.fan_speed[0]);
+ lv_label_set_text(labelFan, public_buf_l);
+}
+
+void disp_print_time() {
+ #if BOTH(LCD_SET_PROGRESS_MANUALLY, USE_M73_REMAINING_TIME)
+ const uint32_t r = ui.get_remaining_time();
+ sprintf_P(public_buf_l, PSTR("%02d:%02d R"), r / 3600, (r % 3600) / 60);
+ #else
+ sprintf_P(public_buf_l, PSTR("%d%d:%d%d:%d%d"), print_time.hours / 10, print_time.hours % 10, print_time.minutes / 10, print_time.minutes % 10, print_time.seconds / 10, print_time.seconds % 10);
+ #endif
+ lv_label_set_text(labelTime, public_buf_l);
+}
+
+void disp_fan_Zpos() {
+ char str_1[16];
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(current_position[Z_AXIS], 1, 3, str_1));
+ lv_label_set_text(labelZpos, public_buf_l);
+}
+
+void reset_print_time() {
+ print_time.hours = 0;
+ print_time.minutes = 0;
+ print_time.seconds = 0;
+ print_time.ms_10 = 0;
+}
+
+void start_print_time() { print_time.start = 1; }
+
+void stop_print_time() { print_time.start = 0; }
+
+void setProBarRate() {
+ int rate;
+ volatile long long rate_tmp_r;
+
+ if (!gCfgItems.from_flash_pic) {
+ #if ENABLED(SDSUPPORT)
+ rate_tmp_r = (long long)card.getIndex() * 100;
+ #endif
+ rate = rate_tmp_r / gCfgItems.curFilesize;
+ }
+ else {
+ #if ENABLED(SDSUPPORT)
+ rate_tmp_r = (long long)card.getIndex();
+ #endif
+ rate = (rate_tmp_r - (PREVIEW_SIZE + To_pre_view)) * 100 / (gCfgItems.curFilesize - (PREVIEW_SIZE + To_pre_view));
+ }
+
+ if (rate <= 0) return;
+
+ if (disp_state == PRINTING_UI) {
+ lv_bar_set_value(bar1, rate, LV_ANIM_ON);
+ sprintf_P(public_buf_l, "%d%%", rate);
+ lv_label_set_text(bar1ValueText,public_buf_l);
+ lv_obj_align(bar1ValueText, bar1, LV_ALIGN_CENTER, 0, 0);
+ }
+}
+
+void lv_clear_printing() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.h
new file mode 100644
index 0000000..d6da1a1
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.h
@@ -0,0 +1,53 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+enum {
+ IDLE,
+ WORKING,
+ PAUSING,
+ PAUSED,
+ REPRINTING,
+ REPRINTED,
+ RESUMING,
+ STOP
+};
+
+extern void lv_draw_printing(void);
+extern void lv_clear_printing();
+extern void disp_ext_temp();
+extern void disp_bed_temp();
+extern void disp_fan_speed();
+extern void disp_print_time();
+extern void disp_fan_Zpos();
+extern void reset_print_time();
+extern void start_print_time();
+extern void stop_print_time();
+extern void setProBarRate();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.cpp
new file mode 100644
index 0000000..de4e41c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.cpp
@@ -0,0 +1,220 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ready_print.h"
+#include "draw_tool.h"
+#include <lv_conf.h>
+#include "tft_lvgl_configuration.h"
+#include "mks_hardware_test.h"
+#include "draw_ui.h"
+
+#include <lvgl.h>
+
+#include "../../../../module/temperature.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ #include "../../../tft_io/touch_calibration.h"
+ #include "draw_touch_calibration.h"
+#endif
+
+#include <stdio.h>
+
+extern lv_group_t* g;
+static lv_obj_t *scr;
+#if ENABLED(MKS_TEST)
+ uint8_t curent_disp_ui = 0;
+#endif
+
+enum {
+ ID_TOOL = 1,
+ ID_SET,
+ ID_PRINT
+};
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ lv_clear_ready_print();
+
+ switch (obj->mks_obj_id) {
+ case ID_TOOL:
+ lv_draw_tool();
+ break;
+ case ID_SET:
+ lv_draw_set();
+ break;
+ case ID_PRINT:
+ lv_draw_print_file();
+ break;
+ }
+}
+
+lv_obj_t *limit_info, *det_info;
+lv_obj_t *tmc_state_info;
+lv_style_t limit_style, det_style, tmc_state_style;
+void disp_Limit_ok() {
+ limit_style.text.color.full = 0xFFFF;
+ lv_obj_set_style(limit_info, &limit_style);
+ lv_label_set_text(limit_info, "Limit:ok");
+}
+void disp_Limit_error() {
+ limit_style.text.color.full = 0xF800;
+ lv_obj_set_style(limit_info, &limit_style);
+ lv_label_set_text(limit_info, "Limit:error");
+}
+
+void disp_det_ok() {
+ det_style.text.color.full = 0xFFFF;
+ lv_obj_set_style(det_info, &det_style);
+ lv_label_set_text(det_info, "det:ok");
+}
+void disp_det_error() {
+ det_style.text.color.full = 0xF800;
+ lv_obj_set_style(det_info, &det_style);
+ lv_label_set_text(det_info, "det:error");
+}
+
+void disp_tmc_ok() {
+ tmc_state_style.text.color.full = 0xFFFF;
+ lv_obj_set_style(tmc_state_info, &tmc_state_style);
+ lv_label_set_text(tmc_state_info, "TMC CONNECTION OK");
+}
+void disp_tmc_error() {
+ tmc_state_style.text.color.full = 0xF800;
+ lv_obj_set_style(tmc_state_info, &tmc_state_style);
+ lv_label_set_text(tmc_state_info, "TMC CONNECTION ERROR");
+}
+
+lv_obj_t *e1, *e2, *e3, *bed;
+void mks_disp_test() {
+ char buf[30] = {0};
+ sprintf_P(buf, PSTR("e1:%d"), (int)thermalManager.temp_hotend[0].celsius);
+ lv_label_set_text(e1, buf);
+ #if HAS_MULTI_HOTEND
+ sprintf_P(buf, PSTR("e2:%d"), (int)thermalManager.temp_hotend[1].celsius);
+ lv_label_set_text(e2, buf);
+ #endif
+ #if HAS_HEATED_BED
+ sprintf_P(buf, PSTR("bed:%d"), (int)thermalManager.temp_bed.celsius);
+ lv_label_set_text(bed, buf);
+ #endif
+}
+
+void lv_draw_ready_print(void) {
+ char buf[30] = {0};
+ lv_obj_t *buttonTool;
+
+ disp_state_stack._disp_index = 0;
+ ZERO(disp_state_stack._disp_state);
+ scr = lv_screen_create(PRINT_READY_UI, "");
+
+ if (mks_test_flag == 0x1E) {
+ // Create image buttons
+ buttonTool = lv_imgbtn_create(scr, "F:/bmp_tool.bin", event_handler, ID_TOOL);
+
+ lv_obj_set_pos(buttonTool, 360, 180);
+
+ lv_obj_t *label_tool = lv_label_create_empty(buttonTool);
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(label_tool, main_menu.tool);
+ lv_obj_align(label_tool, buttonTool, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+
+ #if 1
+ e1 = lv_label_create_empty(scr);
+ lv_obj_set_pos(e1, 20, 20);
+ sprintf_P(buf, PSTR("e1: %d"), (int)thermalManager.temp_hotend[0].celsius);
+ lv_label_set_text(e1, buf);
+ #if HAS_MULTI_HOTEND
+ e2 = lv_label_create_empty(scr);
+ lv_obj_set_pos(e2, 20, 45);
+ sprintf_P(buf, PSTR("e1: %d"), (int)thermalManager.temp_hotend[1].celsius);
+ lv_label_set_text(e2, buf);
+ #endif
+
+ #if HAS_HEATED_BED
+ bed = lv_label_create_empty(scr);
+ lv_obj_set_pos(bed, 20, 95);
+ sprintf_P(buf, PSTR("bed: %d"), (int)thermalManager.temp_bed.celsius);
+ lv_label_set_text(bed, buf);
+ #endif
+
+ limit_info = lv_label_create_empty(scr);
+
+ lv_style_copy(&limit_style, &lv_style_scr);
+ limit_style.body.main_color.full = 0X0000;
+ limit_style.body.grad_color.full = 0X0000;
+ limit_style.text.color.full = 0Xffff;
+ lv_obj_set_style(limit_info, &limit_style);
+
+ lv_obj_set_pos(limit_info, 20, 120);
+ lv_label_set_text(limit_info, " ");
+
+ det_info = lv_label_create_empty(scr);
+
+ lv_style_copy(&det_style, &lv_style_scr);
+ det_style.body.main_color.full = 0X0000;
+ det_style.body.grad_color.full = 0X0000;
+ det_style.text.color.full = 0Xffff;
+ lv_obj_set_style(det_info, &det_style);
+
+ lv_obj_set_pos(det_info, 20, 145);
+ lv_label_set_text(det_info, " ");
+
+ tmc_state_info = lv_label_create_empty(scr);
+
+ lv_style_copy(&tmc_state_style, &lv_style_scr);
+ tmc_state_style.body.main_color.full = 0X0000;
+ tmc_state_style.body.grad_color.full = 0X0000;
+ tmc_state_style.text.color.full = 0Xffff;
+ lv_obj_set_style(tmc_state_info, &tmc_state_style);
+
+ lv_obj_set_pos(tmc_state_info, 20, 170);
+ lv_label_set_text(tmc_state_info, " ");
+ #endif // if 1
+
+ }
+ else {
+ lv_big_button_create(scr, "F:/bmp_tool.bin", main_menu.tool, 20, 90, event_handler, ID_TOOL);
+ lv_big_button_create(scr, "F:/bmp_set.bin", main_menu.set, 180, 90, event_handler, ID_SET);
+ lv_big_button_create(scr, "F:/bmp_printing.bin", main_menu.print, 340, 90, event_handler, ID_PRINT);
+ }
+
+ #if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ // If calibration is required, let's trigger it now, handles the case when there is default value in configuration files
+ if (!touch_calibration.calibration_loaded()) {
+ lv_clear_ready_print();
+ lv_draw_touch_calibration_screen();
+ }
+ #endif
+}
+
+void lv_clear_ready_print() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.h
new file mode 100644
index 0000000..7d17fb2
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.h
@@ -0,0 +1,40 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_ready_print(void);
+extern void mks_disp_test();
+extern void disp_Limit_ok();
+extern void disp_Limit_error();
+extern void disp_det_error();
+extern void disp_det_ok();
+extern void disp_tmc_ok();
+extern void disp_tmc_error();
+extern void lv_clear_ready_print();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_set.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.cpp
new file mode 100644
index 0000000..328f795
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.cpp
@@ -0,0 +1,134 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ready_print.h"
+#include "draw_set.h"
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "pic_manager.h"
+
+#include "../../../../gcode/queue.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if HAS_SUICIDE
+ #include "../../../../MarlinCore.h"
+#endif
+
+static lv_obj_t *scr;
+extern lv_group_t* g;
+
+enum {
+ ID_S_WIFI = 1,
+ ID_S_FAN,
+ ID_S_ABOUT,
+ ID_S_CONTINUE,
+ ID_S_MOTOR_OFF,
+ ID_S_LANGUAGE,
+ ID_S_MACHINE_PARA,
+ ID_S_EEPROM_SET,
+ ID_S_RETURN
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ if(obj->mks_obj_id != ID_S_MOTOR_OFF) lv_clear_set();
+ switch (obj->mks_obj_id) {
+ case ID_S_FAN:
+ lv_draw_fan();
+ break;
+ case ID_S_ABOUT:
+ lv_draw_about();
+ break;
+ case ID_S_CONTINUE: return;
+ case ID_S_MOTOR_OFF:
+ TERN(HAS_SUICIDE, suicide(), queue.enqueue_now_P(PSTR("M84")));
+ return;
+ case ID_S_LANGUAGE:
+ lv_draw_language();
+ break;
+ case ID_S_MACHINE_PARA:
+ lv_draw_machine_para();
+ break;
+ case ID_S_EEPROM_SET:
+ lv_draw_eeprom_settings();
+ break;
+ case ID_S_RETURN:
+ lv_draw_ready_print();
+ break;
+
+ #if ENABLED(MKS_WIFI_MODULE)
+ case ID_S_WIFI:
+ if (gCfgItems.wifi_mode_sel == STA_MODEL) {
+ if (wifi_link_state == WIFI_CONNECTED) {
+ last_disp_state = SET_UI;
+ lv_draw_wifi();
+ }
+ else {
+ if (uiCfg.command_send == 1) {
+ uint8_t cmd_wifi_list[] = { 0xA5, 0x07, 0x00, 0x00, 0xFC };
+ raw_send_to_wifi(cmd_wifi_list, COUNT(cmd_wifi_list));
+ last_disp_state = SET_UI;
+ lv_draw_wifi_list();
+ }
+ else {
+ last_disp_state = SET_UI;
+ lv_draw_dialog(DIALOG_WIFI_ENABLE_TIPS);
+ }
+ }
+ }
+ else {
+ last_disp_state = SET_UI;
+ lv_draw_wifi();
+ }
+ break;
+ #endif
+ }
+}
+
+void lv_draw_set(void) {
+ scr = lv_screen_create(SET_UI);
+ lv_big_button_create(scr, "F:/bmp_eeprom_settings.bin", set_menu.eepromSet, INTERVAL_V, titleHeight, event_handler, ID_S_EEPROM_SET);
+ lv_big_button_create(scr, "F:/bmp_fan.bin", set_menu.fan, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_S_FAN);
+ lv_big_button_create(scr, "F:/bmp_about.bin", set_menu.about, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_S_ABOUT);
+ lv_big_button_create(scr, ENABLED(HAS_SUICIDE) ? "F:/bmp_manual_off.bin" : "F:/bmp_function1.bin", set_menu.TERN(HAS_SUICIDE, shutdown, motoroff), BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_S_MOTOR_OFF);
+ lv_big_button_create(scr, "F:/bmp_machine_para.bin", set_menu.machine_para, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_MACHINE_PARA);
+ #if HAS_LANG_SELECT_SCREEN
+ lv_big_button_create(scr, "F:/bmp_language.bin", set_menu.language, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_LANGUAGE);
+ #endif
+ #if ENABLED(MKS_WIFI_MODULE)
+ lv_big_button_create(scr, "F:/bmp_wifi.bin", set_menu.wifi, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_WIFI);
+ #endif
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_RETURN);
+}
+
+void lv_clear_set() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_set.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.h
new file mode 100644
index 0000000..eed0c6c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_set(void);
+extern void lv_clear_set();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.cpp
new file mode 100644
index 0000000..e3f26d8
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.cpp
@@ -0,0 +1,115 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_STEP_RETURN = 1,
+ ID_STEP_X,
+ ID_STEP_Y,
+ ID_STEP_Z,
+ ID_STEP_E0,
+ ID_STEP_E1,
+ ID_STEP_DOWN,
+ ID_STEP_UP
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ lv_clear_step_settings();
+ switch (obj->mks_obj_id) {
+ case ID_STEP_RETURN:
+ uiCfg.para_ui_page = 0;
+ lv_draw_return_ui();
+ return;
+ case ID_STEP_X:
+ value = Xstep;
+ break;
+ case ID_STEP_Y:
+ value = Ystep;
+ break;
+ case ID_STEP_Z:
+ value = Zstep;
+ break;
+ case ID_STEP_E0:
+ value = E0step;
+ break;
+ case ID_STEP_E1:
+ value = E1step;
+ break;
+ case ID_STEP_UP:
+ uiCfg.para_ui_page = 0;
+ lv_draw_step_settings();
+ return;
+ case ID_STEP_DOWN:
+ uiCfg.para_ui_page = 1;
+ lv_draw_step_settings();
+ return;
+ }
+ lv_draw_number_key();
+}
+
+void lv_draw_step_settings(void) {
+ char str_1[16];
+ scr = lv_screen_create(STEPS_UI, machine_menu.StepsConfTitle);
+
+ if (uiCfg.para_ui_page != 1) {
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[X_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.X_Steps, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_STEP_X, 0, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Y_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Y_Steps, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_STEP_Y, 1, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Z_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Z_Steps, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_STEP_Z, 2, public_buf_l);
+
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.E0_Steps, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_STEP_E0, 3, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_STEP_DOWN);
+ }
+ else {
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS_N(1)], 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.E1_Steps, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_STEP_E1, 0, public_buf_l);
+ lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_STEP_UP);
+ }
+ lv_screen_menu_item_return(scr, event_handler, ID_STEP_RETURN);
+}
+
+void lv_clear_step_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.h
new file mode 100644
index 0000000..b7eaeb4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_step_settings(void);
+extern void lv_clear_step_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.cpp
new file mode 100644
index 0000000..acea430
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.cpp
@@ -0,0 +1,156 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, HAS_TRINAMIC_CONFIG)
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/stepper/indirection.h"
+#include "../../../../feature/tmc_util.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_TMC_CURRENT_RETURN = 1,
+ ID_TMC_CURRENT_X,
+ ID_TMC_CURRENT_Y,
+ ID_TMC_CURRENT_Z,
+ ID_TMC_CURRENT_E0,
+ ID_TMC_CURRENT_E1,
+ ID_TMC_CURRENT_DOWN,
+ ID_TMC_CURRENT_UP
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ lv_clear_tmc_current_settings();
+ switch (obj->mks_obj_id) {
+ case ID_TMC_CURRENT_RETURN:
+ uiCfg.para_ui_page = 0;
+ lv_draw_return_ui();
+ return;
+ #if AXIS_IS_TMC(X)
+ case ID_TMC_CURRENT_X:
+ value = Xcurrent;
+ break;
+ #endif
+ #if AXIS_IS_TMC(Y)
+ case ID_TMC_CURRENT_Y:
+ value = Ycurrent;
+ break;
+ #endif
+ #if AXIS_IS_TMC(Z)
+ case ID_TMC_CURRENT_Z:
+ value = Zcurrent;
+ break;
+ #endif
+ #if AXIS_IS_TMC(E0)
+ case ID_TMC_CURRENT_E0:
+ value = E0current;
+ break;
+ #endif
+ #if AXIS_IS_TMC(E1)
+ case ID_TMC_CURRENT_E1:
+ value = E1current;
+ break;
+ #endif
+
+ case ID_TMC_CURRENT_UP:
+ uiCfg.para_ui_page = 0;
+ lv_draw_tmc_current_settings();
+ return;
+ case ID_TMC_CURRENT_DOWN:
+ uiCfg.para_ui_page = 1;
+ lv_draw_tmc_current_settings();
+ return;
+ }
+ lv_draw_number_key();
+
+}
+
+void lv_draw_tmc_current_settings(void) {
+ scr = lv_screen_create(TMC_CURRENT_UI, machine_menu.TmcCurrentConfTitle);
+
+ float milliamps;
+ char str_1[16];
+ if (uiCfg.para_ui_page != 1) {
+ #if AXIS_IS_TMC(X)
+ milliamps = stepperX.getMilliamps();
+ #else
+ milliamps = -1;
+ #endif
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.X_Current, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_CURRENT_X, 0, public_buf_l);
+
+ #if AXIS_IS_TMC(Y)
+ milliamps = stepperY.getMilliamps();
+ #else
+ milliamps = -1;
+ #endif
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Y_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_TMC_CURRENT_Y, 1, public_buf_l);
+
+ #if AXIS_IS_TMC(Z)
+ milliamps = stepperZ.getMilliamps();
+ #else
+ milliamps = -1;
+ #endif
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.Z_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_TMC_CURRENT_Z, 2, public_buf_l);
+
+ #if AXIS_IS_TMC(E0)
+ milliamps = stepperE0.getMilliamps();
+ #else
+ milliamps = -1;
+ #endif
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.E0_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_TMC_CURRENT_E0, 3, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_TMC_CURRENT_DOWN);
+ }
+ else {
+ #if AXIS_IS_TMC(E1)
+ milliamps = stepperE1.getMilliamps();
+ #else
+ milliamps = -1;
+ #endif
+ sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1));
+ lv_screen_menu_item_1_edit(scr, machine_menu.E1_Current, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_CURRENT_E1, 0, public_buf_l);
+
+ lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_TMC_CURRENT_UP);
+ }
+
+ lv_screen_menu_item_return(scr, event_handler, ID_TMC_CURRENT_RETURN);
+}
+
+void lv_clear_tmc_current_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI && HAS_TRINAMIC_CONFIG
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.h
new file mode 100644
index 0000000..927db37
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.h
@@ -0,0 +1,34 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_tmc_current_settings(void);
+extern void lv_clear_tmc_current_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
+
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.cpp
new file mode 100644
index 0000000..5ba7fe3
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.cpp
@@ -0,0 +1,154 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, HAS_STEALTHCHOP)
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../module/stepper/indirection.h"
+#include "../../../../feature/tmc_util.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(EEPROM_SETTINGS)
+ #include "../../../../module/settings.h"
+#endif
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_TMC_MODE_RETURN = 1,
+ ID_TMC_MODE_X,
+ ID_TMC_MODE_Y,
+ ID_TMC_MODE_Z,
+ ID_TMC_MODE_E0,
+ ID_TMC_MODE_E1,
+ ID_TMC_MODE_DOWN,
+ ID_TMC_MODE_UP
+};
+
+static lv_obj_t *buttonXState = nullptr, *buttonYState = nullptr, *buttonZState = nullptr, *buttonE0State = nullptr;
+
+static lv_obj_t *buttonE1State = nullptr;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+
+ auto toggle_chop = [&](auto &stepper, auto &button) {
+ const bool isena = stepper.toggle_stepping_mode();
+ lv_screen_menu_item_onoff_update(button, isena);
+ TERN_(EEPROM_SETTINGS, (void)settings.save());
+ };
+
+ switch (obj->mks_obj_id) {
+ case ID_TMC_MODE_RETURN:
+ uiCfg.para_ui_page = 0;
+ lv_clear_tmc_step_mode_settings();
+ lv_draw_return_ui();
+ break;
+
+ #if AXIS_HAS_STEALTHCHOP(X)
+ case ID_TMC_MODE_X:
+ toggle_chop(stepperX, buttonXState);
+ break;
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(Y)
+ case ID_TMC_MODE_Y:
+ toggle_chop(stepperY, buttonYState);
+ break;
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(Z)
+ case ID_TMC_MODE_Z:
+ toggle_chop(stepperZ, buttonZState);
+ break;
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(E0)
+ case ID_TMC_MODE_E0:
+ toggle_chop(stepperE0, buttonE0State);
+ break;
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(E1)
+ case ID_TMC_MODE_E1:
+ toggle_chop(stepperE1, buttonE1State);
+ break;
+ #endif
+
+ case ID_TMC_MODE_UP:
+ uiCfg.para_ui_page = 0;
+ lv_clear_tmc_step_mode_settings();
+ lv_draw_tmc_step_mode_settings();
+ break;
+ case ID_TMC_MODE_DOWN:
+ uiCfg.para_ui_page = 1;
+ lv_clear_tmc_step_mode_settings();
+ lv_draw_tmc_step_mode_settings();
+ break;
+ }
+}
+
+void lv_draw_tmc_step_mode_settings(void) {
+ buttonXState = buttonYState = buttonZState = buttonE0State = buttonE1State = nullptr;
+
+ scr = lv_screen_create(TMC_MODE_UI, machine_menu.TmcStepModeConfTitle);
+
+ bool stealth_X = false, stealth_Y = false, stealth_Z = false, stealth_E0 = false, stealth_E1 = false;
+ #if AXIS_HAS_STEALTHCHOP(X)
+ stealth_X = stepperX.get_stealthChop();
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(Y)
+ stealth_Y = stepperY.get_stealthChop();
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(Z)
+ stealth_Z = stepperZ.get_stealthChop();
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(E0)
+ stealth_E0 = stepperE0.get_stealthChop();
+ #endif
+ #if AXIS_HAS_STEALTHCHOP(E1)
+ stealth_E1 = stepperE1.get_stealthChop();
+ #endif
+
+ if (uiCfg.para_ui_page != 1) {
+ buttonXState = lv_screen_menu_item_onoff(scr, machine_menu.X_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_MODE_X, 0, stealth_X);
+ buttonYState = lv_screen_menu_item_onoff(scr, machine_menu.Y_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_TMC_MODE_Y, 1, stealth_Y);
+ buttonZState = lv_screen_menu_item_onoff(scr, machine_menu.Z_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_TMC_MODE_Z, 2, stealth_Z);
+ buttonE0State = lv_screen_menu_item_onoff(scr, machine_menu.E0_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_TMC_MODE_E0, 2, stealth_E0);
+ lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_TMC_MODE_DOWN);
+ }
+ else {
+ buttonE1State = lv_screen_menu_item_onoff(scr, machine_menu.E1_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_MODE_E1, 0, stealth_E1);
+ lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_TMC_MODE_UP);
+ }
+
+ lv_screen_menu_item_return(scr, event_handler, ID_TMC_MODE_RETURN);
+}
+
+void lv_clear_tmc_step_mode_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI && HAS_STEALTHCHOP
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.h
new file mode 100644
index 0000000..35c57ab
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_tmc_step_mode_settings(void);
+extern void lv_clear_tmc_step_mode_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp
new file mode 100644
index 0000000..559d166
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp
@@ -0,0 +1,113 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../gcode/queue.h"
+#include "../../../../module/temperature.h"
+#include "../../../../inc/MarlinConfig.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+
+enum {
+ ID_T_PRE_HEAT = 1,
+ ID_T_EXTRUCT,
+ ID_T_MOV,
+ ID_T_HOME,
+ ID_T_LEVELING,
+ ID_T_FILAMENT,
+ ID_T_MORE,
+ ID_T_RETURN
+};
+
+#if ENABLED(MKS_TEST)
+ extern uint8_t curent_disp_ui;
+#endif
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
+ bool clear = (obj->mks_obj_id != ID_T_LEVELING);
+ #else
+ constexpr bool clear = true;
+ #endif
+ if (clear) lv_clear_tool();
+ switch (obj->mks_obj_id) {
+ case ID_T_PRE_HEAT:
+ lv_draw_preHeat();
+ break;
+ case ID_T_EXTRUCT:
+ lv_draw_extrusion();
+ break;
+ case ID_T_MOV:
+ lv_draw_move_motor();
+ break;
+ case ID_T_HOME:
+ lv_draw_home();
+ break;
+ case ID_T_LEVELING:
+ #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
+ get_gcode_command(AUTO_LEVELING_COMMAND_ADDR,(uint8_t *)public_buf_m);
+ public_buf_m[sizeof(public_buf_m)-1] = 0;
+ queue.inject_P(PSTR(public_buf_m));
+ #else
+ uiCfg.leveling_first_time = 1;
+ lv_draw_manualLevel();
+ #endif
+ break;
+ case ID_T_FILAMENT:
+ uiCfg.desireSprayerTempBak = thermalManager.temp_hotend[uiCfg.curSprayerChoose].target;
+ lv_draw_filament_change();
+ break;
+ case ID_T_MORE: lv_draw_more(); break;
+ case ID_T_RETURN:
+ TERN_(MKS_TEST, curent_disp_ui = 1);
+ lv_draw_ready_print();
+ break;
+ }
+}
+
+void lv_draw_tool(void) {
+ scr = lv_screen_create(TOOL_UI);
+ lv_big_button_create(scr, "F:/bmp_preHeat.bin", tool_menu.preheat, INTERVAL_V, titleHeight, event_handler, ID_T_PRE_HEAT);
+ lv_big_button_create(scr, "F:/bmp_extruct.bin", tool_menu.extrude, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_T_EXTRUCT);
+ lv_big_button_create(scr, "F:/bmp_mov.bin", tool_menu.move, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_T_MOV);
+ lv_big_button_create(scr, "F:/bmp_zero.bin", tool_menu.home, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_T_HOME);
+ lv_big_button_create(scr, "F:/bmp_leveling.bin", tool_menu.TERN(AUTO_BED_LEVELING_BILINEAR, autoleveling, leveling), INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_LEVELING);
+ lv_big_button_create(scr, "F:/bmp_filamentchange.bin", tool_menu.filament, BTN_X_PIXEL+INTERVAL_V*2,BTN_Y_PIXEL+INTERVAL_H+titleHeight, event_handler,ID_T_FILAMENT);
+ lv_big_button_create(scr, "F:/bmp_more.bin", tool_menu.more, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_MORE);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_RETURN);
+}
+
+void lv_clear_tool() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.h
new file mode 100644
index 0000000..2191adc
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_tool(void);
+extern void lv_clear_tool();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.cpp
new file mode 100644
index 0000000..f997f29
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.cpp
@@ -0,0 +1,117 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, TOUCH_SCREEN_CALIBRATION)
+
+#include "draw_ui.h"
+#include "draw_touch_calibration.h"
+#include <lv_conf.h>
+
+#include "../../../../inc/MarlinConfig.h"
+#include "../../../tft_io/touch_calibration.h"
+#include "SPI_TFT.h"
+
+static lv_obj_t *scr;
+static lv_obj_t *status_label;
+
+static void event_handler(lv_obj_t *obj, lv_event_t event);
+
+enum {
+ ID_TC_RETURN = 1
+};
+
+static void drawCross(uint16_t x, uint16_t y, uint16_t color) {
+ SPI_TFT.tftio.set_window(x - 15, y, x + 15, y);
+ SPI_TFT.tftio.WriteMultiple(color, 31);
+ SPI_TFT.tftio.set_window(x, y - 15, x, y + 15);
+ SPI_TFT.tftio.WriteMultiple(color, 31);
+}
+
+void lv_update_touch_calibration_screen() {
+ uint16_t x, y;
+
+ calibrationState calibration_stage = touch_calibration.get_calibration_state();
+ if (calibration_stage == CALIBRATION_NONE) {
+ // start and clear screen
+ calibration_stage = touch_calibration.calibration_start();
+ }
+ else {
+ // clear last cross
+ x = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].x;
+ y = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].y;
+ drawCross(x, y, LV_COLOR_BACKGROUND.full);
+ }
+
+ const char *str = nullptr;
+ if (calibration_stage < CALIBRATION_SUCCESS) {
+ // handle current state
+ switch (calibration_stage) {
+ case CALIBRATION_TOP_LEFT: str = GET_TEXT(MSG_TOP_LEFT); break;
+ case CALIBRATION_BOTTOM_LEFT: str = GET_TEXT(MSG_BOTTOM_LEFT); break;
+ case CALIBRATION_TOP_RIGHT: str = GET_TEXT(MSG_TOP_RIGHT); break;
+ case CALIBRATION_BOTTOM_RIGHT: str = GET_TEXT(MSG_BOTTOM_RIGHT); break;
+ default: break;
+ }
+
+ x = touch_calibration.calibration_points[calibration_stage].x;
+ y = touch_calibration.calibration_points[calibration_stage].y;
+ drawCross(x, y, LV_COLOR_WHITE.full);
+ }
+ else {
+ // end calibration
+ str = calibration_stage == CALIBRATION_SUCCESS ? GET_TEXT(MSG_CALIBRATION_COMPLETED) : GET_TEXT(MSG_CALIBRATION_FAILED);
+ touch_calibration.calibration_end();
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_TC_RETURN);
+ }
+
+ // draw current message
+ lv_label_set_text(status_label, str);
+ lv_obj_align(status_label, nullptr, LV_ALIGN_CENTER, 0, 0);
+}
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_TC_RETURN:
+ lv_clear_touch_calibration_screen();
+ lv_draw_return_ui();
+ break;
+ }
+}
+
+void lv_draw_touch_calibration_screen() {
+ scr = lv_screen_create(TOUCH_CALIBRATION_UI, "");
+
+ status_label = lv_label_create(scr, "");
+ lv_obj_align(status_label, nullptr, LV_ALIGN_CENTER, 0, 0);
+
+ lv_refr_now(lv_refr_get_disp_refreshing());
+
+ lv_update_touch_calibration_screen();
+}
+
+void lv_clear_touch_calibration_screen() {
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI && TOUCH_SCREEN_CALIBRATION
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.h
new file mode 100644
index 0000000..63749a2
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.h
@@ -0,0 +1,34 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_touch_calibration_screen();
+extern void lv_clear_touch_calibration_screen();
+extern void lv_update_touch_calibration_screen();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.cpp
new file mode 100644
index 0000000..55d8a1b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.cpp
@@ -0,0 +1,101 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "../../../../MarlinCore.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../module/probe.h"
+
+#include "draw_ui.h"
+
+extern lv_group_t * g;
+static lv_obj_t * scr, * zOffsetText;
+
+enum {
+ ID_TM_INIT = 1,
+ ID_TM_ZOFFSETPOS,
+ ID_TM_ZOFFSETNEG,
+ ID_TM_SAVE,
+ ID_TM_TEST,
+ ID_TM_RETURN
+ };
+
+static void event_handler(lv_obj_t * obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_TM_INIT:
+ queue.inject_P(PSTR("M851 Z0\nG28\nG1 Z0 F200\nM211 S0"));
+ break;
+ case ID_TM_ZOFFSETPOS:
+ queue.inject_P(PSTR("M290 Z0.1"));
+ break;
+ case ID_TM_ZOFFSETNEG:
+ queue.inject_P(PSTR("M290 Z-0.1"));
+ break;
+ case ID_TM_SAVE:
+ queue.inject_P(PSTR("M211 S1\nM500\nG28 X Y"));
+ break;
+ case ID_TM_TEST:
+ queue.inject_P(PSTR("G28\nG1 Z0"));
+ break;
+ case ID_TM_RETURN:
+ lv_clear_touchmi_settings();
+ lv_draw_return_ui();
+ break;
+
+ }
+}
+
+void lv_draw_touchmi_settings(void) {
+ scr = lv_screen_create(TOUCHMI_UI, machine_menu.LevelingTouchmiConf);
+ lv_big_button_create(scr, "F:/bmp_speed0.bin", machine_menu.TouchmiInit, INTERVAL_V, titleHeight, event_handler, ID_TM_INIT);
+ lv_big_button_create(scr, "F:/bmp_zAdd.bin", machine_menu.TouchmiOffsetpos, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_TM_ZOFFSETPOS);
+ lv_big_button_create(scr, "F:/bmp_zDec.bin", machine_menu.TouchmiOffsetneg, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_TM_ZOFFSETNEG);
+ lv_big_button_create(scr, "F:/bmp_set.bin", machine_menu.TouchmiSave, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_TM_SAVE);
+ lv_big_button_create(scr, "F:/bmp_in.bin", machine_menu.TouchmiTest, BTN_X_PIXEL * 3 + INTERVAL_V * 4,titleHeight, event_handler, ID_TM_TEST);
+ lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_TM_RETURN);
+
+
+ zOffsetText = lv_label_create(scr, 290, TITLE_YPOS, nullptr);
+ disp_z_offset_value_TM();
+}
+
+void disp_z_offset_value_TM() {
+ char buf[20];
+ #if HAS_BED_PROBE
+ char str_1[16];
+ #endif
+ sprintf_P(buf, PSTR("offset Z: %s mm"), TERN(HAS_BED_PROBE, dtostrf(probe.offset.z, 1, 2, str_1), "0"));
+ lv_label_set_text(zOffsetText, buf);
+}
+
+
+void lv_clear_touchmi_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.h
new file mode 100644
index 0000000..cea28df
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.h
@@ -0,0 +1,35 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_touchmi_settings(void);
+extern void lv_clear_touchmi_settings();
+extern void disp_z_offset_value_TM();
+
+//extern void disp_temp_ready_print();
+#ifdef __cplusplus
+} /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
new file mode 100644
index 0000000..8fc399e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp
@@ -0,0 +1,1510 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "SPI_TFT.h"
+
+#include "tft_lvgl_configuration.h"
+
+#include "pic_manager.h"
+
+#include "draw_ui.h"
+#include "mks_hardware_test.h"
+
+#include <SPI.h>
+
+#include "../../../../MarlinCore.h" // for marlin_state
+#include "../../../../sd/cardreader.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if ENABLED(PARK_HEAD_ON_PAUSE)
+ #include "../../../../feature/pause.h"
+#endif
+
+#if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ #include "draw_touch_calibration.h"
+#endif
+
+CFG_ITMES gCfgItems;
+UI_CFG uiCfg;
+DISP_STATE_STACK disp_state_stack;
+DISP_STATE disp_state = MAIN_UI;
+DISP_STATE last_disp_state;
+PRINT_TIME print_time;
+num_key_value_state value;
+keyboard_value_state keyboard_value;
+
+uint32_t To_pre_view;
+bool gcode_preview_over, flash_preview_begin, default_preview_flg;
+uint32_t size = 809;
+uint16_t row;
+bool temps_update_flag;
+uint8_t printing_rate_update_flag;
+
+extern bool once_flag;
+extern uint8_t sel_id;
+extern lv_group_t *g;
+
+extern uint8_t bmp_public_buf[14 * 1024];
+extern uint8_t public_buf[513];
+
+extern void LCD_IO_WriteData(uint16_t RegValue);
+
+static const char custom_gcode_command[][100] = {
+ "G28\nG29\nM500",
+ "G28",
+ "G28",
+ "G28",
+ "G28"
+};
+
+lv_point_t line_points[4][2] = {
+ {{PARA_UI_POS_X, PARA_UI_POS_Y + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y + PARA_UI_SIZE_Y}},
+ {{PARA_UI_POS_X, PARA_UI_POS_Y*2 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*2 + PARA_UI_SIZE_Y}},
+ {{PARA_UI_POS_X, PARA_UI_POS_Y*3 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*3 + PARA_UI_SIZE_Y}},
+ {{PARA_UI_POS_X, PARA_UI_POS_Y*4 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*4 + PARA_UI_SIZE_Y}}
+};
+void gCfgItems_init() {
+ gCfgItems.multiple_language = MULTI_LANGUAGE_ENABLE;
+ #if 1 // LCD_LANGUAGE == en
+ gCfgItems.language = LANG_ENGLISH;
+ #elif LCD_LANGUAGE == zh_CN
+ gCfgItems.language = LANG_SIMPLE_CHINESE;
+ #elif LCD_LANGUAGE == zh_TW
+ gCfgItems.language = LANG_COMPLEX_CHINESE;
+ #elif LCD_LANGUAGE == jp_kana
+ gCfgItems.language = LANG_JAPAN;
+ #elif LCD_LANGUAGE == de
+ gCfgItems.language = LANG_GERMAN;
+ #elif LCD_LANGUAGE == fr
+ gCfgItems.language = LANG_FRENCH;
+ #elif LCD_LANGUAGE == ru
+ gCfgItems.language = LANG_RUSSIAN;
+ #elif LCD_LANGUAGE == ko_KR
+ gCfgItems.language = LANG_KOREAN;
+ #elif LCD_LANGUAGE == tr
+ gCfgItems.language = LANG_TURKISH;
+ #elif LCD_LANGUAGE == es
+ gCfgItems.language = LANG_SPANISH;
+ #elif LCD_LANGUAGE == el
+ gCfgItems.language = LANG_GREEK;
+ #elif LCD_LANGUAGE == it
+ gCfgItems.language = LANG_ITALY;
+ #elif LCD_LANGUAGE == pt
+ gCfgItems.language = LANG_PORTUGUESE;
+ #endif
+ gCfgItems.leveling_mode = 0;
+ gCfgItems.from_flash_pic = false;
+ gCfgItems.curFilesize = 0;
+ gCfgItems.finish_power_off = false;
+ gCfgItems.pause_reprint = false;
+ gCfgItems.pausePosX = -1;
+ gCfgItems.pausePosY = -1;
+ gCfgItems.pausePosZ = 5;
+ gCfgItems.levelingPos[0][0] = X_MIN_POS + 30;
+ gCfgItems.levelingPos[0][1] = Y_MIN_POS + 30;
+ gCfgItems.levelingPos[1][0] = X_MAX_POS - 30;
+ gCfgItems.levelingPos[1][1] = Y_MIN_POS + 30;
+ gCfgItems.levelingPos[2][0] = X_MAX_POS - 30;
+ gCfgItems.levelingPos[2][1] = Y_MAX_POS - 30;
+ gCfgItems.levelingPos[3][0] = X_MIN_POS + 30;
+ gCfgItems.levelingPos[3][1] = Y_MAX_POS - 30;
+ gCfgItems.levelingPos[4][0] = X_BED_SIZE / 2;
+ gCfgItems.levelingPos[4][1] = Y_BED_SIZE / 2;
+ gCfgItems.cloud_enable = false;
+ gCfgItems.wifi_mode_sel = STA_MODEL;
+ gCfgItems.fileSysType = FILE_SYS_SD;
+ gCfgItems.wifi_type = ESP_WIFI;
+ gCfgItems.filamentchange_load_length = 200;
+ gCfgItems.filamentchange_load_speed = 1000;
+ gCfgItems.filamentchange_unload_length = 200;
+ gCfgItems.filamentchange_unload_speed = 1000;
+ gCfgItems.filament_limit_temper = 200;
+
+ gCfgItems.encoder_enable = true;
+
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)&gCfgItems.spi_flash_flag, VAR_INF_ADDR, sizeof(gCfgItems.spi_flash_flag));
+ if (gCfgItems.spi_flash_flag == FLASH_INF_VALID_FLAG) {
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
+ }
+ else {
+ gCfgItems.spi_flash_flag = FLASH_INF_VALID_FLAG;
+ W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR);
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
+ //init gcode command
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[0], AUTO_LEVELING_COMMAND_ADDR, 100);
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[1], OTHERS_COMMAND_ADDR_1, 100);
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[2], OTHERS_COMMAND_ADDR_2, 100);
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[3], OTHERS_COMMAND_ADDR_3, 100);
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[4], OTHERS_COMMAND_ADDR_4, 100);
+ }
+
+ const byte rot = (TFT_ROTATION & TFT_ROTATE_180) ? 0xEE : 0x00;
+ if (gCfgItems.disp_rotation_180 != rot) {
+ gCfgItems.disp_rotation_180 = rot;
+ update_spi_flash();
+ }
+
+ uiCfg.F[0] = 'N';
+ uiCfg.F[1] = 'A';
+ uiCfg.F[2] = 'N';
+ uiCfg.F[3] = 'O';
+ W25QXX.SPI_FLASH_BlockErase(REFLSHE_FLGA_ADD + 32 - 64*1024);
+ W25QXX.SPI_FLASH_BufferWrite(uiCfg.F,REFLSHE_FLGA_ADD,4);
+}
+
+void ui_cfg_init() {
+ uiCfg.curTempType = 0;
+ uiCfg.curSprayerChoose = 0;
+ uiCfg.stepHeat = 10;
+ uiCfg.leveling_first_time = 0;
+ uiCfg.para_ui_page = 0;
+ uiCfg.extruStep = 5;
+ uiCfg.extruSpeed = 10;
+ uiCfg.move_dist = 1;
+ uiCfg.moveSpeed = 3000;
+ uiCfg.stepPrintSpeed = 10;
+ uiCfg.command_send = 0;
+ uiCfg.dialogType = 0;
+ uiCfg.filament_heat_completed_load = 0;
+ uiCfg.filament_rate = 0;
+ uiCfg.filament_loading_completed = 0;
+ uiCfg.filament_unloading_completed = 0;
+ uiCfg.filament_loading_time_flg = 0;
+ uiCfg.filament_loading_time_cnt = 0;
+ uiCfg.filament_unloading_time_flg = 0;
+ uiCfg.filament_unloading_time_cnt = 0;
+
+ #if ENABLED(MKS_WIFI_MODULE)
+ memset(&wifiPara, 0, sizeof(wifiPara));
+ memset(&ipPara, 0, sizeof(ipPara));
+ strcpy(wifiPara.ap_name, WIFI_AP_NAME);
+ strcpy(wifiPara.keyCode, WIFI_KEY_CODE);
+ //client
+ strcpy(ipPara.ip_addr, IP_ADDR);
+ strcpy(ipPara.mask, IP_MASK);
+ strcpy(ipPara.gate, IP_GATE);
+ strcpy(ipPara.dns, IP_DNS);
+
+ ipPara.dhcp_flag = IP_DHCP_FLAG;
+
+ //AP
+ strcpy(ipPara.dhcpd_ip, AP_IP_ADDR);
+ strcpy(ipPara.dhcpd_mask, AP_IP_MASK);
+ strcpy(ipPara.dhcpd_gate, AP_IP_GATE);
+ strcpy(ipPara.dhcpd_dns, AP_IP_DNS);
+ strcpy(ipPara.start_ip_addr, IP_START_IP);
+ strcpy(ipPara.end_ip_addr, IP_END_IP);
+
+ ipPara.dhcpd_flag = AP_IP_DHCP_FLAG;
+
+ strcpy((char*)uiCfg.cloud_hostUrl, "baizhongyun.cn");
+ uiCfg.cloud_port = 10086;
+ #endif
+
+ uiCfg.filament_loading_time = (uint32_t)((gCfgItems.filamentchange_load_length * 60.0 / gCfgItems.filamentchange_load_speed) + 0.5);
+ uiCfg.filament_unloading_time = (uint32_t)((gCfgItems.filamentchange_unload_length * 60.0 / gCfgItems.filamentchange_unload_speed) + 0.5);
+}
+
+void update_spi_flash() {
+ uint8_t command_buf[512];
+
+ W25QXX.init(SPI_QUARTER_SPEED);
+ //read back the gcode command befor erase spi flash
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf));
+ W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR);
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf));
+}
+
+void update_gcode_command(int addr,uint8_t *s) {
+ uint8_t command_buf[512];
+
+ W25QXX.init(SPI_QUARTER_SPEED);
+ //read back the gcode command befor erase spi flash
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf));
+ W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR);
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems));
+ switch (addr) {
+ case AUTO_LEVELING_COMMAND_ADDR: memcpy(&command_buf[0*100], s, 100); break;
+ case OTHERS_COMMAND_ADDR_1: memcpy(&command_buf[1*100], s, 100); break;
+ case OTHERS_COMMAND_ADDR_2: memcpy(&command_buf[2*100], s, 100); break;
+ case OTHERS_COMMAND_ADDR_3: memcpy(&command_buf[3*100], s, 100); break;
+ case OTHERS_COMMAND_ADDR_4: memcpy(&command_buf[4*100], s, 100); break;
+ default: break;
+ }
+ W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf));
+}
+
+void get_gcode_command(int addr,uint8_t *d) {
+ W25QXX.init(SPI_QUARTER_SPEED);
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)d, addr, 100);
+}
+
+lv_style_t tft_style_scr;
+lv_style_t tft_style_label_pre;
+lv_style_t tft_style_label_rel;
+lv_style_t style_line;
+lv_style_t style_para_value_pre;
+lv_style_t style_para_value_rel;
+
+lv_style_t style_num_key_pre;
+lv_style_t style_num_key_rel;
+
+lv_style_t style_num_text;
+lv_style_t style_sel_text;
+
+lv_style_t style_para_value;
+lv_style_t style_para_back;
+
+lv_style_t lv_bar_style_indic;
+
+lv_style_t style_btn_pr;
+lv_style_t style_btn_rel;
+
+void tft_style_init() {
+ lv_style_copy(&tft_style_scr, &lv_style_scr);
+ tft_style_scr.body.main_color = LV_COLOR_BACKGROUND;
+ tft_style_scr.body.grad_color = LV_COLOR_BACKGROUND;
+ tft_style_scr.text.color = LV_COLOR_TEXT;
+ tft_style_scr.text.sel_color = LV_COLOR_TEXT;
+ tft_style_scr.line.width = 0;
+ tft_style_scr.text.letter_space = 0;
+ tft_style_scr.text.line_space = 0;
+
+ lv_style_copy(&tft_style_label_pre, &lv_style_scr);
+ lv_style_copy(&tft_style_label_rel, &lv_style_scr);
+ tft_style_label_pre.body.main_color = LV_COLOR_BACKGROUND;
+ tft_style_label_pre.body.grad_color = LV_COLOR_BACKGROUND;
+ tft_style_label_pre.text.color = LV_COLOR_TEXT;
+ tft_style_label_pre.text.sel_color = LV_COLOR_TEXT;
+ tft_style_label_rel.body.main_color = LV_COLOR_BACKGROUND;
+ tft_style_label_rel.body.grad_color = LV_COLOR_BACKGROUND;
+ tft_style_label_rel.text.color = LV_COLOR_TEXT;
+ tft_style_label_rel.text.sel_color = LV_COLOR_TEXT;
+ tft_style_label_pre.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
+ tft_style_label_rel.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
+ tft_style_label_pre.line.width = 0;
+ tft_style_label_rel.line.width = 0;
+ tft_style_label_pre.text.letter_space = 0;
+ tft_style_label_rel.text.letter_space = 0;
+ tft_style_label_pre.text.line_space = 0;
+ tft_style_label_rel.text.line_space = 0;
+
+ lv_style_copy(&style_para_value_pre, &lv_style_scr);
+ lv_style_copy(&style_para_value_rel, &lv_style_scr);
+ style_para_value_pre.body.main_color = LV_COLOR_BACKGROUND;
+ style_para_value_pre.body.grad_color = LV_COLOR_BACKGROUND;
+ style_para_value_pre.text.color = LV_COLOR_TEXT;
+ style_para_value_pre.text.sel_color = LV_COLOR_TEXT;
+ style_para_value_rel.body.main_color = LV_COLOR_BACKGROUND;
+ style_para_value_rel.body.grad_color = LV_COLOR_BACKGROUND;
+ style_para_value_rel.text.color = LV_COLOR_BLACK;
+ style_para_value_rel.text.sel_color = LV_COLOR_BLACK;
+ style_para_value_pre.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
+ style_para_value_rel.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
+ style_para_value_pre.line.width = 0;
+ style_para_value_rel.line.width = 0;
+ style_para_value_pre.text.letter_space = 0;
+ style_para_value_rel.text.letter_space = 0;
+ style_para_value_pre.text.line_space = 0;
+ style_para_value_rel.text.line_space = 0;
+
+ lv_style_copy(&style_num_key_pre, &lv_style_scr);
+ lv_style_copy(&style_num_key_rel, &lv_style_scr);
+ style_num_key_pre.body.main_color = LV_COLOR_KEY_BACKGROUND;
+ style_num_key_pre.body.grad_color = LV_COLOR_KEY_BACKGROUND;
+ style_num_key_pre.text.color = LV_COLOR_TEXT;
+ style_num_key_pre.text.sel_color = LV_COLOR_TEXT;
+ style_num_key_rel.body.main_color = LV_COLOR_KEY_BACKGROUND;
+ style_num_key_rel.body.grad_color = LV_COLOR_KEY_BACKGROUND;
+ style_num_key_rel.text.color = LV_COLOR_TEXT;
+ style_num_key_rel.text.sel_color = LV_COLOR_TEXT;
+ #if HAS_SPI_FLASH_FONT
+ style_num_key_pre.text.font = &gb2312_puhui32;
+ style_num_key_rel.text.font = &gb2312_puhui32;
+ #else
+ style_num_key_pre.text.font = LV_FONT_DEFAULT;
+ style_num_key_rel.text.font = LV_FONT_DEFAULT;
+ #endif
+ style_num_key_pre.line.width = 0;
+ style_num_key_rel.line.width = 0;
+ style_num_key_pre.text.letter_space = 0;
+ style_num_key_rel.text.letter_space = 0;
+ style_num_key_pre.text.line_space = 0;
+ style_num_key_rel.text.line_space = 0;
+
+ lv_style_copy(&style_num_text, &lv_style_scr);
+ style_num_text.body.main_color = LV_COLOR_WHITE;
+ style_num_text.body.grad_color = LV_COLOR_WHITE;
+ style_num_text.text.color = LV_COLOR_BLACK;
+ style_num_text.text.sel_color = LV_COLOR_BLACK;
+ style_num_text.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT);
+ style_num_text.line.width = 0;
+ style_num_text.text.letter_space = 0;
+ style_num_text.text.line_space = 0;
+
+ lv_style_copy(&style_sel_text, &lv_style_scr);
+ style_sel_text.body.main_color = LV_COLOR_BACKGROUND;
+ style_sel_text.body.grad_color = LV_COLOR_BACKGROUND;
+ style_sel_text.text.color = LV_COLOR_YELLOW;
+ style_sel_text.text.sel_color = LV_COLOR_YELLOW;
+ style_sel_text.text.font = &gb2312_puhui32;
+ style_sel_text.line.width = 0;
+ style_sel_text.text.letter_space = 0;
+ style_sel_text.text.line_space = 0;
+ lv_style_copy(&style_line, &lv_style_plain);
+ style_line.line.color = LV_COLOR_MAKE(0x49, 0x54, 0xFF);
+ style_line.line.width = 1;
+ style_line.line.rounded = 1;
+
+ lv_style_copy(&style_para_value, &lv_style_plain);
+ style_para_value.body.border.color = LV_COLOR_BACKGROUND;
+ style_para_value.body.border.width = 1;
+ style_para_value.body.main_color = LV_COLOR_WHITE;
+ style_para_value.body.grad_color = LV_COLOR_WHITE;
+ style_para_value.body.shadow.width = 0;
+ style_para_value.body.radius = 3;
+ style_para_value.text.color = LV_COLOR_BLACK;
+ style_para_value.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22);
+
+ lv_style_copy(&style_para_back, &lv_style_plain);
+ style_para_back.body.border.color = LV_COLOR_BACKGROUND;
+ style_para_back.body.border.width = 1;
+ style_para_back.body.main_color = TFT_LV_PARA_BACK_BODY_COLOR;
+ style_para_back.body.grad_color = TFT_LV_PARA_BACK_BODY_COLOR;
+ style_para_back.body.shadow.width = 0;
+ style_para_back.body.radius = 3;
+ style_para_back.text.color = LV_COLOR_WHITE;
+ style_para_back.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22);
+
+ lv_style_copy(&style_btn_rel, &lv_style_plain);
+ style_btn_rel.body.border.color = lv_color_hex3(0x269);
+ style_btn_rel.body.border.width = 1;
+ style_btn_rel.body.main_color = lv_color_hex3(0xADF);
+ style_btn_rel.body.grad_color = lv_color_hex3(0x46B);
+ style_btn_rel.body.shadow.width = 4;
+ style_btn_rel.body.shadow.type = LV_SHADOW_BOTTOM;
+ style_btn_rel.body.radius = LV_RADIUS_CIRCLE;
+ style_btn_rel.text.color = lv_color_hex3(0xDEF);
+ style_btn_rel.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22);
+
+ lv_style_copy(&style_btn_pr, &style_btn_rel);
+ style_btn_pr.body.border.color = lv_color_hex3(0x46B);
+ style_btn_pr.body.main_color = lv_color_hex3(0x8BD);
+ style_btn_pr.body.grad_color = lv_color_hex3(0x24A);
+ style_btn_pr.body.shadow.width = 2;
+ style_btn_pr.text.color = lv_color_hex3(0xBCD);
+ style_btn_pr.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22);
+
+ lv_style_copy(&lv_bar_style_indic, &lv_style_pretty_color);
+ lv_bar_style_indic.text.color = lv_color_hex3(0xADF);
+ lv_bar_style_indic.image.color = lv_color_hex3(0xADF);
+ lv_bar_style_indic.line.color = lv_color_hex3(0xADF);
+ lv_bar_style_indic.body.main_color = lv_color_hex3(0xADF);
+ lv_bar_style_indic.body.grad_color = lv_color_hex3(0xADF);
+ lv_bar_style_indic.body.border.color = lv_color_hex3(0xADF);
+}
+
+#define MAX_TITLE_LEN 28
+
+char public_buf_m[100] = {0};
+char public_buf_l[30];
+
+void titleText_cat(char *str, int strSize, char *addPart) {
+ if (str == 0 || addPart == 0) return;
+ if ((int)(strlen(str) + strlen(addPart)) >= strSize) return;
+ strcat(str, addPart);
+}
+
+char *getDispText(int index) {
+
+ ZERO(public_buf_l);
+
+ switch (disp_state_stack._disp_state[index]) {
+ case PRINT_READY_UI:
+ strcpy(public_buf_l, main_menu.title);
+ break;
+ case PRINT_FILE_UI:
+ strcpy(public_buf_l, file_menu.title);
+ break;
+ case PRINTING_UI:
+ if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI
+ #ifndef TFT35
+ || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI
+ || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI
+ #endif
+ ) strcpy(public_buf_l, common_menu.print_special_title);
+ else strcpy(public_buf_l, printing_menu.title);
+ break;
+ case MOVE_MOTOR_UI:
+ strcpy(public_buf_l, move_menu.title);
+ break;
+ case OPERATE_UI:
+ if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI
+ #ifndef TFT35
+ || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI
+ || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI
+ #endif
+ ) strcpy(public_buf_l, common_menu.operate_special_title);
+ else strcpy(public_buf_l, operation_menu.title);
+ break;
+
+ case PAUSE_UI:
+ if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI
+ || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI
+ || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI
+ ) strcpy(public_buf_l, common_menu.pause_special_title);
+ else strcpy(public_buf_l, pause_menu.title);
+ break;
+
+ case EXTRUSION_UI:
+ strcpy(public_buf_l, extrude_menu.title);
+ break;
+ case CHANGE_SPEED_UI:
+ strcpy(public_buf_l, speed_menu.title);
+ break;
+ case FAN_UI:
+ strcpy(public_buf_l, fan_menu.title);
+ break;
+ case PRE_HEAT_UI:
+ if ((disp_state_stack._disp_state[disp_state_stack._disp_index - 1] == OPERATE_UI))
+ strcpy(public_buf_l, preheat_menu.adjust_title);
+ else strcpy(public_buf_l, preheat_menu.title);
+ break;
+ case SET_UI:
+ strcpy(public_buf_l, set_menu.title);
+ break;
+ case ZERO_UI:
+ strcpy(public_buf_l, home_menu.title);
+ break;
+ case SPRAYER_UI: break;
+ case MACHINE_UI: break;
+ case LANGUAGE_UI:
+ strcpy(public_buf_l, language_menu.title);
+ break;
+ case ABOUT_UI:
+ strcpy(public_buf_l, about_menu.title);
+ break;
+ case LOG_UI: break;
+ case DISK_UI:
+ strcpy(public_buf_l, filesys_menu.title);
+ break;
+ case DIALOG_UI:
+ strcpy(public_buf_l, common_menu.dialog_confirm_title);
+ break;
+ case WIFI_UI:
+ strcpy(public_buf_l, wifi_menu.title);
+ break;
+ case MORE_UI:
+ case PRINT_MORE_UI:
+ strcpy(public_buf_l, more_menu.title);
+ break;
+ case FILAMENTCHANGE_UI:
+ strcpy(public_buf_l, filament_menu.title);
+ break;
+ case LEVELING_UI:
+ case MESHLEVELING_UI:
+ strcpy(public_buf_l, leveling_menu.title);
+ break;
+ case BIND_UI:
+ strcpy(public_buf_l, cloud_menu.title);
+ break;
+ case TOOL_UI:
+ strcpy(public_buf_l, tool_menu.title);
+ break;
+ case WIFI_LIST_UI:
+ #if ENABLED(MKS_WIFI_MODULE)
+ strcpy(public_buf_l, list_menu.title);
+ break;
+ #endif
+ case MACHINE_PARA_UI:
+ strcpy(public_buf_l, MachinePara_menu.title);
+ break;
+ case BABY_STEP_UI:
+ strcpy(public_buf_l, operation_menu.babystep);
+ break;
+ case EEPROM_SETTINGS_UI:
+ strcpy(public_buf_l, eeprom_menu.title);
+ break;
+ default: break;
+ }
+
+ return public_buf_l;
+}
+
+char *creat_title_text() {
+ int index = 0;
+ char *tmpText = 0;
+ char tmpCurFileStr[20];
+
+ ZERO(tmpCurFileStr);
+
+ cutFileName(list_file.long_name[sel_id], 16, 16, tmpCurFileStr);
+
+ ZERO(public_buf_m);
+
+ while (index <= disp_state_stack._disp_index) {
+ tmpText = getDispText(index);
+ if ((*tmpText == 0) || (tmpText == 0)) {
+ index++;
+ continue;
+ }
+
+ titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText);
+ if (index < disp_state_stack._disp_index) titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)">");
+
+ index++;
+ }
+
+ if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI) {
+ titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)":");
+ titleText_cat(public_buf_m, sizeof(public_buf_m), tmpCurFileStr);
+ }
+
+ if (strlen(public_buf_m) > MAX_TITLE_LEN) {
+ ZERO(public_buf_m);
+ tmpText = 0;
+ for (index = 0; index <= disp_state_stack._disp_index && (!tmpText || *tmpText == 0); index++)
+ tmpText = getDispText(index);
+ if (*tmpText != 0) {
+ titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText);
+ titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)">...>");
+ tmpText = getDispText(disp_state_stack._disp_index);
+ if (*tmpText != 0) titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText);
+ }
+ }
+
+ return public_buf_m;
+}
+
+#if HAS_GCODE_PREVIEW
+
+ uint32_t gPicturePreviewStart = 0;
+
+ void preview_gcode_prehandle(char *path) {
+ #if ENABLED(SDSUPPORT)
+ uint32_t pre_read_cnt = 0;
+ uint32_t *p1;
+ //char *cur_name;
+
+ gPicturePreviewStart = 0;
+ //cur_name = strrchr(path, '/');
+ card.openFileRead(path);
+ card.read(public_buf, 512);
+ p1 = (uint32_t *)strstr((char *)public_buf, ";simage:");
+
+ if (p1) {
+ pre_read_cnt = (uint32_t)p1 - (uint32_t)((uint32_t *)(&public_buf[0]));
+
+ To_pre_view = pre_read_cnt;
+ gcode_preview_over = true;
+ gCfgItems.from_flash_pic = true;
+ update_spi_flash();
+ }
+ else {
+ gcode_preview_over = false;
+ default_preview_flg = true;
+ gCfgItems.from_flash_pic = false;
+ update_spi_flash();
+ }
+ card.closefile();
+ #endif
+ }
+
+ void gcode_preview(char *path, int xpos_pixel, int ypos_pixel) {
+ #if ENABLED(SDSUPPORT)
+ volatile uint32_t i, j;
+ volatile uint16_t *p_index;
+ //char *cur_name;
+
+ //cur_name = strrchr(path, '/');
+ card.openFileRead(path);
+
+ if (gPicturePreviewStart <= 0) {
+ while (1) {
+ uint32_t br = card.read(public_buf, 400);
+ uint32_t* p1 = (uint32_t *)strstr((char *)public_buf, ";gimage:");
+ if (p1) {
+ gPicturePreviewStart += (uint32_t)p1 - (uint32_t)((uint32_t *)(&public_buf[0]));
+ break;
+ }
+ else {
+ gPicturePreviewStart += br;
+ }
+ if (br < 400) break;
+ }
+ }
+
+ card.setIndex(gPicturePreviewStart + size * row + 8);
+ SPI_TFT.setWindow(xpos_pixel, ypos_pixel + row, 200, 1);
+
+ j = i = 0;
+
+ while (1) {
+ card.read(public_buf, 400);
+ for (i = 0; i < 400;) {
+ bmp_public_buf[j] = ascii2dec_test((char*)&public_buf[i]) << 4 | ascii2dec_test((char*)&public_buf[i + 1]);
+ i += 2;
+ j++;
+ }
+ if (j >= 400) break;
+ }
+ for (i = 0; i < 400; i += 2) {
+ p_index = (uint16_t *)(&bmp_public_buf[i]);
+ if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full;
+ }
+ SPI_TFT.tftio.WriteSequence((uint16_t*)bmp_public_buf, 200);
+ #if HAS_BAK_VIEW_IN_FLASH
+ W25QXX.init(SPI_QUARTER_SPEED);
+ if (row < 20) W25QXX.SPI_FLASH_SectorErase(BAK_VIEW_ADDR_TFT35 + row * 4096);
+ W25QXX.SPI_FLASH_BufferWrite(bmp_public_buf, BAK_VIEW_ADDR_TFT35 + row * 400, 400);
+ #endif
+ row++;
+ if (row >= 200) {
+ size = 809;
+ row = 0;
+
+ gcode_preview_over = false;
+
+ card.closefile();
+ //char *cur_name;
+
+ //cur_name = strrchr(list_file.file_name[sel_id], '/');
+
+ //SdFile file;
+ //SdFile *curDir;
+ card.endFilePrint();
+ //const char * const fname = card.diveToFile(true, curDir, cur_name);
+ //if (!fname) return;
+ //if (file.open(curDir, fname, O_READ)) {
+ //gCfgItems.curFilesize = file.fileSize();
+ //file.close();
+ //update_spi_flash();
+ //}
+
+ card.openFileRead(list_file.file_name[sel_id]);
+ if (card.isFileOpen()) {
+ gCfgItems.curFilesize = card.getFileSize();
+ update_spi_flash();
+ feedrate_percentage = 100;
+ planner.flow_percentage[0] = 100;
+ planner.e_factor[0] = planner.flow_percentage[0] * 0.01;
+ #if HAS_MULTI_EXTRUDER
+ planner.flow_percentage[1] = 100;
+ planner.e_factor[1] = planner.flow_percentage[1] * 0.01;
+ #endif
+ card.startFileprint();
+ TERN_(POWER_LOSS_RECOVERY, recovery.prepare());
+ once_flag = false;
+ }
+ return;
+ }
+ card.closefile();
+ #endif // SDSUPPORT
+ }
+
+ void draw_default_preview(int xpos_pixel, int ypos_pixel, uint8_t sel) {
+ int index;
+ int y_off = 0;
+ W25QXX.init(SPI_QUARTER_SPEED);
+ for (index = 0; index < 10; index++) { // 200*200
+ #if HAS_BAK_VIEW_IN_FLASH
+ if (sel == 1) {
+ flash_view_Read(bmp_public_buf, 8000); // 20k
+ }
+ else {
+ default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 8k
+ }
+ #else
+ default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 8k
+ #endif
+
+ SPI_TFT.setWindow(xpos_pixel, y_off * 20 + ypos_pixel, 200, 20); // 200*200
+ SPI_TFT.tftio.WriteSequence((uint16_t*)(bmp_public_buf), DEFAULT_VIEW_MAX_SIZE / 20);
+
+ y_off++;
+ }
+ W25QXX.init(SPI_QUARTER_SPEED);
+ }
+
+ void disp_pre_gcode(int xpos_pixel, int ypos_pixel) {
+ if (gcode_preview_over) gcode_preview(list_file.file_name[sel_id], xpos_pixel, ypos_pixel);
+ #if HAS_BAK_VIEW_IN_FLASH
+ if (flash_preview_begin) {
+ flash_preview_begin = false;
+ draw_default_preview(xpos_pixel, ypos_pixel, 1);
+ }
+ #endif
+ #if HAS_GCODE_DEFAULT_VIEW_IN_FLASH
+ if (default_preview_flg) {
+ draw_default_preview(xpos_pixel, ypos_pixel, 0);
+ default_preview_flg = false;
+ }
+ #endif
+ }
+#endif // HAS_GCODE_PREVIEW
+
+void print_time_run() {
+ static uint8_t lastSec = 0;
+
+ if (print_time.seconds >= 60) {
+ print_time.seconds = 0;
+ print_time.minutes++;
+ if (print_time.minutes >= 60) {
+ print_time.minutes = 0;
+ print_time.hours++;
+ }
+ }
+ if (disp_state == PRINTING_UI) {
+ if (lastSec != print_time.seconds) disp_print_time();
+ lastSec = print_time.seconds;
+ }
+}
+
+void GUI_RefreshPage() {
+ if ((systick_uptime_millis % 1000) == 0) temps_update_flag = true;
+ if ((systick_uptime_millis % 3000) == 0) printing_rate_update_flag = true;
+
+ switch (disp_state) {
+ case MAIN_UI:
+ break;
+ case EXTRUSION_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_hotend_temp();
+ }
+ break;
+ case PRE_HEAT_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_desire_temp();
+ }
+ break;
+ case PRINT_READY_UI:
+ break;
+
+ case PRINT_FILE_UI: break;
+
+ case PRINTING_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_ext_temp();
+ disp_bed_temp();
+ disp_fan_speed();
+ disp_print_time();
+ disp_fan_Zpos();
+ }
+ if (printing_rate_update_flag || marlin_state == MF_SD_COMPLETE) {
+ printing_rate_update_flag = false;
+ if (!gcode_preview_over) setProBarRate();
+ }
+ break;
+
+ case OPERATE_UI:
+ break;
+
+ case PAUSE_UI:
+ break;
+
+ case FAN_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_fan_value();
+ }
+ break;
+
+ case MOVE_MOTOR_UI:
+ break;
+
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_UI:
+ if (temps_update_flag) {
+ disp_wifi_state();
+ temps_update_flag = false;
+ }
+ break;
+
+ case BIND_UI:
+ refresh_bind_ui();
+ break;
+ #endif
+ case FILAMENTCHANGE_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_filament_temp();
+ }
+ break;
+ case DIALOG_UI:
+ filament_dialog_handle();
+ TERN_(MKS_WIFI_MODULE, wifi_scan_handle());
+ break;
+ case MESHLEVELING_UI:
+ break;
+ case HARDWARE_TEST_UI:
+ break;
+ case WIFI_LIST_UI:
+ #if ENABLED(MKS_WIFI_MODULE)
+ if (printing_rate_update_flag) {
+ disp_wifi_list();
+ printing_rate_update_flag = false;
+ }
+ #endif
+ break;
+ case KEY_BOARD_UI:
+ break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_TIPS_UI:
+ switch (wifi_tips_type) {
+ case TIPS_TYPE_JOINING:
+ if (wifi_link_state == WIFI_CONNECTED && strcmp((const char *)wifi_list.wifiConnectedName,(const char *)wifi_list.wifiName[wifi_list.nameIndex]) == 0) {
+ tips_disp.timer = TIPS_TIMER_STOP;
+ tips_disp.timer_count = 0;
+
+ lv_clear_wifi_tips();
+ wifi_tips_type = TIPS_TYPE_WIFI_CONECTED;
+ lv_draw_wifi_tips();
+
+ }
+ if (tips_disp.timer_count >= 30 * 1000) {
+ tips_disp.timer = TIPS_TIMER_STOP;
+ tips_disp.timer_count = 0;
+ lv_clear_wifi_tips();
+ wifi_tips_type = TIPS_TYPE_TAILED_JOIN;
+ lv_draw_wifi_tips();
+ }
+ break;
+ case TIPS_TYPE_TAILED_JOIN:
+ if (tips_disp.timer_count >= 3 * 1000) {
+ tips_disp.timer = TIPS_TIMER_STOP;
+ tips_disp.timer_count = 0;
+
+ last_disp_state = WIFI_TIPS_UI;
+ lv_clear_wifi_tips();
+ lv_draw_wifi_list();
+ }
+ break;
+ case TIPS_TYPE_WIFI_CONECTED:
+ if (tips_disp.timer_count >= 3 * 1000) {
+ tips_disp.timer = TIPS_TIMER_STOP;
+ tips_disp.timer_count = 0;
+
+ last_disp_state = WIFI_TIPS_UI;
+ lv_clear_wifi_tips();
+ lv_draw_wifi();
+ }
+ break;
+ default: break;
+ }
+ break;
+ #endif
+
+ case BABY_STEP_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_z_offset_value();
+ }
+ break;
+
+ #if ENABLED(BLTOUCH)
+ case BLTOUCH_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_bltouch_z_offset_value();
+ }
+ break;
+ #endif
+
+ #if ENABLED(TOUCH_MI_PROBE)
+ case TOUCHMI_UI:
+ if (temps_update_flag) {
+ temps_update_flag = false;
+ disp_z_offset_value_TM();
+ }
+ break;
+ #endif
+ default: break;
+ }
+
+ print_time_run();
+}
+
+void lv_clear_cur_ui() {
+ last_disp_state = disp_state_stack._disp_state[disp_state_stack._disp_index];
+
+ switch (disp_state_stack._disp_state[disp_state_stack._disp_index]) {
+ case PRINT_READY_UI:
+ lv_clear_ready_print(); break;
+ case PRINT_FILE_UI: lv_clear_print_file(); break;
+ case PRINTING_UI: lv_clear_printing(); break;
+ case MOVE_MOTOR_UI: lv_clear_move_motor(); break;
+ case OPERATE_UI: lv_clear_operation(); break;
+ case PAUSE_UI: break;
+ case EXTRUSION_UI: lv_clear_extrusion(); break;
+ case PRE_HEAT_UI: lv_clear_preHeat(); break;
+ case CHANGE_SPEED_UI: lv_clear_change_speed(); break;
+ case FAN_UI: lv_clear_fan(); break;
+ case SET_UI: lv_clear_set(); break;
+ case ZERO_UI: lv_clear_home(); break;
+ case SPRAYER_UI: break;
+ case MACHINE_UI: break;
+ case LANGUAGE_UI: lv_clear_language(); break;
+ case ABOUT_UI: lv_clear_about(); break;
+ case LOG_UI: break;
+ case DISK_UI: break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_UI: lv_clear_wifi(); break;
+ #endif
+ case MORE_UI: lv_clear_more(); break;
+ case FILETRANSFER_UI: break;
+ case DIALOG_UI: lv_clear_dialog(); break;
+ case FILETRANSFERSTATE_UI: break;
+ case PRINT_MORE_UI: break;
+ case FILAMENTCHANGE_UI: lv_clear_filament_change(); break;
+ case LEVELING_UI: lv_clear_manualLevel(); break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case BIND_UI: lv_clear_cloud_bind(); break;
+ #endif
+ #if HAS_BED_PROBE
+ case NOZZLE_PROBE_OFFSET_UI: lv_clear_auto_level_offset_settings(); break;
+ #endif
+ case TOOL_UI: lv_clear_tool(); break;
+ case MESHLEVELING_UI: break;
+ case HARDWARE_TEST_UI: break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_LIST_UI: lv_clear_wifi_list(); break;
+ #endif
+ case KEY_BOARD_UI: lv_clear_keyboard(); break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_TIPS_UI: lv_clear_wifi_tips(); break;
+ #endif
+ case MACHINE_PARA_UI: lv_clear_machine_para(); break;
+ case MACHINE_SETTINGS_UI: lv_clear_machine_settings(); break;
+ case TEMPERATURE_SETTINGS_UI: break;
+ case MOTOR_SETTINGS_UI: lv_clear_motor_settings(); break;
+ case MACHINETYPE_UI: break;
+ case STROKE_UI: break;
+ case HOME_DIR_UI: break;
+ case ENDSTOP_TYPE_UI: break;
+ case FILAMENT_SETTINGS_UI: break;
+ case LEVELING_SETTIGNS_UI: break;
+ case LEVELING_PARA_UI: lv_clear_level_settings(); break;
+ case DELTA_LEVELING_PARA_UI: break;
+ case MANUAL_LEVELING_POSIGION_UI: lv_clear_manual_level_pos_settings(); break;
+ case MAXFEEDRATE_UI: lv_clear_max_feedrate_settings(); break;
+ case STEPS_UI: lv_clear_step_settings(); break;
+ case ACCELERATION_UI: lv_clear_acceleration_settings(); break;
+ case JERK_UI: TERN_(HAS_CLASSIC_JERK, lv_clear_jerk_settings()); break;
+ case MOTORDIR_UI: break;
+ case HOMESPEED_UI: break;
+ case NOZZLE_CONFIG_UI: break;
+ case HOTBED_CONFIG_UI: break;
+ case ADVANCED_UI: lv_clear_advance_settings(); break;
+ case DOUBLE_Z_UI: break;
+ case ENABLE_INVERT_UI: break;
+ case NUMBER_KEY_UI: lv_clear_number_key(); break;
+ case BABY_STEP_UI: lv_clear_baby_stepping(); break;
+ #if ENABLED(BLTOUCH)
+ case BLTOUCH_UI: lv_clear_bltouch_settings(); break;
+ #endif
+ #if ENABLED(TOUCH_MI_PROBE)
+ case TOUCHMI_UI: lv_clear_touchmi_settings(); break;
+ #endif
+ case PAUSE_POS_UI: lv_clear_pause_position(); break;
+ #if HAS_TRINAMIC_CONFIG
+ case TMC_CURRENT_UI: lv_clear_tmc_current_settings(); break;
+ #endif
+ case EEPROM_SETTINGS_UI: lv_clear_eeprom_settings(); break;
+ #if HAS_STEALTHCHOP
+ case TMC_MODE_UI: lv_clear_tmc_step_mode_settings(); break;
+ #endif
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_SETTINGS_UI: lv_clear_wifi_settings(); break;
+ #endif
+ #if USE_SENSORLESS
+ case HOMING_SENSITIVITY_UI: lv_clear_homing_sensitivity_settings(); break;
+ #endif
+ #if HAS_ROTARY_ENCODER
+ case ENCODER_SETTINGS_UI: lv_clear_encoder_settings(); break;
+ #endif
+ #if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ case TOUCH_CALIBRATION_UI: lv_clear_touch_calibration_screen(); break;
+ #endif
+ default: break;
+ }
+}
+
+void lv_draw_return_ui() {
+ if (disp_state_stack._disp_index > 0) {
+ disp_state_stack._disp_index--;
+
+ switch (disp_state_stack._disp_state[disp_state_stack._disp_index]) {
+ case PRINT_READY_UI: lv_draw_ready_print(); break;
+ case PRINT_FILE_UI: lv_draw_print_file(); break;
+
+ case PRINTING_UI: if (gCfgItems.from_flash_pic)
+ flash_preview_begin = true;
+ else
+ default_preview_flg = true;
+ lv_draw_printing();
+ break;
+
+ case MOVE_MOTOR_UI: lv_draw_move_motor(); break;
+ case OPERATE_UI: lv_draw_operation(); break;
+ case PAUSE_UI: break;
+ case EXTRUSION_UI: lv_draw_extrusion(); break;
+ case PRE_HEAT_UI: lv_draw_preHeat(); break;
+ case CHANGE_SPEED_UI: lv_draw_change_speed(); break;
+ case FAN_UI: lv_draw_fan(); break;
+ case SET_UI: lv_draw_set(); break;
+ case ZERO_UI: lv_draw_home(); break;
+ case SPRAYER_UI: break;
+ case MACHINE_UI: break;
+ case LANGUAGE_UI: lv_draw_language(); break;
+ case ABOUT_UI: lv_draw_about(); break;
+
+ case CALIBRATE_UI: break;
+ case DISK_UI: break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_UI: lv_draw_wifi(); break;
+ #endif
+ case MORE_UI: break;
+ case PRINT_MORE_UI: lv_draw_more(); break;
+ case FILAMENTCHANGE_UI: lv_draw_filament_change(); break;
+ case LEVELING_UI: lv_draw_manualLevel(); break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case BIND_UI: lv_draw_cloud_bind(); break;
+ #endif
+ #if HAS_BED_PROBE
+ case NOZZLE_PROBE_OFFSET_UI: lv_draw_auto_level_offset_settings(); break;
+ #endif
+ case TOOL_UI: lv_draw_tool(); break;
+ case MESHLEVELING_UI: break;
+ case HARDWARE_TEST_UI: break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_LIST_UI: lv_draw_wifi_list(); break;
+ #endif
+ case KEY_BOARD_UI: lv_draw_keyboard(); break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_TIPS_UI: lv_draw_wifi_tips(); break;
+ #endif
+ case MACHINE_PARA_UI: lv_draw_machine_para(); break;
+ case MACHINE_SETTINGS_UI: lv_draw_machine_settings(); break;
+ case TEMPERATURE_SETTINGS_UI: break;
+ case MOTOR_SETTINGS_UI: lv_draw_motor_settings(); break;
+ case MACHINETYPE_UI: break;
+ case STROKE_UI: break;
+ case HOME_DIR_UI: break;
+ case ENDSTOP_TYPE_UI: break;
+ case FILAMENT_SETTINGS_UI: lv_draw_filament_settings(); break;
+ case LEVELING_SETTIGNS_UI: break;
+ case LEVELING_PARA_UI: lv_draw_level_settings(); break;
+ case DELTA_LEVELING_PARA_UI: break;
+ case MANUAL_LEVELING_POSIGION_UI: lv_draw_manual_level_pos_settings(); break;
+ case MAXFEEDRATE_UI: lv_draw_max_feedrate_settings(); break;
+ case STEPS_UI: lv_draw_step_settings(); break;
+ case ACCELERATION_UI: lv_draw_acceleration_settings(); break;
+ #if HAS_CLASSIC_JERK
+ case JERK_UI: lv_draw_jerk_settings(); break;
+ #endif
+ case MOTORDIR_UI: break;
+ case HOMESPEED_UI: break;
+ case NOZZLE_CONFIG_UI: break;
+ case HOTBED_CONFIG_UI: break;
+ case ADVANCED_UI: lv_draw_advance_settings(); break;
+ case DOUBLE_Z_UI: break;
+ case ENABLE_INVERT_UI: break;
+ case NUMBER_KEY_UI: lv_draw_number_key(); break;
+ case DIALOG_UI: break;
+ case BABY_STEP_UI: lv_draw_baby_stepping(); break;
+ case PAUSE_POS_UI: lv_draw_pause_position(); break;
+ #if HAS_TRINAMIC_CONFIG
+ case TMC_CURRENT_UI: lv_draw_tmc_current_settings(); break;
+ #endif
+ case EEPROM_SETTINGS_UI: lv_draw_eeprom_settings(); break;
+ #if HAS_STEALTHCHOP
+ case TMC_MODE_UI: lv_draw_tmc_step_mode_settings(); break;
+ #endif
+ #if ENABLED(MKS_WIFI_MODULE)
+ case WIFI_SETTINGS_UI: lv_draw_wifi_settings(); break;
+ #endif
+ #if USE_SENSORLESS
+ case HOMING_SENSITIVITY_UI: lv_draw_homing_sensitivity_settings(); break;
+ #endif
+ #if HAS_ROTARY_ENCODER
+ case ENCODER_SETTINGS_UI: lv_draw_encoder_settings(); break;
+ #endif
+ case TOUCHMI_UI: lv_draw_touchmi_settings(); break;
+ default: break;
+ }
+ }
+}
+
+// Set the same image for both Released and Pressed
+void lv_imgbtn_set_src_both(lv_obj_t *imgbtn, const void *src) {
+ lv_imgbtn_set_src(imgbtn, LV_BTN_STATE_REL, src);
+ lv_imgbtn_set_src(imgbtn, LV_BTN_STATE_PR, src);
+}
+
+// Use label style for the image button
+void lv_imgbtn_use_label_style(lv_obj_t *imgbtn) {
+ lv_imgbtn_set_style(imgbtn, LV_BTN_STATE_REL, &tft_style_label_rel);
+ lv_imgbtn_set_style(imgbtn, LV_BTN_STATE_PR, &tft_style_label_pre);
+}
+
+// Use label style for the button
+void lv_btn_use_label_style(lv_obj_t *btn) {
+ lv_btn_set_style(btn, LV_BTN_STYLE_REL, &tft_style_label_rel);
+ lv_btn_set_style(btn, LV_BTN_STYLE_PR, &tft_style_label_pre);
+}
+
+// Use button style for the button
+void lv_btn_use_button_style(lv_obj_t *btn) {
+ lv_btn_set_style(btn, LV_BTN_STYLE_REL, &style_btn_rel);
+ lv_btn_set_style(btn, LV_BTN_STYLE_PR, &style_btn_pr);
+}
+
+// Use a single style for both Released and Pressed
+void lv_btn_set_style_both(lv_obj_t *btn, lv_style_t *style) {
+ lv_btn_set_style(btn, LV_BTN_STYLE_REL, style);
+ lv_btn_set_style(btn, LV_BTN_STYLE_PR, style);
+}
+
+// Create a screen
+lv_obj_t* lv_screen_create(DISP_STATE newScreenType, const char* title) {
+ lv_obj_t *scr = lv_obj_create(nullptr, nullptr);
+ lv_obj_set_style(scr, &tft_style_scr);
+ lv_scr_load(scr);
+ lv_obj_clean(scr);
+
+ // breadcrumbs
+ if (disp_state_stack._disp_state[disp_state_stack._disp_index] != newScreenType) {
+ disp_state_stack._disp_index++;
+ disp_state_stack._disp_state[disp_state_stack._disp_index] = newScreenType;
+ }
+ disp_state = newScreenType;
+
+ // title
+ lv_obj_t *titleLabel = nullptr;
+ if (!title)
+ titleLabel = lv_label_create(scr, TITLE_XPOS, TITLE_YPOS, creat_title_text());
+ else if (title[0] != '\0')
+ titleLabel = lv_label_create(scr, TITLE_XPOS, TITLE_YPOS, title);
+ if (titleLabel)
+ lv_obj_set_style(titleLabel, &tft_style_label_rel);
+
+ lv_refr_now(lv_refr_get_disp_refreshing());
+
+ return scr;
+}
+
+// Create an empty label
+lv_obj_t* lv_label_create_empty(lv_obj_t *par) {
+ lv_obj_t *label = lv_label_create(par, (lv_obj_t*)nullptr);
+ return label;
+}
+
+// Create a label with style and text
+lv_obj_t* lv_label_create(lv_obj_t *par, const char *text) {
+ lv_obj_t *label = lv_label_create_empty(par);
+ if (text) lv_label_set_text(label, text);
+ lv_obj_set_style(label, &tft_style_label_rel);
+ return label;
+}
+
+// Create a label with style, position, and text
+lv_obj_t* lv_label_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, const char *text) {
+ lv_obj_t *label = lv_label_create(par, text);
+ lv_obj_set_pos(label, x, y);
+ return label;
+}
+
+// Create a button with callback, ID, and Style.
+lv_obj_t* lv_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/, lv_style_t *style/*=&style_para_value*/) {
+ lv_obj_t *btn = lv_btn_create(par, nullptr);
+ if (id)
+ lv_obj_set_event_cb_mks(btn, cb, id, "", 0);
+ else
+ lv_obj_set_event_cb(btn, cb);
+ lv_btn_set_style_both(btn, style);
+ return btn;
+}
+
+// Create a button with callback and ID, with label style.
+lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_btn_create(par, cb, id, nullptr);
+ lv_btn_use_label_style(btn);
+ return btn;
+}
+
+// Create a button with callback and ID, with button style.
+lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_btn_create(par, cb, id, nullptr);
+ lv_btn_use_button_style(btn);
+ return btn;
+}
+
+// Create a button with position, size, callback, ID, and style.
+lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id, lv_style_t *style) {
+ lv_obj_t *btn = lv_btn_create(par, cb, id, style);
+ lv_obj_set_pos(btn, x, y);
+ lv_obj_set_size(btn, w, h);
+ return btn;
+}
+
+// Create a button with position, size, callback, and ID. Style set to style_para_value.
+lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_btn_create(par, x, y, w, h, cb, id, &style_para_value);
+ return btn;
+}
+
+// Create a button with position, size, callback, and ID, with label style.
+lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_label_btn_create(par, cb, id);
+ lv_obj_set_pos(btn, x, y);
+ lv_obj_set_size(btn, w, h);
+ return btn;
+}
+
+// Create a button with position, size, callback, and ID, with label style.
+lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_button_btn_create(par, cb, id);
+ lv_obj_set_pos(btn, x, y);
+ lv_obj_set_size(btn, w, h);
+ return btn;
+}
+
+// Create a button with callback and ID. Style set to style_para_back.
+lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/) {
+ return lv_btn_create(par, cb, id, &style_para_back);
+}
+// Create a button with position, size, callback, and ID. Style set to style_para_back.
+lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_btn_create_back(par, cb, id);
+ lv_obj_set_pos(btn, x, y);
+ lv_obj_set_size(btn, w, h);
+ return btn;
+}
+
+// Create an image button with image, callback, and ID. Use label style.
+lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_imgbtn_create(par, nullptr);
+ if (img) lv_imgbtn_set_src_both(btn, img);
+ if (id)
+ lv_obj_set_event_cb_mks(btn, cb, id, "", 0);
+ else
+ lv_obj_set_event_cb(btn, cb);
+ lv_imgbtn_use_label_style(btn);
+ lv_btn_set_layout(btn, LV_LAYOUT_OFF);
+ return btn;
+}
+
+// Create an image button with image, position, callback, and ID. Use label style.
+lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id/*=0*/) {
+ lv_obj_t *btn = lv_imgbtn_create(par, img, cb, id);
+ lv_obj_set_pos(btn, x, y);
+ return btn;
+}
+
+lv_obj_t* lv_big_button_create(lv_obj_t *par, const char *img, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, bool centerLabel) {
+ lv_obj_t *btn = lv_imgbtn_create(par, img, cb, id);
+ lv_obj_set_pos(btn, x, y);
+ lv_obj_t *label = lv_label_create_empty(btn);
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(label, text);
+ if (centerLabel)
+ lv_obj_align(label, btn, LV_ALIGN_CENTER, 0, 0);
+ else
+ lv_obj_align(label, btn, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable))
+ lv_group_add_obj(g, btn);
+ return btn;
+}
+
+lv_obj_t* lv_screen_menu_item(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, bool drawArrow) {
+ lv_obj_t *btn = lv_btn_create(par, nullptr); /*Add a button the current screen*/
+ lv_obj_set_pos(btn, x, y); /*Set its position*/
+ lv_obj_set_size(btn, PARA_UI_SIZE_X, PARA_UI_SIZE_Y); /*Set its size*/
+ if (id > -1) lv_obj_set_event_cb_mks(btn, cb, id, "", 0);
+ lv_btn_use_label_style(btn);
+ lv_btn_set_layout(btn, LV_LAYOUT_OFF);
+ lv_obj_t *label = lv_label_create_empty(btn); /*Add a label to the button*/
+ if (gCfgItems.multiple_language) {
+ lv_label_set_text(label, text);
+ lv_obj_align(label, btn, LV_ALIGN_IN_LEFT_MID, PARA_UI_ITEM_TEXT_H, 0);
+ }
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable))
+ lv_group_add_obj(g, btn);
+
+ if (drawArrow) (void)lv_imgbtn_create(par, "F:/bmp_arrow.bin", x + PARA_UI_SIZE_X, y + PARA_UI_ARROW_V, cb, id);
+
+ lv_obj_t *line1 = lv_line_create(par, nullptr);
+ lv_ex_line(line1, line_points[index]);
+
+ return btn;
+}
+
+lv_obj_t* lv_screen_menu_item_onoff(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const bool curValue) {
+ lv_label_create(par, x + PARA_UI_ITEM_TEXT_H, y + PARA_UI_ITEM_TEXT_V, text);
+
+ lv_obj_t* btnValue = lv_imgbtn_create(par, curValue ? "F:/bmp_enable.bin" : "F:/bmp_disable.bin", PARA_UI_STATE_POS_X, y + PARA_UI_STATE_V, cb, id);
+ lv_obj_t* labelValue = lv_label_create_empty(btnValue);
+ lv_label_set_text(labelValue, curValue ? machine_menu.enable : machine_menu.disable);
+ lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue);
+ lv_obj_t *line1 = lv_line_create(par, nullptr);
+ lv_ex_line(line1, line_points[index]);
+ return btnValue;
+}
+
+void lv_screen_menu_item_1_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue) {
+ lv_label_create(par, x + PARA_UI_ITEM_TEXT_H, y + PARA_UI_ITEM_TEXT_V, text);
+
+ lv_obj_t* btnValue = lv_btn_create(par, PARA_UI_VALUE_POS_X, y + PARA_UI_VALUE_V, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE, cb, id);
+ lv_obj_t* labelValue = lv_label_create_empty(btnValue);
+ lv_label_set_text(labelValue, editValue);
+ lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue);
+
+ lv_obj_t *line1 = lv_line_create(par, nullptr);
+ lv_ex_line(line1, line_points[index]);
+}
+
+void lv_screen_menu_item_2_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue, const int idEdit2, const char *editValue2) {
+ lv_label_create(par, x + PARA_UI_ITEM_TEXT_H, y + PARA_UI_ITEM_TEXT_V, text);
+
+ lv_obj_t* btnValue = lv_btn_create(par, PARA_UI_VALUE_POS_X_2, y + PARA_UI_VALUE_V_2, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE, cb, idEdit2);
+ lv_obj_t* labelValue = lv_label_create_empty(btnValue);
+ lv_label_set_text(labelValue, editValue2);
+ lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue);
+
+ btnValue = lv_btn_create(par, PARA_UI_VALUE_POS_X, y + PARA_UI_VALUE_V, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE, cb, id);
+ labelValue = lv_label_create_empty(btnValue);
+ lv_label_set_text(labelValue, editValue);
+ lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue);
+
+ lv_obj_t *line1 = lv_line_create(par, nullptr);
+ lv_ex_line(line1, line_points[index]);
+}
+
+void lv_screen_menu_item_onoff_update(lv_obj_t *btn, const bool curValue) {
+ lv_imgbtn_set_src_both(btn, curValue ? "F:/bmp_enable.bin" : "F:/bmp_disable.bin");
+ lv_label_set_text((lv_obj_t*)btn->child_ll.head, curValue ? machine_menu.enable : machine_menu.disable);
+}
+
+void lv_screen_menu_item_turn_page(lv_obj_t *par, const char *text, lv_event_cb_t cb, const int id) {
+ lv_obj_t* btnTurnPage = lv_btn_create(par, PARA_UI_TURN_PAGE_POS_X, PARA_UI_TURN_PAGE_POS_Y, PARA_UI_TURN_BTN_X_SIZE, PARA_UI_TURN_BTN_Y_SIZE, cb, id);
+ lv_obj_t* labelTurnPage = lv_label_create_empty(btnTurnPage);
+ lv_btn_set_style_both(btnTurnPage, &style_para_back);
+ lv_label_set_text(labelTurnPage, text);
+ lv_obj_align(labelTurnPage, btnTurnPage, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable))
+ lv_group_add_obj(g, btnTurnPage);
+}
+
+void lv_screen_menu_item_return(lv_obj_t *par, lv_event_cb_t cb, const int id) {
+ lv_obj_t* btnReturn = lv_btn_create(par, PARA_UI_BACL_POS_X, PARA_UI_BACL_POS_Y, PARA_UI_BACK_BTN_X_SIZE, PARA_UI_BACK_BTN_Y_SIZE, cb, id);
+ lv_obj_t* labelReturn = lv_label_create_empty(btnReturn);
+ lv_btn_set_style_both(btnReturn, &style_para_back);
+ lv_label_set_text(labelReturn, common_menu.text_back);
+ lv_obj_align(labelReturn, btnReturn, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable))
+ lv_group_add_obj(g, btnReturn);
+}
+
+#if ENABLED(SDSUPPORT)
+
+ void sd_detection() {
+ static bool last_sd_status;
+ const bool sd_status = IS_SD_INSERTED();
+ if (sd_status != last_sd_status) {
+ last_sd_status = sd_status;
+ if (sd_status) card.mount(); else card.release();
+ }
+ }
+
+#endif
+
+void lv_ex_line(lv_obj_t *line, lv_point_t *points) {
+ // Copy the previous line and apply the new style
+ lv_line_set_points(line, points, 2); // Set the points
+ lv_line_set_style(line, LV_LINE_STYLE_MAIN, &style_line);
+ lv_obj_align(line, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0);
+}
+
+extern volatile uint32_t systick_uptime_millis;
+
+void print_time_count() {
+ if ((systick_uptime_millis % 1000) == 0)
+ if (print_time.start == 1) print_time.seconds++;
+}
+
+void lv_print_finished() {
+ if (once_flag == 0) {
+ stop_print_time();
+
+ flash_preview_begin = false;
+ default_preview_flg = false;
+ lv_clear_cur_ui();
+ lv_draw_dialog(DIALOG_TYPE_FINISH_PRINT);
+
+ once_flag = true;
+
+ #if HAS_SUICIDE
+ if (gCfgItems.finish_power_off) {
+ gcode.process_subcommands_now_P(PSTR("M1001"));
+ queue.inject_P(PSTR("M81"));
+ marlin_state = MF_RUNNING;
+ }
+ #endif
+ uiCfg.print_state = IDLE;
+ }
+}
+
+void LV_TASK_HANDLER() {
+ lv_task_handler();
+ if (mks_test_flag == 0x1E) mks_hardware_test();
+
+ TERN_(HAS_GCODE_PREVIEW, disp_pre_gcode(2, 36));
+
+ GUI_RefreshPage();
+
+ TERN_(MKS_WIFI_MODULE, get_wifi_commands());
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_update_encoder();
+ #endif
+ if (marlin_state == MF_SD_COMPLETE) lv_print_finished();
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h
new file mode 100644
index 0000000..5f27123
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h
@@ -0,0 +1,551 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <lvgl.h>
+
+#include <stdint.h>
+#include <string.h>
+
+// the colors of the last MKS Ui
+#undef LV_COLOR_BACKGROUND
+#define LV_COLOR_BACKGROUND LV_COLOR_MAKE(0x1A, 0x1A, 0x1A)
+
+#define TFT_LV_PARA_BACK_BODY_COLOR LV_COLOR_MAKE(0x4A, 0x52, 0xFF)
+
+#include "tft_lvgl_configuration.h"
+#include "tft_multi_language.h"
+#include "pic_manager.h"
+#include "draw_ready_print.h"
+#include "draw_language.h"
+#include "draw_set.h"
+#include "draw_tool.h"
+#include "draw_print_file.h"
+#include "draw_dialog.h"
+#include "draw_printing.h"
+#include "draw_operation.h"
+#include "draw_preHeat.h"
+#include "draw_extrusion.h"
+#include "draw_home.h"
+#include "draw_more.h"
+#include "draw_move_motor.h"
+#include "draw_fan.h"
+#include "draw_about.h"
+#include "draw_change_speed.h"
+#include "draw_manuaLevel.h"
+#include "draw_error_message.h"
+#include "printer_operation.h"
+#include "draw_machine_para.h"
+#include "draw_machine_settings.h"
+#include "draw_motor_settings.h"
+#include "draw_advance_settings.h"
+#include "draw_acceleration_settings.h"
+#include "draw_number_key.h"
+#include "draw_jerk_settings.h"
+#include "draw_pause_position.h"
+#include "draw_step_settings.h"
+#include "draw_tmc_current_settings.h"
+#include "draw_eeprom_settings.h"
+#include "draw_max_feedrate_settings.h"
+#include "draw_tmc_step_mode_settings.h"
+#include "draw_level_settings.h"
+#include "draw_manual_level_pos_settings.h"
+#include "draw_auto_level_offset_settings.h"
+#include "draw_filament_change.h"
+#include "draw_filament_settings.h"
+#include "draw_homing_sensitivity_settings.h"
+#include "draw_baby_stepping.h"
+#include "draw_keyboard.h"
+#include "draw_encoder_settings.h"
+#include "draw_touchmi_settings.h"
+#include "draw_bltouch_settings.h"
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+ #include "wifiSerial.h"
+ #include "wifi_module.h"
+ #include "wifi_upload.h"
+ #include "draw_wifi_settings.h"
+ #include "draw_wifi.h"
+ #include "draw_wifi_list.h"
+ #include "draw_wifi_tips.h"
+ #include "draw_cloud_bind.h"
+#endif
+
+#define ESP_WIFI 0x02
+#define AP_MODEL 0x01
+#define STA_MODEL 0x02
+
+#define FILE_SYS_USB 0
+#define FILE_SYS_SD 1
+
+#define TICK_CYCLE 1
+
+#define PARA_SEL_ICON_TEXT_COLOR LV_COLOR_MAKE(0x4A, 0x52, 0xFF);
+
+#define TFT35
+
+#ifdef TFT35
+
+ #define TFT_WIDTH 480
+ #define TFT_HEIGHT 320
+
+ #define titleHeight 36 // TFT_screen.title_high
+ #define INTERVAL_H 2 // TFT_screen.gap_h // 2
+ #define INTERVAL_V 2 // TFT_screen.gap_v // 2
+ #define BTN_X_PIXEL 117 // TFT_screen.btn_x_pixel
+ #define BTN_Y_PIXEL 140 // TFT_screen.btn_y_pixel
+
+ #define SIMPLE_FIRST_PAGE_GRAP 30
+
+ #define BUTTON_TEXT_Y_OFFSET -20
+
+ #define TITLE_XPOS 3 // TFT_screen.title_xpos
+ #define TITLE_YPOS 5 // TFT_screen.title_ypos
+
+ #define FILE_BTN_CNT 6
+
+ #define OTHER_BTN_XPIEL 117
+ #define OTHER_BTN_YPIEL 92
+
+ #define FILE_PRE_PIC_X_OFFSET 8
+ #define FILE_PRE_PIC_Y_OFFSET 0
+
+ #define PREVIEW_LITTLE_PIC_SIZE 40910 // 400*100+9*101+1
+ #define PREVIEW_SIZE 202720 // (PREVIEW_LITTLE_PIC_SIZE+800*200+201*9+1)
+
+ // machine parameter ui
+ #define PARA_UI_POS_X 10
+ #define PARA_UI_POS_Y 50
+
+ #define PARA_UI_SIZE_X 450
+ #define PARA_UI_SIZE_Y 40
+
+ #define PARA_UI_ARROW_V 12
+ #define PARA_UI_ITEM_TEXT_V 10
+ #define PARA_UI_ITEM_TEXT_H 10
+
+ #define PARA_UI_BACL_POS_X 400
+ #define PARA_UI_BACL_POS_Y 270
+
+ #define PARA_UI_TURN_PAGE_POS_X 320
+ #define PARA_UI_TURN_PAGE_POS_Y 270
+
+ #define PARA_UI_VALUE_SIZE_X 370
+ #define PARA_UI_VALUE_POS_X 400
+ #define PARA_UI_VALUE_V 5
+
+ #define PARA_UI_STATE_POS_X 380
+ #define PARA_UI_STATE_V 2
+
+ #define PARA_UI_VALUE_SIZE_X_2 200
+ #define PARA_UI_VALUE_POS_X_2 320
+ #define PARA_UI_VALUE_V_2 5
+
+ #define PARA_UI_VALUE_BTN_X_SIZE 70
+ #define PARA_UI_VALUE_BTN_Y_SIZE 28
+
+ #define PARA_UI_TURN_BTN_X_SIZE 70
+ #define PARA_UI_TURN_BTN_Y_SIZE 40
+
+ #define PARA_UI_BACK_BTN_X_SIZE 70
+ #define PARA_UI_BACK_BTN_Y_SIZE 40
+
+ #define QRCODE_X 20
+ #define QRCODE_Y 40
+ #define QRCODE_WIDTH 160
+
+#else // ifdef TFT35
+
+ #define TFT_WIDTH 320
+ #define TFT_HEIGHT 240
+
+#endif // ifdef TFT35
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern char public_buf_m[100];
+extern char public_buf_l[30];
+
+typedef struct {
+ uint32_t spi_flash_flag;
+ uint8_t disp_rotation_180;
+ bool multiple_language;
+ uint8_t language;
+ uint8_t leveling_mode;
+ bool from_flash_pic;
+ bool finish_power_off;
+ bool pause_reprint;
+ uint8_t wifi_mode_sel;
+ uint8_t fileSysType;
+ uint8_t wifi_type;
+ bool cloud_enable;
+ bool encoder_enable;
+ int levelingPos[5][2];
+ int filamentchange_load_length;
+ int filamentchange_load_speed;
+ int filamentchange_unload_length;
+ int filamentchange_unload_speed;
+ int filament_limit_temper;
+ float pausePosX;
+ float pausePosY;
+ float pausePosZ;
+ uint32_t curFilesize;
+} CFG_ITMES;
+
+typedef struct {
+ uint8_t curTempType:1,
+ curSprayerChoose:3,
+ stepHeat:4;
+ uint8_t leveling_first_time:1,
+ para_ui_page:1,
+ configWifi:1,
+ command_send:1,
+ filament_load_heat_flg:1,
+ filament_heat_completed_load:1,
+ filament_unload_heat_flg:1,
+ filament_heat_completed_unload:1;
+ uint8_t filament_loading_completed:1,
+ filament_unloading_completed:1,
+ filament_loading_time_flg:1,
+ filament_unloading_time_flg:1,
+ curSprayerChoose_bak:4;
+ uint8_t tmc_connect_state:1;
+ uint8_t wifi_name[32];
+ uint8_t wifi_key[64];
+ uint8_t cloud_hostUrl[96];
+ uint8_t extruStep;
+ uint8_t extruSpeed;
+ uint8_t print_state;
+ uint8_t stepPrintSpeed;
+ uint8_t waitEndMoves;
+ uint8_t dialogType;
+ uint8_t F[4];
+ uint8_t filament_rate;
+ uint16_t moveSpeed;
+ uint16_t cloud_port;
+ uint16_t moveSpeed_bak;
+ uint32_t totalSend;
+ uint32_t filament_loading_time;
+ uint32_t filament_unloading_time;
+ uint32_t filament_loading_time_cnt;
+ uint32_t filament_unloading_time_cnt;
+ float move_dist;
+ float desireSprayerTempBak;
+ float current_x_position_bak;
+ float current_y_position_bak;
+ float current_z_position_bak;
+ float current_e_position_bak;
+} UI_CFG;
+
+typedef enum {
+ MAIN_UI,
+ PRINT_READY_UI,
+ PRINT_FILE_UI,
+ PRINTING_UI,
+ MOVE_MOTOR_UI,
+ OPERATE_UI,
+ PAUSE_UI,
+ EXTRUSION_UI,
+ FAN_UI,
+ PRE_HEAT_UI,
+ CHANGE_SPEED_UI,
+ TEMP_UI,
+ SET_UI,
+ ZERO_UI,
+ BLTOUCH_UI,
+ TOUCHMI_UI,
+ SPRAYER_UI,
+ MACHINE_UI,
+ LANGUAGE_UI,
+ ABOUT_UI,
+ LOG_UI,
+ DISK_UI,
+ CALIBRATE_UI,
+ DIALOG_UI,
+ WIFI_UI,
+ MORE_UI,
+ FILETRANSFER_UI,
+ FILETRANSFERSTATE_UI,
+ PRINT_MORE_UI,
+ FILAMENTCHANGE_UI,
+ LEVELING_UI,
+ MESHLEVELING_UI,
+ BIND_UI,
+ #if HAS_BED_PROBE
+ NOZZLE_PROBE_OFFSET_UI,
+ #endif
+ TOOL_UI,
+ HARDWARE_TEST_UI,
+ WIFI_LIST_UI,
+ KEY_BOARD_UI,
+ WIFI_TIPS_UI,
+ MACHINE_PARA_UI,
+ MACHINE_SETTINGS_UI,
+ TEMPERATURE_SETTINGS_UI,
+ MOTOR_SETTINGS_UI,
+ MACHINETYPE_UI,
+ STROKE_UI,
+ HOME_DIR_UI,
+ ENDSTOP_TYPE_UI,
+ FILAMENT_SETTINGS_UI,
+ LEVELING_SETTIGNS_UI,
+ LEVELING_PARA_UI,
+ DELTA_LEVELING_PARA_UI,
+ MANUAL_LEVELING_POSIGION_UI,
+ MAXFEEDRATE_UI,
+ STEPS_UI,
+ ACCELERATION_UI,
+ JERK_UI,
+ MOTORDIR_UI,
+ HOMESPEED_UI,
+ NOZZLE_CONFIG_UI,
+ HOTBED_CONFIG_UI,
+ ADVANCED_UI,
+ DOUBLE_Z_UI,
+ ENABLE_INVERT_UI,
+ NUMBER_KEY_UI,
+ BABY_STEP_UI,
+ ERROR_MESSAGE_UI,
+ PAUSE_POS_UI,
+ TMC_CURRENT_UI,
+ TMC_MODE_UI,
+ EEPROM_SETTINGS_UI,
+ WIFI_SETTINGS_UI,
+ HOMING_SENSITIVITY_UI,
+ ENCODER_SETTINGS_UI,
+ TOUCH_CALIBRATION_UI
+} DISP_STATE;
+
+typedef struct {
+ DISP_STATE _disp_state[100];
+ int _disp_index;
+} DISP_STATE_STACK;
+
+typedef struct {
+ int16_t days;
+ uint16_t hours;
+ uint8_t minutes;
+ volatile int8_t seconds;
+ int8_t ms_10;
+ int8_t start;
+} PRINT_TIME;
+extern PRINT_TIME print_time;
+
+typedef enum {
+ PrintAcceleration,
+ RetractAcceleration,
+ TravelAcceleration,
+ XAcceleration,
+ YAcceleration,
+ ZAcceleration,
+ E0Acceleration,
+ E1Acceleration,
+
+ XMaxFeedRate,
+ YMaxFeedRate,
+ ZMaxFeedRate,
+ E0MaxFeedRate,
+ E1MaxFeedRate,
+
+ XJerk,
+ YJerk,
+ ZJerk,
+ EJerk,
+
+ Xstep,
+ Ystep,
+ Zstep,
+ E0step,
+ E1step,
+
+ Xcurrent,
+ Ycurrent,
+ Zcurrent,
+ E0current,
+ E1current,
+
+ pause_pos_x,
+ pause_pos_y,
+ pause_pos_z,
+
+ level_pos_x1,
+ level_pos_y1,
+ level_pos_x2,
+ level_pos_y2,
+ level_pos_x3,
+ level_pos_y3,
+ level_pos_x4,
+ level_pos_y4,
+ level_pos_x5,
+ level_pos_y5,
+ #if HAS_BED_PROBE
+ x_offset,
+ y_offset,
+ z_offset,
+ #endif
+ load_length,
+ load_speed,
+ unload_length,
+ unload_speed,
+ filament_temp,
+
+ x_sensitivity,
+ y_sensitivity,
+ z_sensitivity,
+ z2_sensitivity
+} num_key_value_state;
+extern num_key_value_state value;
+
+typedef enum {
+ wifiName,
+ wifiPassWord,
+ wifiConfig,
+ gcodeCommand
+} keyboard_value_state;
+extern keyboard_value_state keyboard_value;
+
+extern CFG_ITMES gCfgItems;
+extern UI_CFG uiCfg;
+extern DISP_STATE disp_state;
+extern DISP_STATE last_disp_state;
+extern DISP_STATE_STACK disp_state_stack;
+
+extern lv_style_t tft_style_scr;
+extern lv_style_t tft_style_label_pre;
+extern lv_style_t tft_style_label_rel;
+extern lv_style_t style_line;
+extern lv_style_t style_para_value_pre;
+extern lv_style_t style_para_value_rel;
+extern lv_style_t style_num_key_pre;
+extern lv_style_t style_num_key_rel;
+extern lv_style_t style_num_text;
+extern lv_style_t style_sel_text;
+extern lv_style_t style_para_value;
+extern lv_style_t style_para_back;
+extern lv_style_t lv_bar_style_indic;
+extern lv_style_t style_btn_pr;
+extern lv_style_t style_btn_rel;
+
+extern lv_point_t line_points[4][2];
+
+extern void gCfgItems_init();
+extern void ui_cfg_init();
+extern void tft_style_init();
+extern char *creat_title_text(void);
+extern void preview_gcode_prehandle(char *path);
+extern void update_spi_flash();
+extern void update_gcode_command(int addr,uint8_t *s);
+extern void get_gcode_command(int addr,uint8_t *d);
+#if HAS_GCODE_PREVIEW
+ extern void disp_pre_gcode(int xpos_pixel, int ypos_pixel);
+#endif
+extern void GUI_RefreshPage();
+extern void lv_clear_cur_ui();
+extern void lv_draw_return_ui();
+extern void sd_detection();
+extern void gCfg_to_spiFlah();
+extern void print_time_count();
+
+extern void LV_TASK_HANDLER();
+extern void lv_ex_line(lv_obj_t *line, lv_point_t *points);
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
+
+// Set the same image for both Released and Pressed
+void lv_imgbtn_set_src_both(lv_obj_t *imgbtn, const void *src);
+
+// Set label styles for Released and Pressed
+void lv_imgbtn_use_label_style(lv_obj_t *imgbtn);
+
+// Set label styles for Released and Pressed
+void lv_btn_use_label_style(lv_obj_t *btn);
+
+// Set the same style for both Released and Pressed
+void lv_btn_set_style_both(lv_obj_t *btn, lv_style_t *style);
+
+// Create a screen
+lv_obj_t* lv_screen_create(DISP_STATE newScreenType, const char* title = nullptr);
+
+// Create an empty label
+lv_obj_t* lv_label_create_empty(lv_obj_t *par);
+
+// Create a label with style and text
+lv_obj_t* lv_label_create(lv_obj_t *par, const char *text);
+
+// Create a label with style, position, and text
+lv_obj_t* lv_label_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, const char *text);
+
+// Create a button with callback, ID, and Style.
+lv_obj_t* lv_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id, lv_style_t *style=&style_para_value);
+
+// Create a button with callback and ID, with label style.
+lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id=0);
+
+// Create a button with callback and ID, with button style.
+lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id=0);
+
+// Create a button with position, size, callback, ID, and style.
+lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id, lv_style_t *style);
+
+// Create a button with position, size, callback, and ID. Style set to style_para_value.
+lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0);
+
+// Create a button with position, size, callback, and ID, with label style.
+lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0);
+
+// Create a button with position, size, callback, and ID, with button style.
+lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0);
+
+// Create a button with callback and ID. Style set to style_para_back.
+lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_event_cb_t cb, const int id=0);
+
+// Create a button with position, size, callback, and ID. Style set to style_para_back.
+lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0);
+
+// Create an image button with image, callback, and ID. Use label style.
+lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_event_cb_t cb, const int id=0);
+
+// Create an image button with image, position, callback, and ID. Use label style.
+lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id=0);
+
+// Create a big image button with a label, follow the LVGL UI standard.
+lv_obj_t* lv_big_button_create(lv_obj_t *par, const char *img, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, bool centerLabel = false);
+
+// Create a menu item, follow the LVGL UI standard.
+lv_obj_t* lv_screen_menu_item(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, bool drawArrow = true);
+
+lv_obj_t* lv_screen_menu_item_onoff(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const bool curValue);
+
+void lv_screen_menu_item_1_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue);
+void lv_screen_menu_item_2_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue, const int idEdit2, const char *editValue2);
+void lv_screen_menu_item_onoff_update(lv_obj_t *btn, const bool curValue);
+void lv_screen_menu_item_turn_page(lv_obj_t *par, const char *text, lv_event_cb_t cb, const int id);
+void lv_screen_menu_item_return(lv_obj_t *par, lv_event_cb_t cb, const int id);
+
+#define _DIA_1(T) (uiCfg.dialogType == DIALOG_##T)
+#define DIALOG_IS(V...) DO(DIA,||,V)
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.cpp
new file mode 100644
index 0000000..416905e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.cpp
@@ -0,0 +1,166 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include <lv_conf.h>
+#include "tft_lvgl_configuration.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+#include "draw_ui.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr, *wifi_name_text, *wifi_key_text, *wifi_state_text, *wifi_ip_text;
+
+enum {
+ ID_W_RETURN = 1,
+ ID_W_CLOUD,
+ ID_W_RECONNECT
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ lv_clear_cur_ui();
+ switch (obj->mks_obj_id) {
+ case ID_W_RETURN:
+ lv_draw_set();
+ break;
+ case ID_W_CLOUD:
+ lv_draw_cloud_bind();
+ break;
+ #if ENABLED(MKS_WIFI_MODULE)
+ case ID_W_RECONNECT: {
+ uint8_t cmd_wifi_list[] = { 0xA5, 0x07, 0x00, 0x00, 0xFC };
+ raw_send_to_wifi(cmd_wifi_list, COUNT(cmd_wifi_list));
+ lv_draw_wifi_list();
+ } break;
+ #endif
+ }
+}
+
+void lv_draw_wifi(void) {
+ scr = lv_screen_create(WIFI_UI);
+
+ lv_obj_t *buttonReconnect = nullptr, *label_Reconnect = nullptr;
+ lv_obj_t *buttonCloud = nullptr, *label_Cloud = nullptr;
+
+ const bool enc_ena = TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable);
+
+ if (gCfgItems.wifi_mode_sel == STA_MODEL) {
+
+ if (gCfgItems.cloud_enable)
+ buttonCloud = lv_imgbtn_create(scr, "F:/bmp_cloud.bin", BTN_X_PIXEL+INTERVAL_V*2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_CLOUD);
+
+ buttonReconnect = lv_imgbtn_create(scr, "F:/bmp_wifi.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_RECONNECT);
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.cloud_enable) lv_group_add_obj(g, buttonCloud);
+ if (enc_ena) lv_group_add_obj(g, buttonReconnect);
+ #endif
+
+ label_Reconnect = lv_label_create_empty(buttonReconnect);
+ if (gCfgItems.cloud_enable) label_Cloud = lv_label_create_empty(buttonCloud);
+ }
+
+ // Create an Image button
+ lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_RETURN);
+ if (enc_ena) lv_group_add_obj(g, buttonBack);
+ lv_obj_t *label_Back = lv_label_create_empty(buttonBack);
+
+ if (gCfgItems.multiple_language) {
+ if (gCfgItems.wifi_mode_sel == STA_MODEL) {
+ if (gCfgItems.cloud_enable) {
+ lv_label_set_text(label_Cloud, wifi_menu.cloud);
+ lv_obj_align(label_Cloud, buttonCloud, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ lv_label_set_text(label_Reconnect, wifi_menu.reconnect);
+ lv_obj_align(label_Reconnect, buttonReconnect, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+ lv_label_set_text(label_Back, common_menu.text_back);
+ lv_obj_align(label_Back, buttonBack, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET);
+ }
+
+ wifi_ip_text = lv_label_create_empty(scr);
+ lv_obj_set_style(wifi_ip_text, &tft_style_label_rel);
+ wifi_name_text = lv_label_create_empty(scr);
+ lv_obj_set_style(wifi_name_text, &tft_style_label_rel);
+ wifi_key_text = lv_label_create_empty(scr);
+ lv_obj_set_style(wifi_key_text, &tft_style_label_rel);
+ wifi_state_text = lv_label_create_empty(scr);
+ lv_obj_set_style(wifi_state_text, &tft_style_label_rel);
+
+ disp_wifi_state();
+}
+
+void disp_wifi_state() {
+ strcpy(public_buf_m, wifi_menu.ip);
+ strcat(public_buf_m, ipPara.ip_addr);
+ lv_label_set_text(wifi_ip_text, public_buf_m);
+ lv_obj_align(wifi_ip_text, nullptr, LV_ALIGN_CENTER, 0, -100);
+
+ strcpy(public_buf_m, wifi_menu.wifi);
+ strcat(public_buf_m, wifiPara.ap_name);
+ lv_label_set_text(wifi_name_text, public_buf_m);
+ lv_obj_align(wifi_name_text, nullptr, LV_ALIGN_CENTER, 0, -70);
+
+ if (wifiPara.mode == AP_MODEL) {
+ strcpy(public_buf_m, wifi_menu.key);
+ strcat(public_buf_m, wifiPara.keyCode);
+ lv_label_set_text(wifi_key_text, public_buf_m);
+ lv_obj_align(wifi_key_text, nullptr, LV_ALIGN_CENTER, 0, -40);
+
+ strcpy(public_buf_m, wifi_menu.state_ap);
+ if (wifi_link_state == WIFI_CONNECTED)
+ strcat(public_buf_m, wifi_menu.connected);
+ else if (wifi_link_state == WIFI_NOT_CONFIG)
+ strcat(public_buf_m, wifi_menu.disconnected);
+ else
+ strcat(public_buf_m, wifi_menu.exception);
+ lv_label_set_text(wifi_state_text, public_buf_m);
+ lv_obj_align(wifi_state_text, nullptr, LV_ALIGN_CENTER, 0, -10);
+ }
+ else {
+ strcpy(public_buf_m, wifi_menu.state_sta);
+ if (wifi_link_state == WIFI_CONNECTED)
+ strcat(public_buf_m, wifi_menu.connected);
+ else if (wifi_link_state == WIFI_NOT_CONFIG)
+ strcat(public_buf_m, wifi_menu.disconnected);
+ else
+ strcat(public_buf_m, wifi_menu.exception);
+ lv_label_set_text(wifi_state_text, public_buf_m);
+ lv_obj_align(wifi_state_text, nullptr, LV_ALIGN_CENTER, 0, -40);
+
+ lv_label_set_text(wifi_key_text, "");
+ lv_obj_align(wifi_key_text, nullptr, LV_ALIGN_CENTER, 0, -10);
+ }
+}
+
+void lv_clear_wifi() {
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable))
+ lv_group_remove_all_objs(g);
+ lv_obj_del(scr);
+}
+
+#endif // MKS_WIFI_MODULE
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.h
new file mode 100644
index 0000000..966a84d
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.h
@@ -0,0 +1,38 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+
+extern void lv_draw_wifi(void);
+extern void lv_clear_wifi();
+extern void disp_wifi_state();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
+
+
+
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.cpp
new file mode 100644
index 0000000..b0f3848
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.cpp
@@ -0,0 +1,177 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include <lv_conf.h>
+#include "tft_lvgl_configuration.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+#include "draw_ui.h"
+
+#define NAME_BTN_X 330
+#define NAME_BTN_Y 48
+
+#define MARK_BTN_X 0
+#define MARK_BTN_Y 68
+
+WIFI_LIST wifi_list;
+list_menu_def list_menu;
+
+extern lv_group_t *g;
+static lv_obj_t *scr;
+static lv_obj_t *buttonWifiN[NUMBER_OF_PAGE];
+static lv_obj_t *labelWifiText[NUMBER_OF_PAGE];
+static lv_obj_t *labelPageText;
+
+#define ID_WL_RETURN 11
+#define ID_WL_DOWN 12
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+
+ if (obj->mks_obj_id == ID_WL_RETURN) {
+ lv_clear_cur_ui();
+ lv_draw_set();
+ }
+ else if (obj->mks_obj_id == ID_WL_DOWN) {
+ if (wifi_list.getNameNum > 0) {
+ if ((wifi_list.nameIndex + NUMBER_OF_PAGE) >= wifi_list.getNameNum) {
+ wifi_list.nameIndex = 0;
+ wifi_list.currentWifipage = 1;
+ }
+ else {
+ wifi_list.nameIndex += NUMBER_OF_PAGE;
+ wifi_list.currentWifipage++;
+ }
+ disp_wifi_list();
+ }
+ }
+ else {
+ for (uint8_t i = 0; i < NUMBER_OF_PAGE; i++) {
+ if (obj->mks_obj_id == i + 1) {
+ if (wifi_list.getNameNum != 0) {
+ const bool do_wifi = wifi_link_state == WIFI_CONNECTED && strcmp((const char *)wifi_list.wifiConnectedName, (const char *)wifi_list.wifiName[wifi_list.nameIndex + i]) == 0;
+ wifi_list.nameIndex += i;
+ last_disp_state = WIFI_LIST_UI;
+ lv_clear_wifi_list();
+ if (do_wifi)
+ lv_draw_wifi();
+ else {
+ keyboard_value = wifiConfig;
+ lv_draw_keyboard();
+ }
+ }
+ }
+ }
+ }
+}
+
+void lv_draw_wifi_list(void) {
+ scr = lv_screen_create(WIFI_LIST_UI);
+
+ lv_obj_t *buttonDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL + INTERVAL_H, event_handler, ID_WL_DOWN);
+ lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + (OTHER_BTN_YPIEL + INTERVAL_H) * 2, event_handler, ID_WL_RETURN);
+
+ for (uint8_t i = 0; i < NUMBER_OF_PAGE; i++) {
+ buttonWifiN[i] = lv_label_btn_create(scr, 0, NAME_BTN_Y * i + 10 + titleHeight, NAME_BTN_X, NAME_BTN_Y, event_handler, i + 1);
+ labelWifiText[i] = lv_label_create_empty(buttonWifiN[i]);
+ #if HAS_ROTARY_ENCODER
+ uint8_t j = 0;
+ if (gCfgItems.encoder_enable) {
+ j = wifi_list.nameIndex + i;
+ if (j < wifi_list.getNameNum) lv_group_add_obj(g, buttonWifiN[i]);
+ }
+ #endif
+ }
+
+ labelPageText = lv_label_create_empty(scr);
+ lv_obj_set_style(labelPageText, &tft_style_label_rel);
+
+ wifi_list.nameIndex = 0;
+ wifi_list.currentWifipage = 1;
+
+ if (wifi_link_state == WIFI_CONNECTED && wifiPara.mode == STA_MODEL) {
+ ZERO(wifi_list.wifiConnectedName);
+ memcpy(wifi_list.wifiConnectedName, wifiPara.ap_name, sizeof(wifi_list.wifiConnectedName));
+ }
+
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) {
+ lv_group_add_obj(g, buttonDown);
+ lv_group_add_obj(g, buttonBack);
+ }
+ #else
+ UNUSED(buttonDown);
+ UNUSED(buttonBack);
+ #endif
+
+ disp_wifi_list();
+}
+
+void disp_wifi_list(void) {
+ int8_t tmpStr[WIFI_NAME_BUFFER_SIZE] = { 0 };
+ uint8_t i, j;
+
+ sprintf((char *)tmpStr, list_menu.file_pages, wifi_list.currentWifipage, wifi_list.getPage);
+ lv_label_set_text(labelPageText, (const char *)tmpStr);
+ lv_obj_align(labelPageText, nullptr, LV_ALIGN_CENTER, 50, -100);
+
+ for (i = 0; i < NUMBER_OF_PAGE; i++) {
+ ZERO(tmpStr);
+
+ j = wifi_list.nameIndex + i;
+ if (j >= wifi_list.getNameNum) {
+ lv_label_set_text(labelWifiText[i], (const char *)tmpStr);
+ lv_obj_align(labelWifiText[i], buttonWifiN[i], LV_ALIGN_IN_LEFT_MID, 20, 0);
+ }
+ else {
+ lv_label_set_text(labelWifiText[i], (char const *)wifi_list.wifiName[j]);
+ lv_obj_align(labelWifiText[i], buttonWifiN[i], LV_ALIGN_IN_LEFT_MID, 20, 0);
+
+ const bool btext = (wifi_link_state == WIFI_CONNECTED && strcmp((const char *)wifi_list.wifiConnectedName, (const char *)wifi_list.wifiName[j]) == 0);
+ lv_btn_set_style(buttonWifiN[i], LV_BTN_STYLE_REL, btext ? &style_sel_text : &tft_style_label_rel);
+ }
+ }
+}
+
+void wifi_scan_handle() {
+ if (!DIALOG_IS(WIFI_ENABLE_TIPS) || uiCfg.command_send != 1) return;
+ last_disp_state = DIALOG_UI;
+ lv_clear_dialog();
+ if (wifi_link_state == WIFI_CONNECTED && wifiPara.mode != AP_MODEL)
+ lv_draw_wifi();
+ else
+ lv_draw_wifi_list();
+}
+
+void lv_clear_wifi_list() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // MKS_WIFI_MODULE
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.h
new file mode 100644
index 0000000..e2d9275
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.h
@@ -0,0 +1,76 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+extern void lv_draw_wifi_list();
+extern void lv_clear_wifi_list();
+extern void disp_wifi_list(void);
+extern void cutWifiName(char *name, int len,char *outStr);
+extern void wifi_scan_handle();
+
+#define NUMBER_OF_PAGE 5
+
+#define WIFI_TOTAL_NUMBER 20
+#define WIFI_NAME_BUFFER_SIZE 33
+
+typedef struct {
+ int8_t getNameNum;
+ int8_t nameIndex;
+ int8_t currentWifipage;
+ int8_t getPage;
+ int8_t RSSI[WIFI_TOTAL_NUMBER];
+ uint8_t wifiName[WIFI_TOTAL_NUMBER][WIFI_NAME_BUFFER_SIZE];
+ uint8_t wifiConnectedName[WIFI_NAME_BUFFER_SIZE];
+} WIFI_LIST;
+extern WIFI_LIST wifi_list;
+
+typedef struct list_menu_disp {
+ const char *title;
+ const char *file_pages;
+} list_menu_def;
+extern list_menu_def list_menu;
+
+typedef struct keyboard_menu_disp {
+ const char *title;
+ const char *apply;
+ const char *password;
+ const char *letter;
+ const char *digital;
+ const char *symbol;
+ const char *space;
+} keyboard_menu_def;
+extern keyboard_menu_def keyboard_menu;
+
+typedef struct tips_menu_disp {
+ const char *joining;
+ const char *failedJoin;
+ const char *wifiConected;
+} tips_menu_def;
+extern tips_menu_def tips_menu;
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.cpp
new file mode 100644
index 0000000..7c1b0af
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.cpp
@@ -0,0 +1,141 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include <lv_conf.h>
+#include "tft_lvgl_configuration.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+#include "draw_ui.h"
+
+extern lv_group_t *g;
+static lv_obj_t *scr, *labelModelAP = nullptr, *buttonModelAP = nullptr, *labelModelSTA = nullptr, *buttonModelSTA = nullptr, *btnCloudState = nullptr;
+
+enum {
+ ID_WIFI_RETURN = 1,
+ ID_WIFI_AP,
+ ID_WIFI_STA,
+ ID_WIFI_NAME,
+ ID_WIFI_PASSWORD,
+ ID_WIFI_CLOUD,
+ ID_WIFI_CONFIG
+};
+
+static void event_handler(lv_obj_t *obj, lv_event_t event) {
+ if (event != LV_EVENT_RELEASED) return;
+ switch (obj->mks_obj_id) {
+ case ID_WIFI_RETURN:
+ lv_clear_wifi_settings();
+ lv_draw_return_ui();
+ break;
+ case ID_WIFI_AP:
+ if (gCfgItems.wifi_mode_sel == AP_MODEL) return;
+ gCfgItems.wifi_mode_sel = AP_MODEL;
+ lv_btn_set_style_both(buttonModelAP, &style_para_back);
+ lv_btn_set_style_both(buttonModelSTA, &style_para_value);
+ update_spi_flash();
+ break;
+ case ID_WIFI_STA:
+ if (gCfgItems.wifi_mode_sel == STA_MODEL) return;
+ gCfgItems.wifi_mode_sel = STA_MODEL;
+ lv_btn_set_style_both(buttonModelSTA, &style_para_back);
+ lv_btn_set_style_both(buttonModelAP, &style_para_value);
+ update_spi_flash();
+ break;
+ case ID_WIFI_NAME:
+ keyboard_value = wifiName;
+ lv_clear_wifi_settings();
+ lv_draw_keyboard();
+ break;
+ case ID_WIFI_PASSWORD:
+ keyboard_value = wifiPassWord;
+ lv_clear_wifi_settings();
+ lv_draw_keyboard();
+ break;
+ case ID_WIFI_CLOUD:
+ gCfgItems.cloud_enable ^= true;
+ lv_screen_menu_item_onoff_update(btnCloudState, gCfgItems.cloud_enable);
+ update_spi_flash();
+ break;
+ case ID_WIFI_CONFIG:
+ lv_clear_wifi_settings();
+ lv_draw_dialog(DIALOG_WIFI_CONFIG_TIPS);
+ break;
+ }
+}
+
+void lv_draw_wifi_settings(void) {
+ scr = lv_screen_create(WIFI_SETTINGS_UI, machine_menu.WifiConfTitle);
+
+ lv_label_create(scr, PARA_UI_POS_X + PARA_UI_ITEM_TEXT_H, PARA_UI_POS_Y + 10, machine_menu.wifiMode);
+ buttonModelAP = lv_btn_create(scr, nullptr);
+ lv_obj_set_pos(buttonModelAP, PARA_UI_VALUE_POS_X_2, PARA_UI_POS_Y + PARA_UI_VALUE_V_2);
+ lv_obj_set_size(buttonModelAP, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE);
+ lv_obj_set_event_cb_mks(buttonModelAP, event_handler, ID_WIFI_AP, "", 0);
+ lv_btn_use_label_style(buttonModelAP);
+ lv_btn_set_layout(buttonModelAP, LV_LAYOUT_OFF);
+ lv_btn_set_style_both(buttonModelAP, gCfgItems.wifi_mode_sel == AP_MODEL ? &style_para_back : &style_para_value);
+ labelModelAP = lv_label_create_empty(buttonModelAP);
+ lv_label_set_text(labelModelAP, WIFI_AP_TEXT);
+ lv_obj_align(labelModelAP, buttonModelAP, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, buttonModelAP);
+
+ buttonModelSTA = lv_btn_create(scr, nullptr);
+ lv_obj_set_pos(buttonModelSTA, PARA_UI_VALUE_POS_X, PARA_UI_POS_Y + PARA_UI_VALUE_V);
+ lv_obj_set_size(buttonModelSTA, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE);
+ lv_obj_set_event_cb_mks(buttonModelSTA, event_handler, ID_WIFI_STA, "", 0);
+ lv_btn_use_label_style(buttonModelSTA);
+ lv_btn_set_layout(buttonModelSTA, LV_LAYOUT_OFF);
+ labelModelSTA = lv_label_create_empty(buttonModelSTA);
+ lv_btn_set_style_both(buttonModelSTA, gCfgItems.wifi_mode_sel == STA_MODEL ? &style_para_back : &style_para_value);
+ lv_label_set_text(labelModelSTA, WIFI_STA_TEXT);
+ lv_obj_align(labelModelSTA, buttonModelSTA, LV_ALIGN_CENTER, 0, 0);
+ if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, buttonModelSTA);
+
+ lv_obj_t *line1 = lv_line_create(scr, nullptr);
+ lv_ex_line(line1, line_points[0]);
+
+ strcpy_P(public_buf_m, PSTR(machine_menu.wifiName));
+ strcat_P(public_buf_m, PSTR((const char *)uiCfg.wifi_name));
+ lv_screen_menu_item_1_edit(scr, public_buf_m, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_WIFI_NAME, 1, machine_menu.wifiEdit);
+
+ strcpy_P(public_buf_m, PSTR(machine_menu.wifiPassWord));
+ strcat_P(public_buf_m, PSTR((const char *)uiCfg.wifi_key));
+ lv_screen_menu_item_1_edit(scr, public_buf_m, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_WIFI_PASSWORD, 2, machine_menu.wifiEdit);
+
+ btnCloudState = lv_screen_menu_item_onoff(scr, machine_menu.wifiCloud, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_WIFI_CLOUD, 3, gCfgItems.cloud_enable);
+ lv_screen_menu_item_turn_page(scr, machine_menu.wifiConfig, event_handler, ID_WIFI_CONFIG);
+ lv_screen_menu_item_return(scr, event_handler, ID_WIFI_RETURN);
+}
+
+void lv_clear_wifi_settings() {
+ #if HAS_ROTARY_ENCODER
+ if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g);
+ #endif
+ lv_obj_del(scr);
+}
+
+#endif // MKS_WIFI_MODULE
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.h
new file mode 100644
index 0000000..c0d6e0c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.h
@@ -0,0 +1,36 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+#define WIFI_AP_TEXT "AP"
+#define WIFI_STA_TEXT "STA"
+
+extern void lv_draw_wifi_settings(void);
+extern void lv_clear_wifi_settings();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.cpp
new file mode 100644
index 0000000..7428d36
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.cpp
@@ -0,0 +1,68 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include <lv_conf.h>
+#include "tft_lvgl_configuration.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+#include "draw_ui.h"
+
+static lv_obj_t *scr;
+
+TIPS_TYPE wifi_tips_type;
+TIPS_DISP tips_disp;
+tips_menu_def tips_menu;
+
+void lv_draw_wifi_tips(void) {
+ static lv_obj_t *text_tips,*wifi_name;
+
+ scr = lv_screen_create(WIFI_TIPS_UI, "");
+
+ wifi_name = lv_label_create(scr, (const char *)wifi_list.wifiName[wifi_list.nameIndex]);
+ lv_obj_align(wifi_name, nullptr, LV_ALIGN_CENTER, 0, -20);
+
+ text_tips = lv_label_create_empty(scr);
+ if (wifi_tips_type == TIPS_TYPE_JOINING) {
+ lv_label_set_text(text_tips, tips_menu.joining);
+ lv_obj_align(text_tips, nullptr, LV_ALIGN_CENTER, 0, -60);
+ }
+ else if (wifi_tips_type == TIPS_TYPE_TAILED_JOIN) {
+ lv_label_set_text(text_tips, tips_menu.failedJoin);
+ lv_obj_align(text_tips, nullptr, LV_ALIGN_CENTER, 0, -60);
+ }
+ else if (wifi_tips_type == TIPS_TYPE_WIFI_CONECTED) {
+ lv_label_set_text(text_tips, tips_menu.wifiConected);
+ lv_obj_align(text_tips, nullptr, LV_ALIGN_CENTER, 0, -60);
+ }
+
+ tips_disp.timer = TIPS_TIMER_START;
+ tips_disp.timer_count = 0;
+}
+
+void lv_clear_wifi_tips() { lv_obj_del(scr); }
+
+#endif // MKS_WIFI_MODULE
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.h
new file mode 100644
index 0000000..4f81f00
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.h
@@ -0,0 +1,51 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+
+extern void lv_draw_wifi_tips(void);
+extern void lv_clear_wifi_tips();
+
+typedef enum {
+ TIPS_TYPE_JOINING,
+ TIPS_TYPE_TAILED_JOIN,
+ TIPS_TYPE_WIFI_CONECTED
+} TIPS_TYPE;
+extern TIPS_TYPE wifi_tips_type;
+
+typedef struct {
+ unsigned char timer;
+ unsigned int timer_count;
+} TIPS_DISP;
+extern TIPS_DISP tips_disp;
+
+#define TIPS_TIMER_START 1
+#define TIPS_TIMER_STOP 0
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
+
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/gb2312_puhui16.cpp b/Marlin/src/lcd/extui/lib/mks_ui/gb2312_puhui16.cpp
new file mode 100644
index 0000000..f3585cc
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/gb2312_puhui16.cpp
@@ -0,0 +1,105 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "pic_manager.h"
+#include <lvgl.h>
+
+#include "../../../../inc/MarlinConfig.h"
+
+#if HAS_SPI_FLASH_FONT
+
+typedef struct {
+ uint16_t min;
+ uint16_t max;
+ uint8_t bpp;
+ uint8_t reserved[3];
+} x_header_t;
+
+typedef struct {
+ uint32_t pos;
+} x_table_t;
+
+typedef struct {
+ uint8_t adv_w;
+ uint8_t box_w;
+} glyph_dsc_t;
+
+static x_header_t __g_xbf_hd = { .min = 0, .max = 0, .bpp = 0 };
+static uint8_t __g_font_buf[63];
+
+static uint8_t *__user_font_getdata(int offset, int size) {
+ get_spi_flash_data((char *)__g_font_buf, offset, size);
+ return __g_font_buf;
+}
+
+static const uint8_t * __user_font_get_bitmap(const lv_font_t * font, uint32_t unicode_letter) {
+ if (__g_xbf_hd.max == 0) {
+ uint8_t *p = __user_font_getdata(0, sizeof(x_header_t));
+ memcpy(&__g_xbf_hd, p, sizeof(x_header_t));
+ }
+ if (unicode_letter > __g_xbf_hd.max || unicode_letter < __g_xbf_hd.min)
+ return nullptr;
+ uint32_t unicode_offset = sizeof(x_header_t) + (unicode_letter - __g_xbf_hd.min) * 4;
+ uint32_t *p_pos = (uint32_t *)__user_font_getdata(unicode_offset, 4);
+ if (p_pos[0] != 0) {
+ uint32_t pos = p_pos[0];
+ __user_font_getdata(pos, 2);
+ return __user_font_getdata(pos + 2, sizeof(__g_font_buf));
+ }
+ return nullptr;
+}
+
+static bool __user_font_get_glyph_dsc(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) {
+ if (__g_xbf_hd.max == 0) {
+ uint8_t *p = __user_font_getdata(0, sizeof(x_header_t));
+ memcpy(&__g_xbf_hd, p, sizeof(x_header_t));
+ }
+ if (unicode_letter > __g_xbf_hd.max || unicode_letter < __g_xbf_hd.min)
+ return false;
+ uint32_t unicode_offset = sizeof(x_header_t) + (unicode_letter - __g_xbf_hd.min) * 4;
+ uint32_t *p_pos = (uint32_t *)__user_font_getdata(unicode_offset, 4);
+ if (p_pos[0] != 0) {
+ glyph_dsc_t * gdsc = (glyph_dsc_t*)__user_font_getdata(p_pos[0], 2);
+ dsc_out->adv_w = gdsc->adv_w;
+ dsc_out->box_h = font->line_height;
+ dsc_out->box_w = gdsc->box_w;
+ dsc_out->ofs_x = 0;
+ dsc_out->ofs_y = 0;
+ dsc_out->bpp = __g_xbf_hd.bpp;
+ return true;
+ }
+ return false;
+}
+
+lv_font_t gb2312_puhui32;
+void init_gb2312_font() {
+ gb2312_puhui32.get_glyph_bitmap = __user_font_get_bitmap;
+ gb2312_puhui32.get_glyph_dsc = __user_font_get_glyph_dsc;
+ gb2312_puhui32.line_height = 21;
+ gb2312_puhui32.base_line = 0;
+}
+
+#endif // HAS_SPI_FLASH_FONT
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/irq_overrid.cpp b/Marlin/src/lcd/extui/lib/mks_ui/irq_overrid.cpp
new file mode 100644
index 0000000..a26116a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/irq_overrid.cpp
@@ -0,0 +1,63 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "tft_lvgl_configuration.h"
+
+#ifdef __STM32F1__
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+ #include "draw_ui.h"
+ #include "wifiSerial.h"
+
+ #include <libmaple/libmaple.h>
+ #include <libmaple/gpio.h>
+ #include <libmaple/timer.h>
+ #include <libmaple/usart.h>
+ #include <libmaple/ring_buffer.h>
+
+ #include "../../../../inc/MarlinConfig.h"
+
+ #ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+ #endif
+
+ #define WIFI_IO1_SET() WRITE(WIFI_IO1_PIN, HIGH);
+ #define WIFI_IO1_RESET() WRITE(WIFI_IO1_PIN, LOW);
+
+ void __irq_usart1(void) {
+ if ((USART1_BASE->CR1 & USART_CR1_RXNEIE) && (USART1_BASE->SR & USART_SR_RXNE))
+ WRITE(WIFI_IO1_PIN, HIGH);
+
+ WIFISERIAL.wifi_usart_irq(USART1_BASE);
+ }
+
+ #ifdef __cplusplus
+ } /* C-declarations for C++ */
+ #endif
+
+#endif // MKS_WIFI_MODULE
+#endif // __STM32F1__
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
new file mode 100644
index 0000000..4a6a5ce
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp
@@ -0,0 +1,655 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "SPI_TFT.h"
+
+#include "tft_lvgl_configuration.h"
+#include "draw_ready_print.h"
+#include "mks_hardware_test.h"
+#include "draw_ui.h"
+#include "pic_manager.h"
+#include <lvgl.h>
+
+#include "../../../../MarlinCore.h"
+#include "../../../../module/temperature.h"
+#include "../../../../sd/cardreader.h"
+
+bool pw_det_sta, pw_off_sta, mt_det_sta, mt_det3_sta;
+#if PIN_EXISTS(MT_DET_2)
+ bool mt_det2_sta;
+#endif
+bool endstopx1_sta, endstopx2_sta, endstopy1_sta, endstopy2_sta, endstopz1_sta, endstopz2_sta;
+void test_gpio_readlevel_L() {
+ #if ENABLED(MKS_TEST)
+ volatile uint32_t itest;
+ WRITE(WIFI_IO0_PIN, HIGH);
+ itest = 10000;
+ while (itest--);
+ pw_det_sta = !READ(MKS_TEST_POWER_LOSS_PIN);
+ pw_off_sta = !READ(MKS_TEST_PS_ON_PIN);
+ mt_det_sta = !READ(MT_DET_1_PIN);
+ #if PIN_EXISTS(MT_DET_2)
+ mt_det2_sta = !READ(MT_DET_2_PIN);
+ #endif
+ endstopx1_sta = !READ(X_MIN_PIN);
+ endstopy1_sta = !READ(Y_MIN_PIN);
+ endstopz1_sta = !READ(Z_MIN_PIN);
+ endstopz2_sta = !READ(Z_MAX_PIN);
+ #endif
+}
+
+void test_gpio_readlevel_H() {
+ #if ENABLED(MKS_TEST)
+ volatile uint32_t itest;
+ WRITE(WIFI_IO0_PIN, LOW);
+ itest = 10000;
+ while (itest--);
+ pw_det_sta = READ(MKS_TEST_POWER_LOSS_PIN);
+ pw_off_sta = READ(MKS_TEST_PS_ON_PIN);
+ mt_det_sta = READ(MT_DET_1_PIN);
+ #if PIN_EXISTS(MT_DET_2)
+ mt_det2_sta = READ(MT_DET_2_PIN);
+ #endif
+ endstopx1_sta = READ(X_MIN_PIN);
+ endstopy1_sta = READ(Y_MIN_PIN);
+ endstopz1_sta = READ(Z_MIN_PIN);
+ endstopz2_sta = READ(Z_MAX_PIN);
+ #endif
+}
+
+void init_test_gpio() {
+ #ifdef MKS_TEST
+ SET_INPUT_PULLUP(X_MIN_PIN);
+ SET_INPUT_PULLUP(Y_MIN_PIN);
+ SET_INPUT_PULLUP(Z_MIN_PIN);
+ SET_INPUT_PULLUP(Z_MAX_PIN);
+
+ SET_OUTPUT(WIFI_IO0_PIN);
+
+ SET_INPUT_PULLUP(MT_DET_1_PIN);
+ #if PIN_EXISTS(MT_DET_2)
+ SET_INPUT_PULLUP(MT_DET_2_PIN);
+ #endif
+
+ SET_INPUT_PULLUP(MKS_TEST_POWER_LOSS_PIN);
+ SET_INPUT_PULLUP(MKS_TEST_PS_ON_PIN);
+
+ SET_INPUT_PULLUP(SERVO0_PIN);
+
+ SET_OUTPUT(X_ENABLE_PIN);
+ SET_OUTPUT(Y_ENABLE_PIN);
+ SET_OUTPUT(Z_ENABLE_PIN);
+ SET_OUTPUT(E0_ENABLE_PIN);
+ #if !MB(MKS_ROBIN_E3P)
+ SET_OUTPUT(E1_ENABLE_PIN);
+ #endif
+
+ WRITE(X_ENABLE_PIN, LOW);
+ WRITE(Y_ENABLE_PIN, LOW);
+ WRITE(Z_ENABLE_PIN, LOW);
+ WRITE(E0_ENABLE_PIN, LOW);
+ #if !MB(MKS_ROBIN_E3P)
+ WRITE(E1_ENABLE_PIN, LOW);
+ #endif
+
+ #if MB(MKS_ROBIN_E3P)
+ SET_INPUT_PULLUP(PA1);
+ SET_INPUT_PULLUP(PA3);
+ SET_INPUT_PULLUP(PC2);
+ SET_INPUT_PULLUP(PD8);
+ SET_INPUT_PULLUP(PE5);
+ SET_INPUT_PULLUP(PE6);
+ SET_INPUT_PULLUP(PE7);
+ #endif
+ #endif
+}
+
+void mks_test_beeper() {
+ #ifdef MKS_TEST
+ WRITE(BEEPER_PIN, HIGH);
+ delay(100);
+ WRITE(BEEPER_PIN, LOW);
+ delay(100);
+ #endif
+}
+
+void mks_gpio_test() {
+ #if ENABLED(MKS_TEST)
+ init_test_gpio();
+
+ test_gpio_readlevel_L();
+ test_gpio_readlevel_H();
+ test_gpio_readlevel_L();
+ if ((pw_det_sta == true)
+ && (pw_off_sta == true)
+ && (mt_det_sta == true)
+ #if PIN_EXISTS(MT_DET_2)
+ && (mt_det2_sta == true)
+ #endif
+ #if MB(MKS_ROBIN_E3P)
+ && (READ(PA1) == false)
+ && (READ(PA3) == false)
+ && (READ(PC2) == false)
+ && (READ(PD8) == false)
+ && (READ(PE5) == false)
+ && (READ(PE6) == false)
+ && (READ(PE7) == false)
+ #endif
+ )
+ disp_det_ok();
+ else
+ disp_det_error();
+
+ if ( (endstopx1_sta == true)
+ && (endstopy1_sta == true)
+ && (endstopz1_sta == true)
+ && (endstopz2_sta == true)
+ )
+ disp_Limit_ok();
+ else
+ disp_Limit_error();
+ #endif
+
+ if (uiCfg.tmc_connect_state) disp_tmc_ok();
+ else disp_tmc_error();
+}
+
+void mks_hardware_test() {
+ #if ENABLED(MKS_TEST)
+ if (millis() % 1000 < 500) {
+ WRITE(X_DIR_PIN, LOW);
+ WRITE(Y_DIR_PIN, LOW);
+ WRITE(Z_DIR_PIN, LOW);
+ WRITE(E0_DIR_PIN, LOW);
+ #if !MB(MKS_ROBIN_E3P)
+ WRITE(E1_DIR_PIN, LOW);
+ #endif
+ thermalManager.fan_speed[0] = 255;
+ #if PIN_EXISTS(FAN1)
+ thermalManager.fan_speed[1] = 255;
+ #endif
+ #if !MB(MKS_ROBIN_E3P)
+ WRITE(HEATER_1_PIN, HIGH); // HE1
+ #endif
+ WRITE(HEATER_0_PIN, HIGH); // HE0
+ WRITE(HEATER_BED_PIN, HIGH); // HOT-BED
+ }
+ else {
+ WRITE(X_DIR_PIN, HIGH);
+ WRITE(Y_DIR_PIN, HIGH);
+ WRITE(Z_DIR_PIN, HIGH);
+ WRITE(E0_DIR_PIN, HIGH);
+ #if !MB(MKS_ROBIN_E3P)
+ WRITE(E1_DIR_PIN, HIGH);
+ #endif
+ thermalManager.fan_speed[0] = 0;
+ #if PIN_EXISTS(FAN1)
+ thermalManager.fan_speed[1] = 0;
+ #endif
+ #if !MB(MKS_ROBIN_E3P)
+ WRITE(HEATER_1_PIN, LOW); // HE1
+ #endif
+ WRITE(HEATER_0_PIN, LOW); // HE0
+ WRITE(HEATER_BED_PIN, LOW); // HOT-BED
+ }
+
+ if ( (endstopx1_sta == 1) && (endstopx2_sta == 1)
+ && (endstopy1_sta == 1) && (endstopy2_sta == 1)
+ && (endstopz1_sta == 1) && (endstopz2_sta == 1)
+ ) {
+ // nothing here
+ }
+ else {
+ }
+
+ if (disp_state == PRINT_READY_UI) mks_disp_test();
+
+ #endif
+}
+
+static const uint16_t ASCII_Table_16x24[] PROGMEM = {
+ // Space ' '
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '!'
+ 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0000, 0x0000,
+ 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '"'
+ 0x0000, 0x0000, 0x00CC, 0x00CC, 0x00CC, 0x00CC, 0x00CC, 0x00CC,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '#'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0C60, 0x0C60,
+ 0x0C60, 0x0630, 0x0630, 0x1FFE, 0x1FFE, 0x0630, 0x0738, 0x0318,
+ 0x1FFE, 0x1FFE, 0x0318, 0x0318, 0x018C, 0x018C, 0x018C, 0x0000,
+ // '$'
+ 0x0000, 0x0080, 0x03E0, 0x0FF8, 0x0E9C, 0x1C8C, 0x188C, 0x008C,
+ 0x0098, 0x01F8, 0x07E0, 0x0E80, 0x1C80, 0x188C, 0x188C, 0x189C,
+ 0x0CB8, 0x0FF0, 0x03E0, 0x0080, 0x0080, 0x0000, 0x0000, 0x0000,
+ // '%'
+ 0x0000, 0x0000, 0x0000, 0x180E, 0x0C1B, 0x0C11, 0x0611, 0x0611,
+ 0x0311, 0x0311, 0x019B, 0x018E, 0x38C0, 0x6CC0, 0x4460, 0x4460,
+ 0x4430, 0x4430, 0x4418, 0x6C18, 0x380C, 0x0000, 0x0000, 0x0000,
+ // '&'
+ 0x0000, 0x01E0, 0x03F0, 0x0738, 0x0618, 0x0618, 0x0330, 0x01F0,
+ 0x00F0, 0x00F8, 0x319C, 0x330E, 0x1E06, 0x1C06, 0x1C06, 0x3F06,
+ 0x73FC, 0x21F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // "'"
+ 0x0000, 0x0000, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '('
+ 0x0000, 0x0200, 0x0300, 0x0180, 0x00C0, 0x00C0, 0x0060, 0x0060,
+ 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
+ 0x0060, 0x0060, 0x00C0, 0x00C0, 0x0180, 0x0300, 0x0200, 0x0000,
+ // ')'
+ 0x0000, 0x0020, 0x0060, 0x00C0, 0x0180, 0x0180, 0x0300, 0x0300,
+ 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600,
+ 0x0300, 0x0300, 0x0180, 0x0180, 0x00C0, 0x0060, 0x0020, 0x0000,
+ // '*'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00C0, 0x00C0,
+ 0x06D8, 0x07F8, 0x01E0, 0x0330, 0x0738, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '+'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x3FFC, 0x3FFC, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // ','
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0180, 0x0180, 0x0100, 0x0100, 0x0080, 0x0000, 0x0000,
+ // '-'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x07E0, 0x07E0, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '.'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '/'
+ 0x0000, 0x0C00, 0x0C00, 0x0600, 0x0600, 0x0600, 0x0300, 0x0300,
+ 0x0300, 0x0380, 0x0180, 0x0180, 0x0180, 0x00C0, 0x00C0, 0x00C0,
+ 0x0060, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '0'
+ 0x0000, 0x03E0, 0x07F0, 0x0E38, 0x0C18, 0x180C, 0x180C, 0x180C,
+ 0x180C, 0x180C, 0x180C, 0x180C, 0x180C, 0x180C, 0x0C18, 0x0E38,
+ 0x07F0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '1'
+ 0x0000, 0x0100, 0x0180, 0x01C0, 0x01F0, 0x0198, 0x0188, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '2'
+ 0x0000, 0x03E0, 0x0FF8, 0x0C18, 0x180C, 0x180C, 0x1800, 0x1800,
+ 0x0C00, 0x0600, 0x0300, 0x0180, 0x00C0, 0x0060, 0x0030, 0x0018,
+ 0x1FFC, 0x1FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '3'
+ 0x0000, 0x01E0, 0x07F8, 0x0E18, 0x0C0C, 0x0C0C, 0x0C00, 0x0600,
+ 0x03C0, 0x07C0, 0x0C00, 0x1800, 0x1800, 0x180C, 0x180C, 0x0C18,
+ 0x07F8, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '4'
+ 0x0000, 0x0C00, 0x0E00, 0x0F00, 0x0F00, 0x0D80, 0x0CC0, 0x0C60,
+ 0x0C60, 0x0C30, 0x0C18, 0x0C0C, 0x3FFC, 0x3FFC, 0x0C00, 0x0C00,
+ 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '5'
+ 0x0000, 0x0FF8, 0x0FF8, 0x0018, 0x0018, 0x000C, 0x03EC, 0x07FC,
+ 0x0E1C, 0x1C00, 0x1800, 0x1800, 0x1800, 0x180C, 0x0C1C, 0x0E18,
+ 0x07F8, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '6'
+ 0x0000, 0x07C0, 0x0FF0, 0x1C38, 0x1818, 0x0018, 0x000C, 0x03CC,
+ 0x0FEC, 0x0E3C, 0x1C1C, 0x180C, 0x180C, 0x180C, 0x1C18, 0x0E38,
+ 0x07F0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '7'
+ 0x0000, 0x1FFC, 0x1FFC, 0x0C00, 0x0600, 0x0600, 0x0300, 0x0380,
+ 0x0180, 0x01C0, 0x00C0, 0x00E0, 0x0060, 0x0060, 0x0070, 0x0030,
+ 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '8'
+ 0x0000, 0x03E0, 0x07F0, 0x0E38, 0x0C18, 0x0C18, 0x0C18, 0x0638,
+ 0x07F0, 0x07F0, 0x0C18, 0x180C, 0x180C, 0x180C, 0x180C, 0x0C38,
+ 0x0FF8, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '9'
+ 0x0000, 0x03E0, 0x07F0, 0x0E38, 0x0C1C, 0x180C, 0x180C, 0x180C,
+ 0x1C1C, 0x1E38, 0x1BF8, 0x19E0, 0x1800, 0x0C00, 0x0C00, 0x0E1C,
+ 0x07F8, 0x01F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // ':'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // ';'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0180, 0x0180, 0x0100, 0x0100, 0x0080, 0x0000, 0x0000, 0x0000,
+ // '<'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1000, 0x1C00, 0x0F80, 0x03E0, 0x00F8, 0x0018, 0x00F8, 0x03E0,
+ 0x0F80, 0x1C00, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '='
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1FF8, 0x0000, 0x0000, 0x0000, 0x1FF8, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '>'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0008, 0x0038, 0x01F0, 0x07C0, 0x1F00, 0x1800, 0x1F00, 0x07C0,
+ 0x01F0, 0x0038, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '?'
+ 0x0000, 0x03E0, 0x0FF8, 0x0C18, 0x180C, 0x180C, 0x1800, 0x0C00,
+ 0x0600, 0x0300, 0x0180, 0x00C0, 0x00C0, 0x00C0, 0x0000, 0x0000,
+ 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '@'
+ 0x0000, 0x0000, 0x07E0, 0x1818, 0x2004, 0x29C2, 0x4A22, 0x4411,
+ 0x4409, 0x4409, 0x4409, 0x2209, 0x1311, 0x0CE2, 0x4002, 0x2004,
+ 0x1818, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'A'
+ 0x0000, 0x0380, 0x0380, 0x06C0, 0x06C0, 0x06C0, 0x0C60, 0x0C60,
+ 0x1830, 0x1830, 0x1830, 0x3FF8, 0x3FF8, 0x701C, 0x600C, 0x600C,
+ 0xC006, 0xC006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'B'
+ 0x0000, 0x03FC, 0x0FFC, 0x0C0C, 0x180C, 0x180C, 0x180C, 0x0C0C,
+ 0x07FC, 0x0FFC, 0x180C, 0x300C, 0x300C, 0x300C, 0x300C, 0x180C,
+ 0x1FFC, 0x07FC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'C'
+ 0x0000, 0x07C0, 0x1FF0, 0x3838, 0x301C, 0x700C, 0x6006, 0x0006,
+ 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x6006, 0x700C, 0x301C,
+ 0x1FF0, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'D'
+ 0x0000, 0x03FE, 0x0FFE, 0x0E06, 0x1806, 0x1806, 0x3006, 0x3006,
+ 0x3006, 0x3006, 0x3006, 0x3006, 0x3006, 0x1806, 0x1806, 0x0E06,
+ 0x0FFE, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'E'
+ 0x0000, 0x3FFC, 0x3FFC, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C,
+ 0x1FFC, 0x1FFC, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C,
+ 0x3FFC, 0x3FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'F'
+ 0x0000, 0x3FF8, 0x3FF8, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
+ 0x1FF8, 0x1FF8, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
+ 0x0018, 0x0018, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'G'
+ 0x0000, 0x0FE0, 0x3FF8, 0x783C, 0x600E, 0xE006, 0xC007, 0x0003,
+ 0x0003, 0xFE03, 0xFE03, 0xC003, 0xC007, 0xC006, 0xC00E, 0xF03C,
+ 0x3FF8, 0x0FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'H'
+ 0x0000, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C,
+ 0x3FFC, 0x3FFC, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C,
+ 0x300C, 0x300C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'I'
+ 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'J'
+ 0x0000, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600,
+ 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0618, 0x0618, 0x0738,
+ 0x03F0, 0x01E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'K'
+ 0x0000, 0x3006, 0x1806, 0x0C06, 0x0606, 0x0306, 0x0186, 0x00C6,
+ 0x0066, 0x0076, 0x00DE, 0x018E, 0x0306, 0x0606, 0x0C06, 0x1806,
+ 0x3006, 0x6006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'L'
+ 0x0000, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
+ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
+ 0x1FF8, 0x1FF8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'M'
+ 0x0000, 0xE00E, 0xF01E, 0xF01E, 0xF01E, 0xD836, 0xD836, 0xD836,
+ 0xD836, 0xCC66, 0xCC66, 0xCC66, 0xC6C6, 0xC6C6, 0xC6C6, 0xC6C6,
+ 0xC386, 0xC386, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'N'
+ 0x0000, 0x300C, 0x301C, 0x303C, 0x303C, 0x306C, 0x306C, 0x30CC,
+ 0x30CC, 0x318C, 0x330C, 0x330C, 0x360C, 0x360C, 0x3C0C, 0x3C0C,
+ 0x380C, 0x300C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'O'
+ 0x0000, 0x07E0, 0x1FF8, 0x381C, 0x700E, 0x6006, 0xC003, 0xC003,
+ 0xC003, 0xC003, 0xC003, 0xC003, 0xC003, 0x6006, 0x700E, 0x381C,
+ 0x1FF8, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'P'
+ 0x0000, 0x0FFC, 0x1FFC, 0x380C, 0x300C, 0x300C, 0x300C, 0x300C,
+ 0x180C, 0x1FFC, 0x07FC, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C,
+ 0x000C, 0x000C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'Q'
+ 0x0000, 0x07E0, 0x1FF8, 0x381C, 0x700E, 0x6006, 0xE003, 0xC003,
+ 0xC003, 0xC003, 0xC003, 0xC003, 0xE007, 0x6306, 0x3F0E, 0x3C1C,
+ 0x3FF8, 0xF7E0, 0xC000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'R'
+ 0x0000, 0x0FFE, 0x1FFE, 0x3806, 0x3006, 0x3006, 0x3006, 0x3806,
+ 0x1FFE, 0x07FE, 0x0306, 0x0606, 0x0C06, 0x1806, 0x1806, 0x3006,
+ 0x3006, 0x6006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'S'
+ 0x0000, 0x03E0, 0x0FF8, 0x0C1C, 0x180C, 0x180C, 0x000C, 0x001C,
+ 0x03F8, 0x0FE0, 0x1E00, 0x3800, 0x3006, 0x3006, 0x300E, 0x1C1C,
+ 0x0FF8, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'T'
+ 0x0000, 0x7FFE, 0x7FFE, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'U'
+ 0x0000, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C,
+ 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x1818,
+ 0x1FF8, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'V'
+ 0x0000, 0x6003, 0x3006, 0x3006, 0x3006, 0x180C, 0x180C, 0x180C,
+ 0x0C18, 0x0C18, 0x0E38, 0x0630, 0x0630, 0x0770, 0x0360, 0x0360,
+ 0x01C0, 0x01C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'W'
+ 0x0000, 0x6003, 0x61C3, 0x61C3, 0x61C3, 0x3366, 0x3366, 0x3366,
+ 0x3366, 0x3366, 0x3366, 0x1B6C, 0x1B6C, 0x1B6C, 0x1A2C, 0x1E3C,
+ 0x0E38, 0x0E38, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'X'
+ 0x0000, 0xE00F, 0x700C, 0x3018, 0x1830, 0x0C70, 0x0E60, 0x07C0,
+ 0x0380, 0x0380, 0x03C0, 0x06E0, 0x0C70, 0x1C30, 0x1818, 0x300C,
+ 0x600E, 0xE007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'Y'
+ 0x0000, 0xC003, 0x6006, 0x300C, 0x381C, 0x1838, 0x0C30, 0x0660,
+ 0x07E0, 0x03C0, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'Z'
+ 0x0000, 0x7FFC, 0x7FFC, 0x6000, 0x3000, 0x1800, 0x0C00, 0x0600,
+ 0x0300, 0x0180, 0x00C0, 0x0060, 0x0030, 0x0018, 0x000C, 0x0006,
+ 0x7FFE, 0x7FFE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '['
+ 0x0000, 0x03E0, 0x03E0, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060,
+ 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060,
+ 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x03E0, 0x03E0, 0x0000,
+ // '\'
+ 0x0000, 0x0030, 0x0030, 0x0060, 0x0060, 0x0060, 0x00C0, 0x00C0,
+ 0x00C0, 0x01C0, 0x0180, 0x0180, 0x0180, 0x0300, 0x0300, 0x0300,
+ 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // ']'
+ 0x0000, 0x03E0, 0x03E0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300,
+ 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300,
+ 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x03E0, 0x03E0, 0x0000,
+ // '^'
+ 0x0000, 0x0000, 0x01C0, 0x01C0, 0x0360, 0x0360, 0x0360, 0x0630,
+ 0x0630, 0x0C18, 0x0C18, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '_'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '''
+ 0x0000, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'a'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03F0, 0x07F8,
+ 0x0C1C, 0x0C0C, 0x0F00, 0x0FF0, 0x0CF8, 0x0C0C, 0x0C0C, 0x0F1C,
+ 0x0FF8, 0x18F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'b'
+ 0x0000, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x03D8, 0x0FF8,
+ 0x0C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x0C38,
+ 0x0FF8, 0x03D8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'c'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03C0, 0x07F0,
+ 0x0E30, 0x0C18, 0x0018, 0x0018, 0x0018, 0x0018, 0x0C18, 0x0E30,
+ 0x07F0, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'd'
+ 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1BC0, 0x1FF0,
+ 0x1C30, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1C30,
+ 0x1FF0, 0x1BC0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'e'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03C0, 0x0FF0,
+ 0x0C30, 0x1818, 0x1FF8, 0x1FF8, 0x0018, 0x0018, 0x1838, 0x1C30,
+ 0x0FF0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'f'
+ 0x0000, 0x0F80, 0x0FC0, 0x00C0, 0x00C0, 0x00C0, 0x07F0, 0x07F0,
+ 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'g'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0DE0, 0x0FF8,
+ 0x0E18, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0E18,
+ 0x0FF8, 0x0DE0, 0x0C00, 0x0C0C, 0x061C, 0x07F8, 0x01F0, 0x0000,
+ // 'h'
+ 0x0000, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x07D8, 0x0FF8,
+ 0x1C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818,
+ 0x1818, 0x1818, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'i'
+ 0x0000, 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'j'
+ 0x0000, 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00F8, 0x0078, 0x0000,
+ // 'k'
+ 0x0000, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x0C0C, 0x060C,
+ 0x030C, 0x018C, 0x00CC, 0x006C, 0x00FC, 0x019C, 0x038C, 0x030C,
+ 0x060C, 0x0C0C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'l'
+ 0x0000, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'm'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3C7C, 0x7EFF,
+ 0xE3C7, 0xC183, 0xC183, 0xC183, 0xC183, 0xC183, 0xC183, 0xC183,
+ 0xC183, 0xC183, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'n'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0798, 0x0FF8,
+ 0x1C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818,
+ 0x1818, 0x1818, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'o'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03C0, 0x0FF0,
+ 0x0C30, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x0C30,
+ 0x0FF0, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'p'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03D8, 0x0FF8,
+ 0x0C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x0C38,
+ 0x0FF8, 0x03D8, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0000,
+ // 'q'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1BC0, 0x1FF0,
+ 0x1C30, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1C30,
+ 0x1FF0, 0x1BC0, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000,
+ // 'r'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07B0, 0x03F0,
+ 0x0070, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
+ 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 's'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, 0x03F0,
+ 0x0E38, 0x0C18, 0x0038, 0x03F0, 0x07C0, 0x0C00, 0x0C18, 0x0E38,
+ 0x07F0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 't'
+ 0x0000, 0x0000, 0x0080, 0x00C0, 0x00C0, 0x00C0, 0x07F0, 0x07F0,
+ 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0,
+ 0x07C0, 0x0780, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'u'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1818, 0x1818,
+ 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1C38,
+ 0x1FF0, 0x19E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'v'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x180C, 0x0C18,
+ 0x0C18, 0x0C18, 0x0630, 0x0630, 0x0630, 0x0360, 0x0360, 0x0360,
+ 0x01C0, 0x01C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'w'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x41C1, 0x41C1,
+ 0x61C3, 0x6363, 0x6363, 0x6363, 0x3636, 0x3636, 0x3636, 0x1C1C,
+ 0x1C1C, 0x1C1C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'x'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x381C, 0x1C38,
+ 0x0C30, 0x0660, 0x0360, 0x0360, 0x0360, 0x0360, 0x0660, 0x0C30,
+ 0x1C38, 0x381C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // 'y'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3018, 0x1830,
+ 0x1830, 0x1870, 0x0C60, 0x0C60, 0x0CE0, 0x06C0, 0x06C0, 0x0380,
+ 0x0380, 0x0380, 0x0180, 0x0180, 0x01C0, 0x00F0, 0x0070, 0x0000,
+ // 'z'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1FFC, 0x1FFC,
+ 0x0C00, 0x0600, 0x0300, 0x0180, 0x00C0, 0x0060, 0x0030, 0x0018,
+ 0x1FFC, 0x1FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ // '{'
+ 0x0000, 0x0300, 0x0180, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0,
+ 0x00C0, 0x0060, 0x0060, 0x0030, 0x0060, 0x0040, 0x00C0, 0x00C0,
+ 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x0180, 0x0300, 0x0000, 0x0000,
+ // '|'
+ 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0000,
+ // '}'
+ 0x0000, 0x0060, 0x00C0, 0x01C0, 0x0180, 0x0180, 0x0180, 0x0180,
+ 0x0180, 0x0300, 0x0300, 0x0600, 0x0300, 0x0100, 0x0180, 0x0180,
+ 0x0180, 0x0180, 0x0180, 0x0180, 0x00C0, 0x0060, 0x0000, 0x0000,
+ // '~'
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x10F0, 0x1FF8, 0x0F08, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+void disp_char_1624(uint16_t x, uint16_t y, uint8_t c, uint16_t charColor, uint16_t bkColor) {
+ for (uint16_t i = 0; i < 24; i++) {
+ const uint16_t tmp_char = pgm_read_word(&ASCII_Table_16x24[((c - 0x20) * 24) + i]);
+ for (uint16_t j = 0; j < 16; j++)
+ SPI_TFT.SetPoint(x + j, y + i, ((tmp_char >> j) & 0x01) ? charColor : bkColor);
+ }
+}
+
+void disp_string(uint16_t x, uint16_t y, const char * string, uint16_t charColor, uint16_t bkColor) {
+ while (*string != '\0') {
+ disp_char_1624(x, y, *string, charColor, bkColor);
+ string++;
+ x += 16;
+ }
+}
+
+void disp_assets_update() {
+ SPI_TFT.LCD_clear(0x0000);
+ disp_string(100, 140, "Assets Updating...", 0xFFFF, 0x0000);
+}
+
+void disp_assets_update_progress(const char *msg) {
+ char buf[30];
+ memset(buf, ' ', COUNT(buf));
+ strncpy(buf, msg, strlen(msg));
+ buf[COUNT(buf)-1] = '\0';
+ disp_string(100, 165, buf, 0xFFFF, 0x0000);
+}
+
+uint8_t mks_test_flag = 0;
+const char *MKSTestPath = "MKS_TEST";
+
+#if ENABLED(SDSUPPORT)
+ void mks_test_get() {
+ SdFile dir, root = card.getroot();
+ if (dir.open(&root, MKSTestPath, O_RDONLY))
+ mks_test_flag = 0x1E;
+ }
+#endif
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.h b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.h
new file mode 100644
index 0000000..0e2d809
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.h
@@ -0,0 +1,33 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <lvgl.h>
+
+void mks_gpio_test();
+void disp_char_1624(uint16_t x, uint16_t y, uint8_t c, uint16_t charColor, uint16_t bkColor);
+void disp_string(uint16_t x, uint16_t y, const char * string, uint16_t charColor, uint16_t bkColor);
+void mks_hardware_test();
+void disp_assets_update();
+void disp_assets_update_progress(const char *msg);
+void mks_test_get();
+extern uint8_t mks_test_flag;
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
new file mode 100644
index 0000000..51aab0a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp
@@ -0,0 +1,622 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "string.h"
+#include "draw_ui.h"
+#include "pic_manager.h"
+#include "draw_ready_print.h"
+#include "mks_hardware_test.h"
+
+#include "SPIFlashStorage.h"
+#include "../../../../libs/W25Qxx.h"
+
+#include "../../../../sd/cardreader.h"
+#include "../../../../MarlinCore.h"
+
+extern uint16_t DeviceCode;
+
+#if ENABLED(SDSUPPORT)
+ extern char *createFilename(char * const buffer, const dir_t &p);
+#endif
+
+static const char assets[][LONG_FILENAME_LENGTH] = {
+ //homing screen
+ "bmp_zeroAll.bin",
+ "bmp_zero.bin",
+ "bmp_zeroX.bin",
+ "bmp_zeroY.bin",
+ "bmp_zeroZ.bin",
+ "bmp_manual_off.bin",
+
+ //tool screen
+ "bmp_preHeat.bin",
+ "bmp_extruct.bin",
+ "bmp_mov.bin",
+ "bmp_leveling.bin",
+ "bmp_filamentchange.bin",
+ "bmp_more.bin",
+
+ //fan screen
+ "bmp_Add.bin",
+ "bmp_Dec.bin",
+ "bmp_speed255.bin",
+ "bmp_speed127.bin",
+ "bmp_speed0.bin",
+ "bmp_speed0.bin",
+
+ "bmp_bed.bin",
+ "bmp_step1_degree.bin",
+ "bmp_step5_degree.bin",
+ "bmp_step10_degree.bin",
+
+ //extrusion screen
+ "bmp_in.bin",
+ "bmp_out.bin",
+ "bmp_extru1.bin",
+ #if HAS_MULTI_EXTRUDER
+ "bmp_extru2.bin",
+ #endif
+ "bmp_speed_high.bin",
+ "bmp_speed_slow.bin",
+ "bmp_speed_normal.bin",
+ "bmp_step1_mm.bin",
+ "bmp_step5_mm.bin",
+ "bmp_step10_mm.bin",
+
+ //select file screen
+ "bmp_pageUp.bin",
+ "bmp_pageDown.bin",
+ "bmp_back.bin", //TODO: why two back buttons? Why not just one? (return / back)
+ "bmp_dir.bin",
+ "bmp_file.bin",
+
+ //move motor screen
+ //TODO: 6 equal icons, just in diffenct rotation... it may be optimized too
+ "bmp_xAdd.bin",
+ "bmp_xDec.bin",
+ "bmp_yAdd.bin",
+ "bmp_yDec.bin",
+ "bmp_zAdd.bin",
+ "bmp_zDec.bin",
+ "bmp_step_move0_1.bin",
+ "bmp_step_move1.bin",
+ "bmp_step_move10.bin",
+
+ //operation screen
+ "bmp_auto_off.bin",
+ "bmp_speed.bin",
+ "bmp_fan.bin",
+ "bmp_temp.bin",
+ "bmp_extrude_opr.bin",
+ "bmp_move_opr.bin",
+
+ //change speed screen
+ "bmp_step1_percent.bin",
+ "bmp_step5_percent.bin",
+ "bmp_step10_percent.bin",
+ "bmp_extruct_sel.bin",
+ "bmp_mov_changespeed.bin",
+ "bmp_mov_sel.bin",
+ "bmp_speed_extruct.bin",
+
+ //printing screen
+ "bmp_pause.bin",
+ "bmp_resume.bin",
+ "bmp_stop.bin",
+ "bmp_ext1_state.bin",
+ #if HAS_MULTI_EXTRUDER
+ "bmp_ext2_state.bin",
+ #endif
+ "bmp_bed_state.bin",
+ "bmp_fan_state.bin",
+ "bmp_time_state.bin",
+ "bmp_zpos_state.bin",
+ "bmp_operate.bin",
+
+ //manual leval screen (only if disabled auto level)
+ #if DISABLED(AUTO_BED_LEVELING_BILINEAR)
+ "bmp_leveling1.bin",
+ "bmp_leveling2.bin",
+ "bmp_leveling3.bin",
+ "bmp_leveling4.bin",
+ "bmp_leveling5.bin",
+ #endif
+
+ //lang select screen
+ #if HAS_LANG_SELECT_SCREEN
+ "bmp_language.bin",
+ "bmp_simplified_cn.bin",
+ "bmp_simplified_cn_sel.bin",
+ "bmp_traditional_cn.bin",
+ "bmp_traditional_cn_sel.bin",
+ "bmp_english.bin",
+ "bmp_english_sel.bin",
+ "bmp_russian.bin",
+ "bmp_russian_sel.bin",
+ "bmp_spanish.bin",
+ "bmp_spanish_sel.bin",
+ "bmp_french.bin",
+ "bmp_french_sel.bin",
+ "bmp_italy.bin",
+ "bmp_italy_sel.bin",
+ #endif // HAS_LANG_SELECT_SCREEN
+
+ // gcode preview
+ #if HAS_GCODE_DEFAULT_VIEW_IN_FLASH
+ "bmp_preview.bin",
+ #endif
+
+ #if HAS_LOGO_IN_FLASH
+ "bmp_logo.bin",
+ #endif
+
+ // settings screen
+ "bmp_about.bin",
+ "bmp_eeprom_settings.bin",
+ "bmp_machine_para.bin",
+ "bmp_function1.bin",
+
+ //start screen
+ "bmp_printing.bin",
+ "bmp_set.bin",
+ "bmp_tool.bin",
+
+ // base icons
+ "bmp_arrow.bin",
+ "bmp_back70x40.bin",
+ "bmp_value_blank.bin",
+ "bmp_blank_sel.bin",
+ "bmp_disable.bin",
+ "bmp_enable.bin",
+ "bmp_return.bin",
+
+ #if ENABLED(MKS_WIFI_MODULE)
+ // wifi screen
+ "bmp_wifi.bin",
+ "bmp_cloud.bin",
+ #endif
+
+ // babystep screen
+ "bmp_baby_move0_01.bin",
+ "bmp_baby_move0_05.bin",
+ "bmp_baby_move0_1.bin",
+
+ // more screen
+ "bmp_custom1.bin",
+ "bmp_custom2.bin",
+ "bmp_custom3.bin",
+ "bmp_custom4.bin",
+ "bmp_custom5.bin",
+ "bmp_custom6.bin",
+ "bmp_custom7.bin"
+};
+
+#if HAS_SPI_FLASH_FONT
+ static char fonts[][LONG_FILENAME_LENGTH] = { "FontUNIGBK.bin" };
+#endif
+
+uint8_t currentFlashPage = 0;
+
+uint32_t lv_get_pic_addr(uint8_t *Pname) {
+ uint8_t Pic_cnt;
+ uint8_t i, j;
+ PIC_MSG PIC;
+ uint32_t tmp_cnt = 0;
+ uint32_t addr = 0;
+
+ currentFlashPage = 0;
+
+ #if ENABLED(MARLIN_DEV_MODE)
+ SERIAL_ECHOLNPAIR("Getting picture SPI Flash Address: ", (const char*)Pname);
+ #endif
+
+ W25QXX.init(SPI_QUARTER_SPEED);
+
+ W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1);
+ if (Pic_cnt == 0xFF) Pic_cnt = 0;
+ for (i = 0; i < Pic_cnt; i++) {
+ j = 0;
+ do {
+ W25QXX.SPI_FLASH_BufferRead(&PIC.name[j], PIC_NAME_ADDR + tmp_cnt, 1);
+ tmp_cnt++;
+ } while (PIC.name[j++] != '\0');
+
+ if ((strcasecmp((char*)Pname, (char*)PIC.name)) == 0) {
+ if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761))
+ addr = PIC_DATA_ADDR_TFT35 + i * PER_PIC_MAX_SPACE_TFT35;
+ else
+ addr = PIC_DATA_ADDR_TFT32 + i * PER_PIC_MAX_SPACE_TFT32;
+ return addr;
+ }
+ }
+
+ return addr;
+}
+
+const char *assetsPath = "assets";
+const char *bakPath = "_assets";
+
+void spiFlashErase_PIC() {
+ volatile uint32_t pic_sectorcnt = 0;
+ W25QXX.init(SPI_QUARTER_SPEED);
+ //erase 0x001000 -64K
+ for (pic_sectorcnt = 0; pic_sectorcnt < (64 - 4) / 4; pic_sectorcnt++) {
+ watchdog_refresh();
+ W25QXX.SPI_FLASH_SectorErase(PICINFOADDR + pic_sectorcnt * 4 * 1024);
+ }
+ //erase 64K -- 6M
+ for (pic_sectorcnt = 0; pic_sectorcnt < (PIC_SIZE_xM * 1024 / 64 - 1); pic_sectorcnt++) {
+ watchdog_refresh();
+ W25QXX.SPI_FLASH_BlockErase((pic_sectorcnt + 1) * 64 * 1024);
+ }
+}
+
+#if HAS_SPI_FLASH_FONT
+ void spiFlashErase_FONT() {
+ volatile uint32_t Font_sectorcnt = 0;
+ W25QXX.init(SPI_QUARTER_SPEED);
+ for (Font_sectorcnt = 0; Font_sectorcnt < 32-1; Font_sectorcnt++) {
+ watchdog_refresh();
+ W25QXX.SPI_FLASH_BlockErase(FONTINFOADDR + Font_sectorcnt * 64 * 1024);
+ }
+ }
+#endif
+
+uint32_t LogoWrite_Addroffset = 0;
+
+uint8_t Pic_Logo_Write(uint8_t *LogoName, uint8_t *Logo_Wbuff, uint32_t LogoWriteSize) {
+ if (LogoWriteSize <= 0) return 0;
+
+ W25QXX.SPI_FLASH_BufferWrite(Logo_Wbuff, PIC_LOGO_ADDR + LogoWrite_Addroffset, LogoWriteSize);
+
+ for (uint32_t i = 0; i < LogoWriteSize; i++) {
+ uint8_t temp1;
+ W25QXX.SPI_FLASH_BufferRead(&temp1, PIC_LOGO_ADDR + LogoWrite_Addroffset + i, 1);
+ if (*(Logo_Wbuff + i) != temp1) return 0;
+ }
+ LogoWrite_Addroffset += LogoWriteSize;
+ const uint32_t logo_maxsize = DeviceCode == 0x9488 || DeviceCode == 0x5761 ? LOGO_MAX_SIZE_TFT35 : LOGO_MAX_SIZE_TFT32;
+ if (LogoWrite_Addroffset >= logo_maxsize) LogoWrite_Addroffset = 0;
+ return 1;
+}
+
+uint32_t TitleLogoWrite_Addroffset = 0;
+uint8_t Pic_TitleLogo_Write(uint8_t *TitleLogoName, uint8_t *TitleLogo_Wbuff, uint32_t TitleLogoWriteSize) {
+ if (TitleLogoWriteSize <= 0)
+ return 0;
+ if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761))
+ W25QXX.SPI_FLASH_BufferWrite(TitleLogo_Wbuff, PIC_ICON_LOGO_ADDR_TFT35 + TitleLogoWrite_Addroffset, TitleLogoWriteSize);
+ else
+ W25QXX.SPI_FLASH_BufferWrite(TitleLogo_Wbuff, PIC_ICON_LOGO_ADDR_TFT32 + TitleLogoWrite_Addroffset, TitleLogoWriteSize);
+ TitleLogoWrite_Addroffset += TitleLogoWriteSize;
+ if (TitleLogoWrite_Addroffset >= TITLELOGO_MAX_SIZE)
+ TitleLogoWrite_Addroffset = 0;
+ return 1;
+}
+
+uint32_t default_view_addroffset_r = 0;
+void default_view_Write(uint8_t *default_view__Rbuff, uint32_t default_view_Writesize) {
+ W25QXX.SPI_FLASH_BufferWrite(default_view__Rbuff, DEFAULT_VIEW_ADDR_TFT35 + default_view_addroffset_r, default_view_Writesize);
+ default_view_addroffset_r += default_view_Writesize;
+ if (default_view_addroffset_r >= DEFAULT_VIEW_MAX_SIZE)
+ default_view_addroffset_r = 0;
+}
+
+uint32_t Pic_Info_Write(uint8_t *P_name, uint32_t P_size) {
+ uint8_t pic_counter = 0;
+ uint32_t Pic_SaveAddr;
+ uint32_t Pic_SizeSaveAddr;
+ uint32_t Pic_NameSaveAddr;
+ uint8_t Pname_temp;
+ uint32_t i, j;
+ uint32_t name_len = 0;
+ uint32_t SaveName_len = 0;
+ union union32 size_tmp;
+
+ W25QXX.SPI_FLASH_BufferRead(&pic_counter, PIC_COUNTER_ADDR, 1);
+
+ if (pic_counter == 0xFF)
+ pic_counter = 0;
+
+ if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761))
+ Pic_SaveAddr = PIC_DATA_ADDR_TFT35 + pic_counter * PER_PIC_MAX_SPACE_TFT35;
+ else
+ Pic_SaveAddr = PIC_DATA_ADDR_TFT32 + pic_counter * PER_PIC_MAX_SPACE_TFT32;
+
+ for (j = 0; j < pic_counter; j++) {
+ do {
+ W25QXX.SPI_FLASH_BufferRead(&Pname_temp, PIC_NAME_ADDR + SaveName_len, 1);
+ SaveName_len++;
+ } while (Pname_temp != '\0');
+ }
+ i = 0;
+ while ((*(P_name + i) != '\0')) {
+ i++;
+ name_len++;
+ }
+
+ Pic_NameSaveAddr = PIC_NAME_ADDR + SaveName_len;
+ W25QXX.SPI_FLASH_BufferWrite(P_name, Pic_NameSaveAddr, name_len + 1);
+ Pic_SizeSaveAddr = PIC_SIZE_ADDR + 4 * pic_counter;
+ size_tmp.dwords = P_size;
+ W25QXX.SPI_FLASH_BufferWrite(size_tmp.bytes, Pic_SizeSaveAddr, 4);
+
+ pic_counter++;
+ W25QXX.SPI_FLASH_SectorErase(PIC_COUNTER_ADDR);
+ W25QXX.SPI_FLASH_BufferWrite(&pic_counter, PIC_COUNTER_ADDR, 1);
+
+ return Pic_SaveAddr;
+}
+
+#if ENABLED(SDSUPPORT)
+
+ static void dosName2LongName(const char dosName[11], char* longName) {
+ uint8_t j = 0;
+ LOOP_L_N(i, 11) {
+ if (i == 8) longName[j++] = '.';
+ if (dosName[i] == '\0' || dosName[i] == ' ') continue;
+ longName[j++] = dosName[i];
+ }
+ longName[j] = '\0';
+ }
+
+ static int8_t arrayFindStr(const char arr[][LONG_FILENAME_LENGTH], uint8_t arraySize, const char* str) {
+ for (uint8_t a = 0; a < arraySize; a++) {
+ if (strcasecmp(arr[a], str) == 0)
+ return a;
+ }
+ return -1;
+ }
+
+ #if ENABLED(MARLIN_DEV_MODE)
+ static uint32_t totalSizes = 0, totalCompressed = 0;
+ #endif
+
+ #define ASSET_TYPE_ICON 0
+ #define ASSET_TYPE_LOGO 1
+ #define ASSET_TYPE_TITLE_LOGO 2
+ #define ASSET_TYPE_G_PREVIEW 3
+ #define ASSET_TYPE_FONT 4
+ static void loadAsset(SdFile &dir, dir_t& entry, const char *fn, int8_t assetType) {
+ SdFile file;
+ char dosFilename[FILENAME_LENGTH];
+ createFilename(dosFilename, entry);
+ if (!file.open(&dir, dosFilename, O_READ)) {
+ #if ENABLED(MARLIN_DEV_MODE)
+ SERIAL_ECHOLNPAIR("Error opening Asset: ", fn);
+ #endif
+ return;
+ }
+
+ watchdog_refresh();
+ disp_assets_update_progress(fn);
+
+ W25QXX.init(SPI_QUARTER_SPEED);
+
+ uint16_t pbr;
+ uint32_t pfileSize;
+ uint32_t totalSizeLoaded = 0;
+ uint32_t Pic_Write_Addr;
+ pfileSize = file.fileSize();
+ totalSizeLoaded += pfileSize;
+ if (assetType == ASSET_TYPE_LOGO) {
+ do {
+ watchdog_refresh();
+ pbr = file.read(public_buf, BMP_WRITE_BUF_LEN);
+ Pic_Logo_Write((uint8_t *)fn, public_buf, pbr);
+ } while (pbr >= BMP_WRITE_BUF_LEN);
+ }
+ else if (assetType == ASSET_TYPE_TITLE_LOGO) {
+ do {
+ watchdog_refresh();
+ pbr = file.read(public_buf, BMP_WRITE_BUF_LEN);
+ Pic_TitleLogo_Write((uint8_t *)fn, public_buf, pbr);
+ } while (pbr >= BMP_WRITE_BUF_LEN);
+ }
+ else if (assetType == ASSET_TYPE_G_PREVIEW) {
+ do {
+ watchdog_refresh();
+ pbr = file.read(public_buf, BMP_WRITE_BUF_LEN);
+ default_view_Write(public_buf, pbr);
+ } while (pbr >= BMP_WRITE_BUF_LEN);
+ }
+ else if (assetType == ASSET_TYPE_ICON) {
+ Pic_Write_Addr = Pic_Info_Write((uint8_t *)fn, pfileSize);
+ SPIFlash.beginWrite(Pic_Write_Addr);
+ #if HAS_SPI_FLASH_COMPRESSION
+ do {
+ watchdog_refresh();
+ pbr = file.read(public_buf, SPI_FLASH_PageSize);
+ TERN_(MARLIN_DEV_MODE, totalSizes += pbr);
+ SPIFlash.writeData(public_buf, SPI_FLASH_PageSize);
+ } while (pbr >= SPI_FLASH_PageSize);
+ #else
+ do {
+ pbr = file.read(public_buf, BMP_WRITE_BUF_LEN);
+ W25QXX.SPI_FLASH_BufferWrite(public_buf, Pic_Write_Addr, pbr);
+ Pic_Write_Addr += pbr;
+ } while (pbr >= BMP_WRITE_BUF_LEN);
+ #endif
+ #if ENABLED(MARLIN_DEV_MODE)
+ SERIAL_ECHOLNPAIR("Space used: ", fn, " - ", (SPIFlash.getCurrentPage() + 1) * SPI_FLASH_PageSize / 1024, "KB");
+ totalCompressed += (SPIFlash.getCurrentPage() + 1) * SPI_FLASH_PageSize;
+ #endif
+ SPIFlash.endWrite();
+ }
+ else if (assetType == ASSET_TYPE_FONT) {
+ Pic_Write_Addr = UNIGBK_FLASH_ADDR;
+ do {
+ watchdog_refresh();
+ pbr = file.read(public_buf, BMP_WRITE_BUF_LEN);
+ W25QXX.SPI_FLASH_BufferWrite(public_buf, Pic_Write_Addr, pbr);
+ Pic_Write_Addr += pbr;
+ } while (pbr >= BMP_WRITE_BUF_LEN);
+ }
+
+ file.close();
+
+ #if ENABLED(MARLIN_DEV_MODE)
+ SERIAL_ECHOLNPAIR("Asset added: ", fn);
+ #endif
+ }
+
+ void UpdateAssets() {
+ if (!card.isMounted()) return;
+ SdFile dir, root = card.getroot();
+ if (dir.open(&root, assetsPath, O_RDONLY)) {
+
+ disp_assets_update();
+ disp_assets_update_progress("Erasing pics...");
+ watchdog_refresh();
+ spiFlashErase_PIC();
+ #if HAS_SPI_FLASH_FONT
+ disp_assets_update_progress("Erasing fonts...");
+ watchdog_refresh();
+ spiFlashErase_FONT();
+ #endif
+
+ disp_assets_update_progress("Reading files...");
+ dir_t d;
+ while (dir.readDir(&d, card.longFilename) > 0) {
+ // If we dont get a long name, but gets a short one, try it
+ if (card.longFilename[0] == 0 && d.name[0] != 0)
+ dosName2LongName((const char*)d.name, card.longFilename);
+ if (card.longFilename[0] == 0) continue;
+ if (card.longFilename[0] == '.') continue;
+
+ int8_t a = arrayFindStr(assets, COUNT(assets), card.longFilename);
+ if (a >= 0 && a < (int8_t)COUNT(assets)) {
+ uint8_t assetType = ASSET_TYPE_ICON;
+ if (strstr(assets[a], "_logo"))
+ assetType = ASSET_TYPE_LOGO;
+ else if (strstr(assets[a], "_titlelogo"))
+ assetType = ASSET_TYPE_TITLE_LOGO;
+ else if (strstr(assets[a], "_preview"))
+ assetType = ASSET_TYPE_G_PREVIEW;
+
+ loadAsset(dir, d, assets[a], assetType);
+
+ continue;
+ }
+
+ #if HAS_SPI_FLASH_FONT
+ a = arrayFindStr(fonts, COUNT(fonts), card.longFilename);
+ if (a >= 0 && a < (int8_t)COUNT(fonts))
+ loadAsset(dir, d, fonts[a], ASSET_TYPE_FONT);
+ #endif
+ }
+ dir.rename(&root, bakPath);
+ }
+ dir.close();
+
+ #if ENABLED(MARLIN_DEV_MODE)
+ uint8_t pic_counter = 0;
+ W25QXX.SPI_FLASH_BufferRead(&pic_counter, PIC_COUNTER_ADDR, 1);
+ SERIAL_ECHOLNPAIR("Total assets loaded: ", pic_counter);
+ SERIAL_ECHOLNPAIR("Total Uncompressed: ", totalSizes, ", Compressed: ", totalCompressed);
+ #endif
+ }
+
+ #if HAS_SPI_FLASH_FONT
+ void spi_flash_read_test() { W25QXX.SPI_FLASH_BufferRead(public_buf, UNIGBK_FLASH_ADDR, BMP_WRITE_BUF_LEN); }
+ #endif
+
+#endif // SDSUPPORT
+
+void Pic_Read(uint8_t *Pname, uint8_t *P_Rbuff) {
+ uint8_t i, j;
+ uint8_t Pic_cnt;
+ uint32_t tmp_cnt = 0;
+ PIC_MSG PIC;
+
+ W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1);
+ if (Pic_cnt == 0xFF)
+ Pic_cnt = 0;
+
+ for (i = 0; i < Pic_cnt; i++) {
+ j = 0;
+ do {
+ W25QXX.SPI_FLASH_BufferRead(&PIC.name[j], PIC_NAME_ADDR + tmp_cnt, 1);
+ tmp_cnt++;
+ } while (PIC.name[j++] != '\0');
+ //pic size
+ W25QXX.SPI_FLASH_BufferRead(PIC.size.bytes, PIC_SIZE_ADDR + i * 4, 4);
+
+ if ((strcmp((char*)Pname, (char*)PIC.name)) == 0) {
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)P_Rbuff, PIC_DATA_ADDR_TFT35 + i * PER_PIC_MAX_SPACE_TFT35, PIC.size.dwords);
+ break;
+ }
+ }
+}
+
+void lv_pic_test(uint8_t *P_Rbuff, uint32_t addr, uint32_t size) {
+ #if HAS_SPI_FLASH_COMPRESSION
+ if (currentFlashPage == 0)
+ SPIFlash.beginRead(addr);
+ SPIFlash.readData(P_Rbuff, size);
+ currentFlashPage++;
+ #else
+ W25QXX.init(SPI_QUARTER_SPEED);
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)P_Rbuff, addr, size);
+ #endif
+}
+
+#if HAS_SPI_FLASH_FONT
+ void get_spi_flash_data(const char *rec_buf, int addr, int size) {
+ W25QXX.init(SPI_QUARTER_SPEED);
+ W25QXX.SPI_FLASH_BufferRead((uint8_t *)rec_buf, UNIGBK_FLASH_ADDR + addr, size);
+ }
+#endif
+
+uint32_t logo_addroffset = 0;
+void Pic_Logo_Read(uint8_t *LogoName, uint8_t *Logo_Rbuff, uint32_t LogoReadsize) {
+ W25QXX.init(SPI_QUARTER_SPEED);
+ W25QXX.SPI_FLASH_BufferRead(Logo_Rbuff, PIC_LOGO_ADDR + logo_addroffset, LogoReadsize);
+ logo_addroffset += LogoReadsize;
+ if (logo_addroffset >= LOGO_MAX_SIZE_TFT35)
+ logo_addroffset = 0;
+}
+
+uint32_t default_view_addroffset = 0;
+void default_view_Read(uint8_t *default_view_Rbuff, uint32_t default_view_Readsize) {
+ W25QXX.init(SPI_QUARTER_SPEED);
+ W25QXX.SPI_FLASH_BufferRead(default_view_Rbuff, DEFAULT_VIEW_ADDR_TFT35 + default_view_addroffset, default_view_Readsize);
+ default_view_addroffset += default_view_Readsize;
+ if (default_view_addroffset >= DEFAULT_VIEW_MAX_SIZE)
+ default_view_addroffset = 0;
+}
+
+#if HAS_BAK_VIEW_IN_FLASH
+ uint32_t flash_view_addroffset = 0;
+ void flash_view_Read(uint8_t *flash_view_Rbuff, uint32_t flash_view_Readsize) {
+ W25QXX.init(SPI_QUARTER_SPEED);
+ W25QXX.SPI_FLASH_BufferRead(flash_view_Rbuff, BAK_VIEW_ADDR_TFT35 + flash_view_addroffset, flash_view_Readsize);
+ flash_view_addroffset += flash_view_Readsize;
+ if (flash_view_addroffset >= FLASH_VIEW_MAX_SIZE)
+ flash_view_addroffset = 0;
+ }
+#endif
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h
new file mode 100644
index 0000000..83d7431
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h
@@ -0,0 +1,168 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../../../../inc/MarlinConfig.h"
+
+#include "../../../../libs/W25Qxx.h"
+
+#include <lvgl.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#ifndef HAS_SPI_FLASH_FONT
+ #define HAS_SPI_FLASH_FONT 1 // Disabled until fix the font load code
+#endif
+#ifndef HAS_GCODE_PREVIEW
+ #define HAS_GCODE_PREVIEW 1
+#endif
+#ifndef HAS_LANG_SELECT_SCREEN
+ #define HAS_LANG_SELECT_SCREEN 1
+#endif
+#ifndef HAS_BAK_VIEW_IN_FLASH
+ #define HAS_BAK_VIEW_IN_FLASH 1
+#endif
+#ifndef HAS_GCODE_DEFAULT_VIEW_IN_FLASH
+ #define HAS_GCODE_DEFAULT_VIEW_IN_FLASH 1
+#endif
+#ifndef HAS_LOGO_IN_FLASH
+ #define HAS_LOGO_IN_FLASH 1
+#endif
+#ifndef SPI_FLASH_SIZE
+ #define SPI_FLASH_SIZE 0x1000000 // 16MB
+#endif
+
+#define PIC_MAX_CN 100 // Maximum number of pictures
+#define PIC_NAME_MAX_LEN 50 // Picture name maximum length
+
+#define LOGO_MAX_SIZE_TFT35 (300*1024)
+#define LOGO_MAX_SIZE_TFT32 (150*1024)
+#define TITLELOGO_MAX_SIZE (150*1024) // Little logo maximum
+#define DEFAULT_VIEW_MAX_SIZE (200*200*2)
+#define FLASH_VIEW_MAX_SIZE (200*200*2)
+
+#define PER_PIC_MAX_SPACE_TFT35 (9*1024)
+#define PER_PIC_MAX_SPACE_TFT32 (16*1024)
+#define PER_FONT_MAX_SPACE (16*1024)
+
+#if SPI_FLASH_SIZE == 0x200000
+ //pic
+ //Robin_pro pic addr
+ #define PIC_NAME_ADDR 0x001000 // Pic information addr
+ #define PIC_SIZE_ADDR 0x001800 // Pic size information addr
+ #define PIC_COUNTER_ADDR 0x002000 // Pic total number
+ #define PER_PIC_SAVE_ADDR 0x000000 // Storage address of each picture
+ #define PIC_LOGO_ADDR 0x000000 // Logo addr
+ #define PIC_DATA_ADDR 0x003000 //
+
+ // TFT35
+ #define DEFAULT_VIEW_ADDR_TFT35 0x1EA070
+ #define BAK_VIEW_ADDR_TFT35 (DEFAULT_VIEW_ADDR_TFT35+90*1024)
+ #define PIC_ICON_LOGO_ADDR_TFT35 (BAK_VIEW_ADDR_TFT35+80*1024)
+ #define PIC_DATA_ADDR_TFT35 0x003000 // (PIC_ICON_LOGO_ADDR_TFT35+350*1024) //0xC5800
+
+ #define PIC_DATA_ADDR_TFT32 0x00F000
+ #define PIC_ICON_LOGO_ADDR_TFT32 0x5D8000
+ #define PIC_OTHER_SIZE_ADDR_TFT32 0x5EE000
+
+ // font
+ #define FONTINFOADDR 0x150000 // 6M -- font addr
+ #define UNIGBK_FLASH_ADDR (FONTINFOADDR+4096) // 4*1024
+
+#else
+ //pic
+ // pic addr
+ #define PIC_NAME_ADDR 0x003000 // Pic information addr
+ #define PIC_SIZE_ADDR 0x007000 // Pic size information addr
+ #define PIC_COUNTER_ADDR 0x008000 // Pic total number
+ #define PIC_LOGO_ADDR 0x009000 // Logo addr
+
+ // TFT35
+ #define DEFAULT_VIEW_ADDR_TFT35 0xC5800
+ #define BAK_VIEW_ADDR_TFT35 (DEFAULT_VIEW_ADDR_TFT35+90*1024)
+ #define PIC_ICON_LOGO_ADDR_TFT35 (BAK_VIEW_ADDR_TFT35+80*1024)
+ #define PIC_DATA_ADDR_TFT35 (PIC_ICON_LOGO_ADDR_TFT35+350*1024) //0xC5800
+
+ // TFT32
+ #define PIC_DATA_ADDR_TFT32 0x02F000
+ #define PIC_ICON_LOGO_ADDR_TFT32 0x5D8000
+ #define PIC_OTHER_SIZE_ADDR_TFT32 0x5EE000
+
+ // font
+ #define FONTINFOADDR 0x600000 // 6M -- font addr
+ #define UNIGBK_FLASH_ADDR (FONTINFOADDR+4096) // 4*1024
+ #define GBK_FLASH_ADDR (UNIGBK_FLASH_ADDR+180224) // 176*1024
+
+#endif
+
+// Flash flag
+#define REFLSHE_FLGA_ADD (0X800000-32)
+
+// SD card information first addr
+#define VAR_INF_ADDR 0x000000
+#define FLASH_INF_VALID_FLAG 0x20201118
+
+//Store some gcode commands, such as auto leveling commands
+#define GCODE_COMMAND_ADDR VAR_INF_ADDR + 3*1024
+#define AUTO_LEVELING_COMMAND_ADDR GCODE_COMMAND_ADDR
+#define OTHERS_COMMAND_ADDR_1 AUTO_LEVELING_COMMAND_ADDR + 100
+#define OTHERS_COMMAND_ADDR_2 OTHERS_COMMAND_ADDR_1 + 100
+#define OTHERS_COMMAND_ADDR_3 OTHERS_COMMAND_ADDR_2 + 100
+#define OTHERS_COMMAND_ADDR_4 OTHERS_COMMAND_ADDR_3 + 100
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+union union32 {
+ uint8_t bytes[4];
+ uint32_t dwords;
+};
+
+// pic information
+struct pic_msg {
+ uint8_t name[PIC_NAME_MAX_LEN];
+ union union32 size;
+};
+
+typedef struct pic_msg PIC_MSG;
+
+#define BMP_WRITE_BUF_LEN 512
+
+#define PICINFOADDR 0x1000
+
+#define PIC_SIZE_xM 6
+#define FONT_SIZE_xM 2
+
+extern void Pic_Read(uint8_t *Pname, uint8_t *P_Rbuff);
+extern void Pic_Logo_Read(uint8_t *LogoName,uint8_t *Logo_Rbuff,uint32_t LogoReadsize);
+extern void lv_pic_test(uint8_t *P_Rbuff, uint32_t addr, uint32_t size);
+extern uint32_t lv_get_pic_addr(uint8_t *Pname);
+extern void get_spi_flash_data(const char *rec_buf, int offset, int size);
+extern void spi_flash_read_test();
+extern void default_view_Read(uint8_t *default_view_Rbuff, uint32_t default_view_Readsize);
+extern void flash_view_Read(uint8_t *flash_view_Rbuff, uint32_t flash_view_Readsize);
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.cpp b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.cpp
new file mode 100644
index 0000000..379eb42
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.cpp
@@ -0,0 +1,250 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include <lv_conf.h>
+
+#include "../../../../gcode/gcode.h"
+#include "../../../../module/temperature.h"
+#include "../../../../module/planner.h"
+#include "../../../../module/motion.h"
+#include "../../../../sd/cardreader.h"
+#include "../../../../inc/MarlinConfig.h"
+#include "../../../../MarlinCore.h"
+#include "../../../../gcode/queue.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+extern uint32_t To_pre_view;
+extern bool flash_preview_begin, default_preview_flg, gcode_preview_over;
+void esp_port_begin(uint8_t interrupt);
+void printer_state_polling() {
+ char str_1[16];
+ if (uiCfg.print_state == PAUSING) {
+ lv_clear_cur_ui();
+ lv_draw_dialog(DIALOG_TYPE_MACHINE_PAUSING_TIPS);
+ #if ENABLED(SDSUPPORT)
+ while(queue.length) {
+ queue.advance();
+ }
+ planner.synchronize();
+ gcode.process_subcommands_now_P(PSTR("M25"));
+ //save the positon
+ uiCfg.current_x_position_bak = current_position.x;
+ uiCfg.current_y_position_bak = current_position.y;
+ uiCfg.current_z_position_bak = current_position.z;
+
+ if (gCfgItems.pausePosZ != (float)-1) {
+ gcode.process_subcommands_now_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 Z%s"), dtostrf(gCfgItems.pausePosZ, 1, 1, str_1));
+ gcode.process_subcommands_now(public_buf_l);
+ gcode.process_subcommands_now_P(PSTR("G90"));
+ }
+ if (gCfgItems.pausePosX != (float)-1) {
+ sprintf_P(public_buf_l, PSTR("G1 X%s"), dtostrf(gCfgItems.pausePosX, 1, 1, str_1));
+ gcode.process_subcommands_now(public_buf_l);
+ }
+ if (gCfgItems.pausePosY != (float)-1) {
+ sprintf_P(public_buf_l, PSTR("G1 Y%s"), dtostrf(gCfgItems.pausePosY, 1, 1, str_1));
+ gcode.process_subcommands_now(public_buf_l);
+ }
+ uiCfg.print_state = PAUSED;
+ uiCfg.current_e_position_bak = current_position.e;
+
+ gCfgItems.pause_reprint = true;
+ update_spi_flash();
+ lv_clear_cur_ui();
+ lv_draw_return_ui();
+ #endif
+ }
+
+ if (uiCfg.print_state == PAUSED) {
+ }
+
+ if (uiCfg.print_state == RESUMING) {
+ if (IS_SD_PAUSED()) {
+ if (gCfgItems.pausePosX != (float)-1) {
+ sprintf_P(public_buf_m, PSTR("G1 X%s"), dtostrf(uiCfg.current_x_position_bak, 1, 1, str_1));
+ gcode.process_subcommands_now(public_buf_m);
+ }
+ if (gCfgItems.pausePosY != (float)-1) {
+ sprintf_P(public_buf_m, PSTR("G1 Y%s"), dtostrf(uiCfg.current_y_position_bak, 1, 1, str_1));
+ gcode.process_subcommands_now(public_buf_m);
+ }
+ if (gCfgItems.pausePosZ != (float)-1) {
+ ZERO(public_buf_m);
+ sprintf_P(public_buf_m, PSTR("G1 Z%s"), dtostrf(uiCfg.current_z_position_bak, 1, 1, str_1));
+ gcode.process_subcommands_now(public_buf_m);
+ }
+ gcode.process_subcommands_now_P(M24_STR);
+ uiCfg.print_state = WORKING;
+ start_print_time();
+
+ gCfgItems.pause_reprint = false;
+ update_spi_flash();
+ }
+ }
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ if (uiCfg.print_state == REPRINTED) {
+ #if HAS_HOTEND
+ HOTEND_LOOP() {
+ const int16_t et = recovery.info.target_temperature[e];
+ if (et) {
+ #if HAS_MULTI_HOTEND
+ sprintf_P(public_buf_m, PSTR("T%i"), e);
+ gcode.process_subcommands_now(public_buf_m);
+ #endif
+ sprintf_P(public_buf_m, PSTR("M109 S%i"), et);
+ gcode.process_subcommands_now(public_buf_m);
+ }
+ }
+ #endif
+
+ recovery.resume();
+ #if 0
+ // Move back to the saved XY
+ char str_1[16], str_2[16];
+ sprintf_P(public_buf_m, PSTR("G1 X%s Y%s F2000"),
+ dtostrf(recovery.info.current_position.x, 1, 3, str_1),
+ dtostrf(recovery.info.current_position.y, 1, 3, str_2)
+ );
+ gcode.process_subcommands_now(public_buf_m);
+
+ if (gCfgItems.pause_reprint && gCfgItems.pausePosZ != -1.0f) {
+ gcode.process_subcommands_now_P(PSTR("G91"));
+ sprintf_P(public_buf_l, PSTR("G1 Z-%.1f"), gCfgItems.pausePosZ);
+ gcode.process_subcommands_now(public_buf_l);
+ gcode.process_subcommands_now_P(PSTR("G90"));
+ }
+ #endif
+ uiCfg.print_state = WORKING;
+ start_print_time();
+
+ gCfgItems.pause_reprint = false;
+ update_spi_flash();
+ }
+ #endif
+
+ if (uiCfg.print_state == WORKING)
+ filament_check();
+
+ TERN_(MKS_WIFI_MODULE, wifi_looping());
+}
+
+void filament_pin_setup() {
+ #if PIN_EXISTS(MT_DET_1)
+ SET_INPUT_PULLUP(MT_DET_1_PIN);
+ #endif
+ #if PIN_EXISTS(MT_DET_2)
+ SET_INPUT_PULLUP(MT_DET_2_PIN);
+ #endif
+ #if PIN_EXISTS(MT_DET_3)
+ SET_INPUT_PULLUP(MT_DET_3_PIN);
+ #endif
+}
+
+void filament_check() {
+ #if (PIN_EXISTS(MT_DET_1) || PIN_EXISTS(MT_DET_2) || PIN_EXISTS(MT_DET_3))
+ const int FIL_DELAY = 20;
+ #endif
+ #if PIN_EXISTS(MT_DET_1)
+ static int fil_det_count_1 = 0;
+ if (!READ(MT_DET_1_PIN) && !MT_DET_PIN_INVERTING)
+ fil_det_count_1++;
+ else if (READ(MT_DET_1_PIN) && MT_DET_PIN_INVERTING)
+ fil_det_count_1++;
+ else if (fil_det_count_1 > 0)
+ fil_det_count_1--;
+
+ if (!READ(MT_DET_1_PIN) && !MT_DET_PIN_INVERTING)
+ fil_det_count_1++;
+ else if (READ(MT_DET_1_PIN) && MT_DET_PIN_INVERTING)
+ fil_det_count_1++;
+ else if (fil_det_count_1 > 0)
+ fil_det_count_1--;
+ #endif
+
+ #if PIN_EXISTS(MT_DET_2)
+ static int fil_det_count_2 = 0;
+ if (!READ(MT_DET_2_PIN) && !MT_DET_PIN_INVERTING)
+ fil_det_count_2++;
+ else if (READ(MT_DET_2_PIN) && MT_DET_PIN_INVERTING)
+ fil_det_count_2++;
+ else if (fil_det_count_2 > 0)
+ fil_det_count_2--;
+
+ if (!READ(MT_DET_2_PIN) && !MT_DET_PIN_INVERTING)
+ fil_det_count_2++;
+ else if (READ(MT_DET_2_PIN) && MT_DET_PIN_INVERTING)
+ fil_det_count_2++;
+ else if (fil_det_count_2 > 0)
+ fil_det_count_2--;
+ #endif
+
+ #if PIN_EXISTS(MT_DET_3)
+ static int fil_det_count_3 = 0;
+ if (!READ(MT_DET_3_PIN) && !MT_DET_PIN_INVERTING)
+ fil_det_count_3++;
+ else if (READ(MT_DET_3_PIN) && MT_DET_PIN_INVERTING)
+ fil_det_count_3++;
+ else if (fil_det_count_3 > 0)
+ fil_det_count_3--;
+
+ if (!READ(MT_DET_3_PIN) && !MT_DET_PIN_INVERTING)
+ fil_det_count_3++;
+ else if (READ(MT_DET_3_PIN) && MT_DET_PIN_INVERTING)
+ fil_det_count_3++;
+ else if (fil_det_count_3 > 0)
+ fil_det_count_3--;
+ #endif
+
+ if (false
+ #if PIN_EXISTS(MT_DET_1)
+ || fil_det_count_1 >= FIL_DELAY
+ #endif
+ #if PIN_EXISTS(MT_DET_2)
+ || fil_det_count_2 >= FIL_DELAY
+ #endif
+ #if PIN_EXISTS(MT_DET_3)
+ || fil_det_count_3 >= FIL_DELAY
+ #endif
+ ) {
+ lv_clear_cur_ui();
+ TERN_(SDSUPPORT, card.pauseSDPrint());
+ stop_print_time();
+ uiCfg.print_state = PAUSING;
+
+ if (gCfgItems.from_flash_pic)
+ flash_preview_begin = true;
+ else
+ default_preview_flg = true;
+
+ lv_draw_printing();
+ }
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.h b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.h
new file mode 100644
index 0000000..f304158
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.h
@@ -0,0 +1,36 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+#define MIN_FILE_PRINTED 100 //5000
+
+extern void printer_state_polling();
+extern void filament_pin_setup();
+extern void filament_check();
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h
new file mode 100644
index 0000000..78abb21
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h
@@ -0,0 +1,751 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//****************英文***************************//
+#define MACHINE_CONFIG_EN "Config"
+
+#define NEXT_EN "Next"
+#define PREVIOUS_EN "Previous"
+#define DEFAULT_EN "Default"
+#define KEY_BACK_EN "Del"
+#define KEY_REST_EN "Reset"
+#define KEY_CONFIRM_EN "Confirm"
+
+#define KEYBOARD_KEY0_EN "0"
+#define KEYBOARD_KEY1_EN "1"
+#define KEYBOARD_KEY2_EN "2"
+#define KEYBOARD_KEY3_EN "3"
+#define KEYBOARD_KEY4_EN "4"
+#define KEYBOARD_KEY5_EN "5"
+#define KEYBOARD_KEY6_EN "6"
+#define KEYBOARD_KEY7_EN "7"
+#define KEYBOARD_KEY8_EN "8"
+#define KEYBOARD_KEY9_EN "9"
+#define KEYBOARD_KEY_POINT_EN "."
+#define KEYBOARD_KEY_NEGATIVE_EN "-"
+
+#define MACHINE_PARA_TITLE_EN "Config"
+#define MACHINE_TYPE_CNOFIG_EN "Machine settings"
+#define MOTOR_CONFIG_EN "Motor settings"
+#define MACHINE_LEVELING_CONFIG_EN "Leveling settings"
+#define ADVANCE_CONFIG_EN "Advanced settings"
+
+#define MACHINE_CONFIG_TITLE_EN "Machine Settings"
+#define MACHINE_TYPE_EN "Machine type"
+#define MACHINE_STROKE_EN "Machine Size"
+#define MACHINE_HOMEDIR_EN "Home direction"
+#define MACHINE_ENDSTOP_TYPE_EN "Endstop type"
+#define MACHINE_FILAMENT_CONFIG_EN "Filament settings"
+
+#define MACHINE_TYPE_CONFIG_TITLE_EN "Machine Settings>Machine type"
+#define MACHINE_TYPE_XYZ_EN "XYZ Machine"
+#define MACHINE_TYPE_DELTA_EN "Delta Machine"
+#define MACHINE_TYPE_COREXY_EN "Corexy Machine"
+
+#define MACHINE_STROKE_CONF_TITLE_EN "Machine Settings>Machine Size"
+#define X_MAX_LENGTH_EN "X-axis maximum stroke"
+#define Y_MAX_LENGTH_EN "Y-axis maximum stroke"
+#define Z_MAX_LENGTH_EN "Z-axis maximum stroke"
+
+#define X_MIN_LENGTH_EN "X-axis minimum stroke"
+#define Y_MIN_LENGTH_EN "Y-axis minimum stroke"
+#define Z_MIN_LENGTH_EN "Z-axis minimum stroke"
+
+#define HOME_DIR_CONF_TITLE_EN "Machine Settings>Home direction"
+#define HOME_DIR_X_EN "X-axis home direction"
+#define HOME_DIR_Y_EN "Y-axis home direction"
+#define HOME_DIR_Z_EN "Z-axis home direction"
+#define HOME_MIN_EN "MIN"
+#define HOME_MAX_EN "MAX"
+
+#define ENDSTOP_CONF_TITLE_EN "Machine Settings>Endstop type"
+#define MIN_ENDSTOP_X_EN "X-axis minimum Endstop"
+#define MIN_ENDSTOP_Y_EN "Y-axis minimum Endstop"
+#define MIN_ENDSTOP_Z_EN "Z-axis minimum Endstop"
+#define MAX_ENDSTOP_X_EN "X-axis maximum Endstop"
+#define MAX_ENDSTOP_Y_EN "Y-axis maximum Endstop"
+#define MAX_ENDSTOP_Z_EN "Z-axis maximum Endstop"
+#define ENDSTOP_FIL_EN "Filament sensor"
+#define ENDSTOP_LEVEL_EN "Leveling sensor"
+#define ENDSTOP_OPENED_EN "Open"
+#define ENDSTOP_CLOSED_EN "Close"
+
+#define FILAMENT_CONF_TITLE_EN "Machine Settings>Filament settings"
+#define FILAMENT_IN_LENGTH_EN "Load length"
+#define FILAMENT_IN_SPEED_EN "Load speed"
+#define FILAMENT_TEMPERATURE_EN "Filament temperature"
+#define FILAMENT_OUT_LENGTH_EN "Unload length"
+#define FILAMENT_OUT_SPEED_EN "Unload speed"
+
+#define LEVELING_CONF_TITLE_EN "Machine Settings>Leveling settings"
+#define LEVELING_PARA_CONF_EN "Leveling settings"
+#define LEVELING_MANUAL_POS_EN "Manual leveling coordinate settings"
+#define LEVELING_AUTO_COMMAND_EN "AutoLeveling command settings"
+#define LEVELING_AUTO_ZOFFSET_EN "Nozzle-to-probe offsets settings"
+#define LEVELING_TOUCHMI_EN "Settings-TouchMi-Probe"
+#define TM_INIT_EN "Init"
+#define TM_ZOFFSETPOS_EN "Zoffset+"
+#define TM_ZOFFSETNEG_EN "Zoffset-"
+#define TM_SAVE_EN "Save"
+#define TM_TEST_EN "Test"
+
+#define BLTOUCH_LEVELING_TITTLE_EN "Machine Settings>BL-Touch Probe"
+#define BLTOUCH_LEVELING_EN "BL-Touch Probe"
+#define BLTOUCH_INIT_EN "Init"
+#define BLTOUCH_ZOFFSETPOS_EN "Zoffset+"
+#define BLTOUCH_ZOFFSETNEG_EN "Zoffset-"
+#define BLTOUCH_SAVE_EN "Save"
+#define BLTOUCH_TEST_EN "Test"
+
+#define LEVELING_PARA_CONF_TITLE_EN "leveling setting"
+#define AUTO_LEVELING_ENABLE_EN "Enable auto leveling"
+#define BLTOUCH_LEVELING_ENABLE_EN "Enable BLtouch"
+#define PROBE_PORT_EN "Probe connector"
+#define PROBE_X_OFFSET_EN "Probe X-axis offset"
+#define PROBE_Y_OFFSET_EN "Probe Y-axis offset"
+#define PROBE_Z_OFFSET_EN "Probe Z-axis offset"
+#define PROBE_XY_SPEED_EN "Probe XY-axis speed"
+#define PROBE_Z_SPEED_EN "Probe Z-axis speed"
+#define ENABLE_EN "YES"
+#define DISABLE_EN "NO"
+#define LOCKED_EN "N/A"
+#define Z_MIN_EN "ZMin"
+#define Z_MAX_EN "ZMax"
+
+#define DELTA_LEVEL_CONF_TITLE_EN "Delta Machine settings"
+#define DELTA_LEVEL_CONF_EN "Delta Machine Leveling"
+#define DELTA_MACHINE_RADIUS_EN "Machine Radius"
+#define DELTA_DIAGONAL_ROD_EN "Machine rod length"
+#define DELTA_PRINT_RADIUS_EN "Print radius"
+#define DELTA_HEIGHT_EN "Print height"
+#define SMOOTH_ROD_OFFSET_EN "Slider offset"
+#define EFFECTOR_OFFSET_EN "Effector offset"
+#define CALIBRATION_RADIUS_EN "Leveling radius"
+
+#define XYZ_LEVEL_CONF_TITLE_EN "Cartesian Machine Settings"
+#define PROBE_REACH_MAX_LEFT_EN "Probe reaches leftmost position"
+#define PROBE_REACH_MAX_RIGHT_EN "Probe reaches rightmost position"
+#define PROBE_REACH_MAX_FRONT_EN "Probe reaches front position"
+#define PROBE_REACH_MAX_BACK_EN "Probe reaches final position"
+
+#define TEMPERATURE_CONF_TITLE_EN "Machine Settings>Temperature settings"
+#define NOZZLE_CONF_EN "Nozzle settings"
+#define HOTBED_CONF_EN "Hotbed settings"
+#define PREHEAT_TEMPER_EN "Preset temperature"
+
+#define NOZZLE_CONF_TITLE_EN "Machine Settings>Nozzle settings"
+#define NOZZLECNT_EN "Number of nozzles"
+#define NOZZLE_TYPE_EN "E0 Temperature type"
+#define NOZZLE_ADJUST_TYPE_EN "PID thermostat"
+#define NOZZLE_MIN_TEMPERATURE_EN "lowest temperature"
+#define NOZZLE_MAX_TEMPERATURE_EN "Maximum temperature"
+#define EXTRUD_MIN_TEMPER_EN "Minimum extrusion temperature"
+
+#define HOTBED_CONF_TITLE_EN "Machine Settings>Hotbed settings"
+#define HOTBED_ADJUST_EN "PID thermostat"
+#define HOTBED_MIN_TEMPERATURE_EN "lowest temperature"
+#define HOTBED_MAX_TEMPERATURE_EN "Maximum temperature"
+
+#define MOTOR_CONF_TITLE_EN "Machine Settings>Motor settings"
+#define MAXFEEDRATE_CONF_EN "Maximum speed settings"
+#define ACCELERATION_CONF_EN "Acceleration settings"
+#define JERKCONF_EN "Jerk settings"
+#define STEPSCONF_EN "Steps settings"
+#define TMC_CURRENT_EN "TMC Current settings"
+#define TMC_STEP_MODE_EN "TMC Step mode settings"
+#define MOTORDIRCONF_EN "Motor direction settings"
+#define HOMEFEEDRATECONF_EN "Home speed setting"
+
+#define MAXFEEDRATE_CONF_TITLE_EN "Machine Settings>Maximum speed"
+#define X_MAXFEEDRATE_EN "X-axis maximum speed"
+#define Y_MAXFEEDRATE_EN "Y-axis maximum speed"
+#define Z_MAXFEEDRATE_EN "Z-axis maximum speed"
+#define E0_MAXFEEDRATE_EN "E0 maximum speed"
+#define E1_MAXFEEDRATE_EN "E1 maximum speed"
+
+#define ACCELERATION_CONF_TITLE_EN "Machine Settings>Acceleration"
+#define PRINT_ACCELERATION_EN "Print acceleration"
+#define RETRACT_ACCELERATION_EN "Retraction acceleration"
+#define TRAVEL_ACCELERATION_EN "Travel acceleration"
+#define X_ACCELERATION_EN "X-axis acceleration"
+#define Y_ACCELERATION_EN "Y-axis acceleration"
+#define Z_ACCELERATION_EN "Z-axis acceleration"
+#define E0_ACCELERATION_EN "E0 acceleration"
+#define E1_ACCELERATION_EN "E1 acceleration"
+
+#define JERK_CONF_TITLE_EN "Machine Settings>Jerk speed"
+#define X_JERK_EN "X-axis jerk speed"
+#define Y_JERK_EN "Y-axis jerk speed"
+#define Z_JERK_EN "Z-axis jerk speed"
+#define E_JERK_EN "Extruder jerk speed"
+
+#define STEPS_CONF_TITLE_EN "Machine Settings>Steps settings"
+#define X_STEPS_EN "X-axis steps"
+#define Y_STEPS_EN "Y-axis steps"
+#define Z_STEPS_EN "Z-axis steps"
+#define E0_STEPS_EN "E0 steps"
+#define E1_STEPS_EN "E1 steps"
+
+#define TMC_CURRENT_CONF_TITLE_EN "Machine Settings>TMC current settings"
+#define X_TMC_CURRENT_EN "X-axis current (mA)"
+#define Y_TMC_CURRENT_EN "Y-axis current (mA)"
+#define Z_TMC_CURRENT_EN "Z-axis current (mA)"
+#define E0_TMC_CURRENT_EN "E0 current (mA)"
+#define E1_TMC_CURRENT_EN "E1 current (mA)"
+
+#define TMC_MODE_CONF_TITLE_EN "Machine Settings>TMC step mode settings"
+#define X_TMC_MODE_EN "Whether X-axis enables stealthChop mode"
+#define Y_TMC_MODE_EN "Whether Y-axis enables stealthChop mode"
+#define Z_TMC_MODE_EN "Whether Z-axis enables stealthChop mode"
+#define E0_TMC_MODE_EN "Whether E0 enables stealthChop mode"
+#define E1_TMC_MODE_EN "Whether E1 enables stealthChop mode"
+
+#define MOTORDIR_CONF_TITLE_EN "Machine Settings>Motor direction"
+#define X_MOTORDIR_EN "X-axis motor direction invert"
+#define Y_MOTORDIR_EN "Y-axis motor direction invert"
+#define Z_MOTORDIR_EN "Z-axis motor direction invert"
+#define E0_MOTORDIR_EN "E0 motor direction invert"
+#define E1_MOTORDIR_EN "E1 motor direction invert"
+#define INVERT_P_EN "YES"
+#define INVERT_N_EN "NO"
+
+#define HOMEFEEDRATE_CONF_TITLE_EN "Machine Settings>Home speed"
+#define X_HOMESPEED_EN "XY-axis home speed"
+#define Y_HOMESPEED_EN "Y-axis home speed"
+#define Z_HOMESPEED_EN "Z-axis home speed"
+
+#define ADVANCED_CONF_TITLE_EN "Machine Settings>Advance"
+#define PWROFF_DECTION_EN "power off dection module"
+#define PWROFF_AFTER_PRINT_EN "Auto Shutdown after print"
+#define HAVE_UPS_EN "Has UPS power supply"
+#define Z2_AND_Z2ENDSTOP_CONF_EN "Z2 Settings"
+#define ENABLE_PINS_CONF_EN "Enable pins level settings"
+#define WIFI_SETTINGS_EN "Wi-Fi parameter settings"
+#define HOMING_SENSITIVITY_CONF_EN "Homing sensitivity settings"
+#define ENCODER_SETTINGS_EN "Rotary encoder settings"
+
+#define Z2_AND_Z2ENDSTOP_CONF_TITLE_EN "Z2 Settings"
+#define Z2_ENABLE_EN "Z2 Enable"
+#define Z2_ENDSTOP_EN "Z2_EndStop Enable"
+#define Z2_PORT_EN "Z2 Connector"
+
+#define ENABLE_PINS_CONF_TITLE_EN "ENABLE_PINS_LEVEL"
+#define X_ENABLE_PINS_INVERT_EN "X_ENABLE_PIN_INVERT"
+#define Y_ENABLE_PINS_INVERT_EN "Y_ENABLE_PIN_INVERT"
+#define Z_ENABLE_PINS_INVERT_EN "Z_ENABLE_PIN_INVERT"
+#define E_ENABLE_PINS_INVERT_EN "E_ENABLE_PIN_INVERT"
+
+#define PAUSE_POSITION_EN "Printing pause position settings"
+#define PAUSE_POSITION_X_EN "X-axis position (Absolute position,-1 invalid)"
+#define PAUSE_POSITION_Y_EN "Y-axis position (Absolute position,-1 invalid)"
+#define PAUSE_POSITION_Z_EN "Z-axis position (Relative position,-1 invalid)"
+
+#define WIFI_SETTINGS_TITLE_EN "Machine Settings>Wi-Fi Parameter"
+#define WIFI_SETTINGS_MODE_EN "Wi-Fi Mode"
+#define WIFI_SETTINGS_NAME_EN "Wi-Fi Name: "
+#define WIFI_SETTINGS_PASSWORD_EN "Wi-Fi Password: "
+#define WIFI_SETTINGS_CLOUD_EN "Do you use cloud services?"
+#define WIFI_SETTINGS_CONFIG_EN "Config"
+#define WIFI_SETTINGS_EDIT_EN "Edit"
+#define WIFI_CONFIG_TIPS_EN "Wi-Fi configuration?"
+
+#define OFFSET_TITLE_EN "Machine Settings>Offset"
+#define OFFSET_X_EN "X offset"
+#define OFFSET_Y_EN "Y offset"
+#define OFFSET_Z_EN "Z offset"
+
+#define HOMING_SENSITIVITY_CONF_TITLE_EN "Machine Settings>Sensitivity"
+#define X_SENSITIVITY_EN "X-axis sensitivity"
+#define Y_SENSITIVITY_EN "Y-axis sensitivity"
+#define Z_SENSITIVITY_EN "Z-axis sensitivity"
+#define Z2_SENSITIVITY_EN "Z2-axis sensitivity"
+
+#define ENCODER_CONF_TITLE_EN "Machine Settings>Rotary encoder settings"
+#define ENCODER_CONF_TEXT_EN "Is the encoder function used?"
+
+#define TOOL_TEXT_EN "Tool"
+#define PREHEAT_TEXT_EN "Preheat"
+#define MOVE_TEXT_EN "Move"
+#define HOME_TEXT_EN "Home"
+#define PRINT_TEXT_EN "Printing"
+#define EXTRUDE_TEXT_EN "Extrusion"
+#define LEVELING_TEXT_EN "Leveling"
+#define AUTO_LEVELING_TEXT_EN "AutoLevel"
+#define SET_TEXT_EN "Settings"
+#define MORE_TEXT_EN "More"
+
+#define ADD_TEXT_EN "Add"
+#define DEC_TEXT_EN "Dec"
+#define EXTRUDER_1_TEXT_EN "Extrusion1"
+#define EXTRUDER_2_TEXT_EN "Extrusion2"
+#define HEATBED_TEXT_EN "HeatBed"
+#define TEXT_1C_EN "1℃"
+#define TEXT_5C_EN "5℃"
+#define TEXT_10C_EN "10℃"
+#define CLOSE_TEXT_EN "Close"
+
+#define BACK_TEXT_EN "Back"
+
+#define TOOL_PREHEAT_EN "Preheat"
+#define TOOL_EXTRUDE_EN "Extrusion"
+#define TOOL_MOVE_EN "Move"
+#define TOOL_HOME_EN "Home"
+#define TOOL_LEVELING_EN "Leveling"
+#define TOOL_AUTO_LEVELING_EN "AutoLevel"
+#define TOOL_FILAMENT_EN "Filament"
+#define TOOL_MORE_EN "More"
+
+#define AXIS_X_ADD_TEXT_EN "X+"
+#define AXIS_X_DEC_TEXT_EN "X-"
+#define AXIS_Y_ADD_TEXT_EN "Y+"
+#define AXIS_Y_DEC_TEXT_EN "Y-"
+#define AXIS_Z_ADD_TEXT_EN "Z+"
+#define AXIS_Z_DEC_TEXT_EN "Z-"
+#define TEXT_01MM_EN "0.1mm"
+#define TEXT_1MM_EN "1mm"
+#define TEXT_10MM_EN "10mm"
+
+#define HOME_X_TEXT_EN "X"
+#define HOME_Y_TEXT_EN "Y"
+#define HOME_Z_TEXT_EN "Z"
+#define HOME_ALL_TEXT_EN "Home"
+#define HOME_STOPMOVE_EN "Quickstop"
+
+#define PAGE_UP_TEXT_EN "Page up"
+#define PAGE_DOWN_TEXT_EN "Page down"
+
+#define EXTRUDER_IN_TEXT_EN "In"
+#define EXTRUDER_OUT_TEXT_EN "Out"
+#define EXTRUDE_1MM_TEXT_EN "1mm"
+#define EXTRUDE_5MM_TEXT_EN "5mm"
+#define EXTRUDE_10MM_TEXT_EN "10mm"
+#define EXTRUDE_LOW_SPEED_TEXT_EN "Low"
+#define EXTRUDE_MEDIUM_SPEED_TEXT_EN "Normal"
+#define EXTRUDE_HIGH_SPEED_TEXT_EN "High"
+
+#define LEVELING_POINT1_TEXT_EN "Point1"
+#define LEVELING_POINT2_TEXT_EN "Point2"
+#define LEVELING_POINT3_TEXT_EN "Point3"
+#define LEVELING_POINT4_TEXT_EN "Point4"
+#define LEVELING_POINT5_TEXT_EN "Point5"
+
+#define FILESYS_TEXT_EN "FileSys"
+#define WIFI_TEXT_EN "WiFi"
+#define FAN_TEXT_EN "Fan"
+#define ABOUT_TEXT_EN "About"
+#define BREAK_POINT_TEXT_EN "Continue"
+#define FILAMENT_TEXT_EN "Filament"
+#define LANGUAGE_TEXT_EN "Language"
+#define MOTOR_OFF_TEXT_EN "Motor-off"
+#define MOTOR_OFF_XY_TEXT_EN "Off-XY"
+#define SHUTDOWN_TEXT_EN "Shutdown"
+#define MACHINE_PARA_EN "Config"
+#define EEPROM_SETTINGS_EN "Eeprom Set"
+
+#define U_DISK_TEXT_EN "USB"
+#define SD_CARD_TEXT_EN "SD"
+#define WIFI_NAME_TEXT_EN "WiFi: "
+#define WIFI_KEY_TEXT_EN "Key: "
+#define WIFI_IP_TEXT_EN "IP: "
+#define WIFI_AP_TEXT_EN "State: AP"
+#define WIFI_STA_TEXT_EN "State: STA"
+#define WIFI_CONNECTED_TEXT_EN "Connected"
+#define WIFI_DISCONNECTED_TEXT_EN "Disconnected"
+#define WIFI_EXCEPTION_TEXT_EN "Exception"
+#define WIFI_RECONNECT_TEXT_EN "Reconnect"
+#define CLOUD_TEXT_EN "Cloud"
+#define CLOUD_BIND_EN "Bind"
+#define CLOUD_UNBIND_EN "Unbind"
+#define CLOUD_UNBINDING_EN "Unbinding"
+#define CLOUD_DISCONNECTED_EN "Disconnected"
+#define CLOUD_UNBINDED_EN "Unbinded"
+#define CLOUD_BINDED_EN "Binded"
+#define CLOUD_DISABLE_EN "Disable"
+
+#define FAN_ADD_TEXT_EN "Add"
+#define FAN_DEC_TEXT_EN "Dec"
+#define FAN_OPEN_TEXT_EN "100%"
+#define FAN_HALF_TEXT_EN "50%"
+#define FAN_CLOSE_TEXT_EN "Close"
+#define FAN_TIPS1_TEXT_EN "FAN"
+#define FAN_TIPS2_TEXT_EN "FAN\nClose"
+
+#define FILAMENT_IN_TEXT_EN "Load"
+#define FILAMENT_OUT_TEXT_EN "Unload"
+#define FILAMENT_EXT0_TEXT_EN "Extrusion1"
+#define FILAMENT_EXT1_TEXT_EN "Extrusion2"
+#define FILAMENT_HEAT_TEXT_EN "Preheat"
+#define FILAMENT_STOP_TEXT_EN "Stop"
+#define FILAMENT_TIPS2_TEXT_EN "T:"
+#define FILAMENT_TIPS3_TEXT_EN "Loading..."
+#define FILAMENT_TIPS4_TEXT_EN "Unloading..."
+#define FILAMENT_TIPS5_TEXT_EN "Temp is too low to go,please heat"
+#define FILAMENT_TIPS6_TEXT_EN "Completed"
+
+#define FILAMENT_CHANGE_TEXT_EN "Please click <Load> \nor <unload>,After \npinter pause."
+#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_EN "Heating up the nozzle,\nplease wait..."
+#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_EN "Heating up the nozzle,\nplease wait..."
+#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_EN "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading."
+#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_EN "Please load filament to extruder,\nand click <confirm> for start loading."
+#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_EN "Heat completed,please \nclick <confirm> for start unloading.!"
+#define FILAMENT_DIALOG_LOADING_TIPS_EN "Is loading ,please wait!"
+#define FILAMENT_DIALOG_UNLOADING_TIPS_EN "Is unloading,please wait!"
+#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_EN "Load filament completed,\nclick <confirm> for return!"
+#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_EN "Unload filament completed,\nclick <confirm> for return!"
+
+
+#define PRE_HEAT_EXT_TEXT_EN "E"
+#define PRE_HEAT_BED_TEXT_EN "Bed"
+
+#define FILE_LOADING_EN "Loading......"
+#define NO_FILE_AND_CHECK_EN " No files found!\n Check the file system configuration!"
+
+#define NO_FILE_EN "No files found!"
+
+#define EXTRUDER_TEMP_TEXT_EN "Temper"
+#define EXTRUDER_E_LENGTH1_TEXT_EN "Extrusion1"
+#define EXTRUDER_E_LENGTH2_TEXT_EN "Extrusion2"
+#define EXTRUDER_E_LENGTH3_TEXT_EN "Extrusion3"
+
+#define ABOUT_TYPE_TEXT_EN "Type: "
+#define ABOUT_VERSION_TEXT_EN "Firmware: "
+#define ABOUT_WIFI_TEXT_EN "WiFi: "
+
+#define PRINTING_OPERATION_EN "Option"
+#define PRINTING_PAUSE_EN "Pause"
+#define PRINTING_TEMP_EN "Temp."
+#define PRINTING_CHANGESPEED_EN "Speed"
+#define PRINTING_RESUME_EN "Resume"
+#define PRINTING_STOP_EN "Stop"
+#define PRINTING_MORE_EN "More"
+#define PRINTING_EXTRUDER_EN "Extrusion"
+#define PRINTING_MOVE_EN "Move"
+
+#define EXTRUDER_SPEED_EN "Extrusion"
+#define MOVE_SPEED_EN "Move"
+#define EXTRUDER_SPEED_STATE_EN "Extrude Speed"
+#define MOVE_SPEED_STATE_EN "Move Speed"
+#define STEP_1PERCENT_EN "1%"
+#define STEP_5PERCENT_EN "5%"
+#define STEP_10PERCENT_EN "10%"
+
+#define TITLE_READYPRINT_EN "ReadyPrint"
+#define TITLE_PREHEAT_EN "Preheat"
+#define TITLE_MOVE_EN "Move"
+#define TITLE_HOME_EN "Home"
+#define TITLE_EXTRUDE_EN "Extrusion"
+#define TITLE_LEVELING_EN "Leveling"
+#define TITLE_SET_EN "Settings"
+#define TITLE_MORE_EN "More"
+#define TITLE_CHOOSEFILE_EN "ChooseFile"
+#define TITLE_PRINTING_EN "Printing"
+#define TITLE_OPERATION_EN "Operation"
+#define TITLE_ADJUST_EN "Adjust"
+#define TITLE_WIRELESS_EN "Wireless"
+#define TITLE_FILAMENT_EN "Filament"
+#define TITLE_ABOUT_EN "About"
+#define TITLE_FAN_EN "Fan"
+#define TITLE_LANGUAGE_EN "Language"
+#define TITLE_PAUSE_EN "Pause"
+#define TITLE_CHANGESPEED_EN "Speed"
+#define TITLE_CLOUD_TEXT_EN "Cloud"
+#define TITLE_DIALOG_CONFIRM_EN "Confirm"
+#define TITLE_FILESYS_EN "FileSys"
+
+#define AUTO_SHUTDOWN_EN "Auto"
+#define MANUAL_SHUTDOWN_EN "Manual"
+
+#define DIALOG_CONFIRM_EN "Confirm"
+#define DIALOG_CANCLE_EN "Cancel"
+#define DIALOG_OK_EN "OK"
+#define DIALOG_RESET_EN "Reset"
+#define DIALOG_RETRY_EN "Retry"
+#define DIALOG_DISABLE_EN "Disable"
+#define DIALOG_PRINT_MODEL_EN "Print this model?"
+#define DIALOG_CANCEL_PRINT_EN "Stop print?"
+#define DIALOG_RETRY_EN "Retry"
+#define DIALOG_STOP_EN "Stop"
+#define DIALOG_REPRINT_FROM_BREAKPOINT_EN "Reprint from breakpoint?"
+#define DIALOG_ERROR_TIPS1_EN "Error:no file,please check it again."
+#define DIALOG_ERROR_TIPS2_EN "Error:transaction failed.please check display baudrate \nwhether as the same as mainboard!"
+#define DIALOG_ERROR_TIPS3_EN "Error:file name or path is too long!"
+#define DIALOG_CLOSE_MACHINE_EN "Closing machine......"
+#define DIALOG_UNBIND_PRINTER_EN "Unbind the printer?"
+#define DIALOG_FILAMENT_NO_PRESS_EN "Filament detection switch is not pressed"
+#define DIALOG_PRINT_FINISH_EN "Done print!"
+#define DIALOG_PRINT_TIME_EN "Print time: "
+#define DIALOG_REPRINT_EN "Print again"
+#define DIALOG_WIFI_ENABLE_TIPS_EN "The wifi module is being configured\nplease wait a moment....."
+#define DIALOG_PAUSING_TIPS_EN "The machine pauses..."
+
+#define HOTBED_ENABLE_EN "Enable heatbed"
+#define MOTOR_EN_HIGH_LEVEL_EN "High"
+#define MOTOR_EN_LOW_LEVEL_EN "Low"
+
+#define TEXT_WIFI_MENU_TITLE_EN "WI-FI"
+#define TEXT_WIFI_SAPCE_EN "space"
+#define TEXT_WIFI_LETTER_EN "abc"
+#define TEXT_WIFI_DIGITAL_EN "123"
+#define TEXT_WIFI_SYMBOL_EN "#+="
+#define TEXT_WIFI_PASSWORD_EN "Password"
+
+#define TEXT_WIFI_JOINING_EN "Joining Network..."
+#define TEXT_WIFI_FAILED_JOIN_EN "Failed to Join Wi-Fi"
+#define TEXT_WIFI_WIFI_CONECTED_EN "Wi-Fi Connected"
+
+#define TEXT_BUTTON_DISCONECTED_EN "Disconnect"
+#define TEXT_WIFI_FORGET_EN "Forget Network"
+#define TEXT_DISCONECTED_EN "Wi-Fi Connected"
+
+//wifi-list
+#define MAIN_BUILT_EN "Build"
+#define MAIN_FILAMENT_EN "Filament"
+#define MAIN_SETUP_EN "Setup"
+#define MAIN_ABOUT_EN "About"
+#define MAIN_MENU_EN "Menu"
+#define FILE_MENU_BUILD_EN "Build"
+#define FILE_MENU_MENU_EN " < Menu"
+
+//about
+#define ABOUT_TITLE_EN "About"
+#define ABOUT_BUILT_MACHINES_EN "Built Machines"
+#define ABOUT_SPARK_EN "Spark"
+#define ABOUT_VERSION_EN "Version 1.1.0"
+#define ABOUT_SERIAL_NUMBER_EN "Serial Number:"
+#define ABOUT_S_NUMBER_EN "DCPLX02KFC6P"
+
+//set
+#define SETUP_TITLE_EN "Setup"
+#define SETUP_WIFI_EN "Wi-Fi"
+#define SETUP_MANUAL_IP_EN "Manual IP"
+#define SETUP_WIFI_NOT_CONNECTED_EN "Not Connected"
+#define SETUP_WIFI_NETWORK_EN "WiFi_Network"
+
+//build
+#define BUILD_TITLE_EN "Build"
+#define BUILD_SD_CARD_EN "SD Card"
+#define BUILD_USB_DRIVE_EN "USB Drive"
+
+//SD card
+#define SD_CARD_TITLE_EN "SD Card"
+#define SD_CARD_BACK_EN "< Back"
+//USB Drive
+#define USB_DRIVE_TITLE_EN "USB Drive"
+#define USB_DRIVE_BACK_EN "< Back"
+#define FILE_PAGES_EN "%d/%d"
+#define FILE_NEXT_PAGE_EN "Next Page"
+
+//BUILD PLATE
+#define PLATE_TITLE_EN "Build Plate"
+#define PLATE_BACK_EN "< Back"
+#define PLATE_CONFIRM_EN "Confirm >"
+#define PLATE_TIPS_EN "Confirm that there is a Clear\nBuild Plate installed in the\nmachine."
+
+//build model
+#define MODEL_TITLE_EN "Build Model"
+#define MODEL_START_BUILD_EN "Start Build"
+#define MODEL_BACK_EN "< Back"
+
+//building
+#define BUILDING_TITLE_EN "Building"
+#define BUILDING_MENU_EN "Build Menu"
+#define BUILDING_COMPLETED "Build\nComplete"
+
+//building menu
+#define BUILDING_MENU_TITLE_EN "Build Menu"
+#define BUILDING_MENU_SETTINGS_EN "Build Settings"
+#define BUILDING_MENU_PAUSE_EN "Pause Build"
+#define BUILDING_MENU_CANCEL_EN "Cancel Build"
+#define BUILDING_MENU_BACK_EN "< Back"
+
+//build settings
+#define SETTINGS_TITLE_EN "Build Settings"
+#define SETTINGS_NOZZLE_TEMPER_EN "Nozzle Temp:"
+#define SETTINGS_NOZZLE_VALUE_EN "%d"
+#define SETTINGS_BED_TEMPER_EN "Bed Temp:"
+#define SETTINGS_BED_VALUE_EN "%d"
+#define SETTINGS_BUILD_SPEED_EN "Build Speed:"
+#define SETTINGS_SPEED_VALUE_EN "Standard"
+#define SETTINGS_BACK_EN "< Back"
+
+//build paused
+#define PAUSED_TITLE_EN "Build Paused"
+#define PAUSED_RESUME_EN "Resume Build"
+#define PAUSED_CANCEL_EN "Cancel Build"
+#define PAUSED_BACK_EN "< Back"
+
+//build cancel
+#define CANCEL_TITLE_EN "Cancel Build"
+#define CANCEL_BUILD_EN "Cancel Build"
+#define CANCEL_TIPS_EN "Are you sure you want to\ncancel this build? The model\nwill be deleted from this\nmachine. It will need to be\nresent from your computer\nbefore it can be built in the\nfuture."
+#define CANCEL_BACK_EN "< Back"
+#define CANCEL_BUILD_DISPLAY_EN "Build\nCanceled"
+#define CANCEL_OVER_PLATE_TIPS_EN "Confirm that the Build Plate\nhas been removed from the\nmachine."
+
+//filament model enter
+#define FILAMENT_MODEL_ENTER_TITLE_EN "Model-PLA"
+#define FILAMENT_MODEL_ENTER_BACK_EN "< Back"
+#define FILAMENT_MODEL_ENTER_BEGIN_EN "Begin >"
+#define FILAMENT_MODEL_ENTER_TIPS_EN "The Model Filament spool\ncompartment is located on\nthe right side of the machine."
+
+//filament model PLA
+#define FILAMENT_MODEL_PLA_TITLE_EN "Model-PLA"
+#define FILAMENT_PLA_LOAD_TITLE_EN "Load Filament"
+#define FILAMENT_PLA_UNLOAD_TITLE_EN "Unload Filament"
+#define FILAMENT_MODEL_PLA_LOAD_EN "Load Filament"
+#define FILAMENT_MODEL_PLA_UNLOAD_EN "Unload Filament"
+//filament support enter
+#define FILAMENT_SUPPORT_ENTER_TITLE_EN "Support-PVA"
+#define FILAMENT_SUPPORT_ENTER_BACK_EN "< Back"
+#define FILAMENT_SUPPORT_ENTER_BEGIN_EN "Begin >"
+#define FILAMENT_SUPPORT_ENTER_TIPS_EN "The Support Filament spool\ncompartment is located on\nthe left side of the machine."
+//filament heating
+#define FILAMENT_HEATING_LOAD_TITLE_EN "Load Filament"
+#define FILAMENT_HEATING_UNLOAD_TITLE_EN "Unload Filament"
+#define FILAMENT_HEATING_CANCEL_EN "< Cancel"
+#define FILAMENT_HEATING_MATERIAL_EN "Material:"
+#define FILAMENT_HEATING_PLA_EN "Model-PLA"
+#define FILAMENT_HEATING_TIPS_EN "Print head is heating..."
+//rotate left
+#define ROTATE_LEFT_LOAD_TITLE_EN "Load Filament"
+#define ROTATE_LEFT_UNLOAD_TITLE_EN "Unload Filament"
+#define ROTATE_LEFT_CANCEL_EN "< Cancel"
+#define ROTATE_LEFT_MATERIAL_EN "Material:"
+#define ROTATE_LEFT_PLA_EN "Model-PLA"
+#define ROTATE_LEFT_NEXT_EN "Next >"
+#define ROTATE_LEFT_TIPS_EN "Rotate extruder selection\ndial to the left."
+
+//hang spool
+#define HANG_SPOOL_TITLE_EN "Load Filament"
+#define HANG_SPOOL_PREVIOUS_EN "< Previous"
+#define HANG_SPOOL_MATERIAL_EN "Material:"
+#define HANG_SPOOL_PLA_EN "Model-PLA"
+#define HANG_SPOOL_NEXT_EN "Next >"
+#define HANG_SPOOL_TIPS_EN "Hang the spool in the spool\ncompartment as shown."
+
+//feed filament
+#define FEED_FILAMENT_TITLE_EN "Load Filament"
+#define FEED_FILAMENT_PREVIOUS_EN "< Previous"
+#define FEED_FILAMENT_MATERIAL_EN "Material:"
+#define FEED_FILAMENT_PLA_EN "Model-PLA"
+#define FEED_FILAMENT_NEXT_EN "Next >"
+#define FEED_FILAMENT_TIPS_EN "Feed filament into extruder\nup beyond the gears."
+
+//feed filament
+#define ROTATE_UP_TITLE_EN "Load Filament"
+#define ROTATE_UP_PREVIOUS_EN "< Previous"
+#define ROTATE_UP_MATERIAL_EN "Material:"
+#define ROTATE_UP_PLA_EN "Model-PLA"
+#define ROTATE_UP_NEXT_EN "Next >"
+#define ROTATE_UP_TIPS_EN "Rotate extruder selection\ndial up."
+
+//filament begin
+#define FEED_BEGIN_TITLE_EN "Load Filament"
+#define FEED_BEGIN_MATERIAL_EN "Material:"
+#define FEED_BEGIN_PLA_EN "Model-PLA"
+#define FEED_BEGIN_NEXT_EN "Next >"
+#define FEED_BEGIN_TIPS_EN "Press Next when filament\nbegins to extrude."
+
+//filament finish
+#define FEED_FINISH_TITLE_EN "Load Filament"
+#define FEED_FINISH_MATERIAL_EN "Material:"
+#define FEED_FINISH_PLA_EN "Model-PLA"
+#define FEED_FINISH_NEXT_EN "Finish >"
+#define FEED_FINISH_TIPS_EN "Remove filament from the\nnozzle and discard."
+//fiament remove
+#define REMOVE_SPOOL_TITLE_EN "Unload Filament"
+#define REMOVE_SPOOL_PREVIOUS_EN "< Previous"
+#define REMOVE_SPOOL_FINISH_EN "Finish >"
+#define REMOVE_SPOOL_MATERIAL_EN "Material:"
+#define REMOVE_SPOOL_PLA_EN "Model-PLA"
+#define REMOVE_SPOOL_TIPS_EN "Remove the spool and pull\nfilament out of the machine."
+
+#define FILAMENT_SUPPORT_PVA_EN "Support-PVA"
+#define LOAD_FINISH_EN "Load\nFilament\nComplete"
+#define UNLOAD_FINISH_EN "Unload\nFilament\nComplete"
+
+//manual ip
+#define MANUAL_IP_TITLE_EN "Manual IP"
+#define MANUAL_IP_CANCEL_EN "< Cancel"
+#define MANUAL_IP_APPLY_EN "Join >"
+#define MANUAL_IP_ADDRESS_EN "IP Address"
+#define MANUAL_IP_MASK_EN "Subnet Mask"
+#define MANUAL_IP_GATEWAY_EN "Default Gateway"
+#define MANUAL_IP_SERVER_EN "Name Server"
+#define MANUAL_IP_INIT_DATA_EN "0.0.0.0"
+#define MANUAL_TEXT_POINT_EN "."
+#define MANUAL_TEXT_ENTER_EN "enter"
+
+#define TEXT_FORGET_TIPS_TITLE_EN "Forget Network"
+#define TEXT_FORGET_NETWORK_TIPS1_EN "Are you sure you want to\nforget this network?"
+#define TEXT_FORGET_NETWORK_TIPS2_EN "This machine will no longer\njoin this Wi-Fi Network."
+
+#define TEXT_IPADDRESS_EN "IP Address: "
+
+#define TEXT_BUILD_FROM_CURA_CANCEL_TIPS1_EN "Are you sure you want to\ncancel this build?"
+#define TEXT_BUILD_FROM_CURA_CANCEL_TIPS2_EN "The model will be deleted\nfrom this machine.It will\nneed to be resent from your\ncomputer before it can be\nbuilt in the future."
+
+#define DIALOG_CONFIRM_EN2 "Confirm"
+
+#define HEATING_TITLE_EN "Heating"
+#define LEVELING_TITLE_EN "Leveling"
+
+#define ABOUT_SPARK_ADD_EN "Spark+"
+
+#define TEXT_RECEIVING_DATA_EN "Receiving Data"
+
+#define TEXT_BABY_STEP_EN "Babystep"
+
+#define PRINTING_OTHER_LANGUGE "Printing"
+#define PRINTING_OPERATION_OTHER_LANGUGE "Operation"
+#define PRINTING_PAUSE_OTHER_LANGUGE "Pause"
+
+#define MESSAGE_PAUSING_EN "Parking..."
+#define MESSAGE_CHANGING_EN "Wait for filament change to start"
+#define MESSAGE_UNLOAD_EN "Wait for filament unload"
+#define MESSAGE_WAITING_EN "Press Button to resume print"
+#define MESSAGE_INSERT_EN "Insert filament and press button to continue"
+#define MESSAGE_LOAD_EN "Wait for filament load"
+#define MESSAGE_PURGE_EN "Wait for filament purge"
+#define MESSAGE_RESUME_EN "Wait for print to resume..."
+#define MESSAGE_HEAT_EN "Press button to heat nozzle"
+#define MESSAGE_HEATING_EN "Nozzle heating Please wait..."
+#define MESSAGE_OPTION_EN "Purge more or continue print?"
+#define MESSAGE_PURGE_MORE_EN "Purge"
+#define MESSAGE_CONTINUE_PRINT_EN "Print"
+#define EEPROM_SETTINGS_TITLE_EN "EEPROM Settings"
+#define EEPROM_SETTINGS_STORE_EN "Store settings to EEPROM"
+#define EEPROM_SETTINGS_READ_EN "Read settings from EEPROM"
+#define EEPROM_SETTINGS_REVERT_EN "Revert settings to factory defaults"
+
+#define EEPROM_STORE_TIPS_EN "Store settings to EEPROM?"
+#define EEPROM_READ_TIPS_EN "Read settings from EEPROM?"
+#define EEPROM_REVERT_TIPS_EN "Revert settings to factory defaults?"
+
+#define MORE_CUSTOM1_TEXT_EN USER_DESC_1
+#define MORE_CUSTOM2_TEXT_EN USER_DESC_2
+#define MORE_CUSTOM3_TEXT_EN USER_DESC_3
+#define MORE_CUSTOM4_TEXT_EN USER_DESC_4
+#define MORE_CUSTOM5_TEXT_EN USER_DESC_5
+#define MORE_CUSTOM6_TEXT_EN USER_DESC_6
+#define MORE_CUSTOM7_TEXT_EN USER_DESC_7
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h
new file mode 100644
index 0000000..e65ec43
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h
@@ -0,0 +1,268 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//*************法文****************************//
+#define TOOL_TEXT_FR "prêt"
+#define PREHEAT_TEXT_FR "Préchauffe"
+#define MOVE_TEXT_FR "Déplace"
+#define HOME_TEXT_FR "Acceuil"
+#define PRINT_TEXT_FR "Impression"
+#define EXTRUDE_TEXT_FR "Extruder"
+#define LEVELING_TEXT_FR "Leveling"
+#define AUTO_LEVELING_TEXT_FR "AutoLevel"
+#define SET_TEXT_FR "Config"
+#define MORE_TEXT_FR "Plus"
+
+#define ADD_TEXT_FR "Ajouter"
+#define DEC_TEXT_FR "Réduire"
+#define EXTRUDER_1_TEXT_FR "Extr1"
+#define EXTRUDER_2_TEXT_FR "Extr2"
+#define HEATBED_TEXT_FR "Hotlit"
+#define TEXT_1C_FR "1℃"
+#define TEXT_5C_FR "5℃"
+#define TEXT_10C_FR "10℃"
+#define CLOSE_TEXT_FR "Off"
+
+#define BACK_TEXT_FR "Arrière"
+
+#define TOOL_PREHEAT_FR "Préchauffe"
+#define TOOL_EXTRUDE_FR "Extruder"
+#define TOOL_MOVE_FR "Déplace"
+#define TOOL_HOME_FR "Acceuil"
+#define TOOL_LEVELING_FR "Leveling"
+#define TOOL_AUTO_LEVELING_FR "AutoLevel"
+#define TOOL_FILAMENT_FR "Filament"
+#define TOOL_MORE_FR "Plus"
+
+#define AXIS_X_ADD_TEXT_FR "X+"
+#define AXIS_X_DEC_TEXT_FR "X-"
+#define AXIS_Y_ADD_TEXT_FR "Y+"
+#define AXIS_Y_DEC_TEXT_FR "Y-"
+#define AXIS_Z_ADD_TEXT_FR "Z+"
+#define AXIS_Z_DEC_TEXT_FR "Z-"
+#define TEXT_01MM_FR "0.1mm"
+#define TEXT_1MM_FR "1mm"
+#define TEXT_10MM_FR "10mm"
+
+#define HOME_X_TEXT_FR "X"
+#define HOME_Y_TEXT_FR "Y"
+#define HOME_Z_TEXT_FR "Z"
+#define HOME_ALL_TEXT_FR "ALL"
+#define HOME_STOPMOVE_FR "Quickstop"
+
+#define PAGE_UP_TEXT_FR "En haut"
+#define PAGE_DOWN_TEXT_FR "En bas"
+
+#define EXTRUDER_IN_TEXT_FR "Insérer"
+#define EXTRUDER_OUT_TEXT_FR "éjecter"
+#define EXTRUDE_1MM_TEXT_FR "1mm"
+#define EXTRUDE_5MM_TEXT_FR "5mm"
+#define EXTRUDE_10MM_TEXT_FR "10mm"
+#define EXTRUDE_LOW_SPEED_TEXT_FR "Lente"
+#define EXTRUDE_MEDIUM_SPEED_TEXT_FR "Moyen"
+#define EXTRUDE_HIGH_SPEED_TEXT_FR "Rapide"
+
+#define LEVELING_POINT1_TEXT_FR "Premier"
+#define LEVELING_POINT2_TEXT_FR "Seconde"
+#define LEVELING_POINT3_TEXT_FR "Troisième"
+#define LEVELING_POINT4_TEXT_FR "Quatrième"
+#define LEVELING_POINT5_TEXT_FR "Cinquième"
+
+#define FILESYS_TEXT_FR "Fichier"
+#define WIFI_TEXT_FR "WiFi"
+#define FAN_TEXT_FR "Fan"
+#define ABOUT_TEXT_FR "A propos"
+#define BREAK_POINT_TEXT_FR "Continuer"
+#define FILAMENT_TEXT_FR "Remplacer"
+#define LANGUAGE_TEXT_FR "Langue"
+#define MOTOR_OFF_TEXT_FR "M-hors"
+#define MOTOR_OFF_XY_TEXT_FR "M-hors-XY"
+#define SHUTDOWN_TEXT_FR "Eteindre"
+#define MACHINE_PARA_FR "Config"
+#define EEPROM_SETTINGS_FR "Eeprom Set"
+
+#define U_DISK_TEXT_FR "Clé usb"
+#define SD_CARD_TEXT_FR "Carte SD"
+#define WIFI_NAME_TEXT_FR "WiFi: "
+#define WIFI_KEY_TEXT_FR "Key: "
+#define WIFI_IP_TEXT_FR "IP: "
+#define WIFI_AP_TEXT_FR "Etat: AP"
+#define WIFI_STA_TEXT_FR "Etat: STA"
+#define WIFI_CONNECTED_TEXT_FR "Connecté"
+#define WIFI_DISCONNECTED_TEXT_FR "Déconnecté"
+#define WIFI_EXCEPTION_TEXT_FR "Exception"
+#define WIFI_RECONNECT_TEXT_FR "Reconnect"
+#define CLOUD_TEXT_FR "Cloud"
+#define CLOUD_BIND_FR "Lié"
+#define CLOUD_UNBIND_FR "Délier"
+#define CLOUD_UNBINDING_FR "Délier"
+#define CLOUD_DISCONNECTED_FR "Déconnecté"
+#define CLOUD_UNBINDED_FR "Délier"
+#define CLOUD_BINDED_FR "Lié"
+#define CLOUD_DISABLE_FR "Désactiver"
+
+#define FAN_ADD_TEXT_FR "Ajouter"
+#define FAN_DEC_TEXT_FR "Réduire"
+#define FAN_OPEN_TEXT_FR "100%"
+#define FAN_HALF_TEXT_FR "50%"
+#define FAN_CLOSE_TEXT_FR "0%"
+#define FAN_TIPS1_TEXT_FR "ventilateur"
+#define FAN_TIPS2_TEXT_FR "ventilateur\n0"
+
+#define FILAMENT_IN_TEXT_FR "Insérer"
+#define FILAMENT_OUT_TEXT_FR "éjecter"
+#define FILAMENT_EXT0_TEXT_FR "Extr1"
+#define FILAMENT_EXT1_TEXT_FR "Extr2"
+#define FILAMENT_HEAT_TEXT_FR "Preheat"
+#define FILAMENT_STOP_TEXT_FR "Arrêter"
+#define FILAMENT_TIPS2_TEXT_FR "T:"
+#define FILAMENT_TIPS3_TEXT_FR "Insérer le filament..."
+#define FILAMENT_TIPS4_TEXT_FR "éjecter le filament..."
+#define FILAMENT_TIPS5_TEXT_FR "Température trop basse pour démarrer, chauffez svp"
+#define FILAMENT_TIPS6_TEXT_FR "Terminé"
+
+#define FILAMENT_CHANGE_TEXT_FR "Please click <Load> \nor <unload>,After \npinter pause."
+#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_FR "Heating up the nozzle,\nplease wait..."
+#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_FR "Heating up the nozzle,\nplease wait..."
+#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_FR "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading."
+#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_FR "Please load filament to extruder,\nand click <confirm> for start loading."
+#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_FR "Heat completed,please \nclick <confirm> for start unloading.!"
+#define FILAMENT_DIALOG_LOADING_TIPS_FR "Is loading ,please wait!"
+#define FILAMENT_DIALOG_UNLOADING_TIPS_FR "Is unloading,please wait!"
+#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_FR "Load filament completed,\nclick <confirm> for return!"
+#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_FR "Unload filament completed,\nclick <confirm> for return!"
+
+
+#define PRE_HEAT_EXT_TEXT_FR "E"
+#define PRE_HEAT_BED_TEXT_FR "Bed"
+
+#define FILE_LOADING_FR "Chargement......"
+#define NO_FILE_AND_CHECK_FR "Aucun fichier,vérifiez à nouveau!"
+#define NO_FILE_FR "Pas de fichier!"
+
+#define EXTRUDER_TEMP_TEXT_FR "Temper"
+#define EXTRUDER_E_LENGTH1_TEXT_FR "Extruder1"
+#define EXTRUDER_E_LENGTH2_TEXT_FR "Extruder2"
+#define EXTRUDER_E_LENGTH3_TEXT_FR "Extruder3"
+
+#define ABOUT_TYPE_TEXT_FR "Type: "
+#define ABOUT_VERSION_TEXT_FR "Firmware: "
+#define ABOUT_WIFI_TEXT_FR "Wifi: "
+
+#define PRINTING_OPERATION_FR "Option"
+#define PRINTING_PAUSE_FR "Pause"
+#define PRINTING_TEMP_FR "Temp."
+#define PRINTING_CHANGESPEED_FR "Speed"
+#define PRINTING_RESUME_FR "Reprendre"
+#define PRINTING_STOP_FR "Stop"
+#define PRINTING_MORE_FR "Plus"
+#define PRINTING_EXTRUDER_FR "Extruder"
+#define PRINTING_MOVE_FR "Déplace"
+
+#define EXTRUDER_SPEED_FR "Extruder"
+#define MOVE_SPEED_FR "Déplace"
+#define EXTRUDER_SPEED_STATE_FR "Vitesse d'extrusion"
+#define MOVE_SPEED_STATE_FR "vitesse de déplacement"
+#define STEP_1PERCENT_FR "1%"
+#define STEP_5PERCENT_FR "5%"
+#define STEP_10PERCENT_FR "10%"
+
+#define TITLE_READYPRINT_FR "Prête"
+#define TITLE_PREHEAT_FR "Préchauffe"
+#define TITLE_MOVE_FR "Déplace"
+#define TITLE_HOME_FR "Acceuil"
+#define TITLE_EXTRUDE_FR "Extruder"
+#define TITLE_LEVELING_FR "Leveling"
+#define TITLE_SET_FR "Paramètres"
+#define TITLE_MORE_FR "Plus"
+#define TITLE_CHOOSEFILE_FR "Fichier"
+#define TITLE_PRINTING_FR "Pimpression"
+#define TITLE_OPERATION_FR "Option"
+#define TITLE_ADJUST_FR "Réglage"
+#define TITLE_WIRELESS_FR "Sans fil"
+#define TITLE_FILAMENT_FR "Remplacer"
+#define TITLE_ABOUT_FR "A propos"
+#define TITLE_FAN_FR "Ventilateur"
+#define TITLE_LANGUAGE_FR "Langue"
+#define TITLE_PAUSE_FR "Pause"
+#define TITLE_CHANGESPEED_FR "Speed"
+#define TITLE_CLOUD_TEXT_FR "Cloud"
+#define TITLE_DIALOG_CONFIRM_FR "Confirm"
+#define TITLE_FILESYS_FR "FileSys"
+
+#define DIALOG_CLOSE_MACHINE_FR "Closing machine......"
+
+#define AUTO_SHUTDOWN_FR "Auto"
+#define MANUAL_SHUTDOWN_FR "Manuel"
+
+#define DIALOG_CONFIRM_FR "Confirmer"
+#define DIALOG_CANCLE_FR "Annuler"
+#define DIALOG_OK_FR "OK"
+#define DIALOG_RESET_FR "Réinitialiser"
+#define DIALOG_RETRY_FR "Recommencez"
+#define DIALOG_DISABLE_FR "Disable"
+#define DIALOG_PRINT_MODEL_FR "Imprimer le fichier?"
+#define DIALOG_CANCEL_PRINT_FR "Arrêter?"
+
+#define DIALOG_STOP_FR "Arrêter"
+#define DIALOG_REPRINT_FROM_BREAKPOINT_FR "Continuer?"
+#define DIALOG_ERROR_TIPS1_FR "Erreur:error:Aucun fichier, \nvérifiez à nouveau."
+#define DIALOG_ERROR_TIPS2_FR "Erreur:La opération a échoué. \nVerifiez que le baudrate de l'écran et de \nla carte mère soient identique!"
+#define DIALOG_ERROR_TIPS3_FR "Erreur: le nom du fichier ou le \nchemin d'accès est trop long."
+#define DIALOG_UNBIND_PRINTER_FR "Unbind the printer?"
+#define DIALOG_FILAMENT_NO_PRESS_FR "Filament detection switch is not pressed"
+#define DIALOG_PRINT_FINISH_FR "L'impression est terminée!"
+#define DIALOG_PRINT_TIME_FR "Temps d'impression: "
+#define DIALOG_REPRINT_FR "Print again"
+#define DIALOG_WIFI_ENABLE_TIPS_FR "The wifi module is being configured,\nplease wait a moment....."
+#define DIALOG_PAUSING_TIPS_FR "La machine fait une pause ..."
+
+#define MESSAGE_PAUSING_FR "Parking..."
+#define MESSAGE_CHANGING_FR "Attente filament pour démarrer"
+#define MESSAGE_UNLOAD_FR "Attente retrait du filament"
+#define MESSAGE_WAITING_FR "Presser bouton,pour reprendre"
+#define MESSAGE_INSERT_FR "Insérer filament et app. bouton pour continuer..."
+#define MESSAGE_LOAD_FR "Attente chargement filament"
+#define MESSAGE_PURGE_FR "Attente Purge filament"
+#define MESSAGE_RESUME_FR "Attente reprise impression"
+#define MESSAGE_HEAT_FR "Presser le bouton pour chauffer..."
+#define MESSAGE_HEATING_FR "Buse en chauffe Patienter SVP..."
+#define MESSAGE_OPTION_FR "Purger davantage ou continuer l'impression?"
+#define MESSAGE_PURGE_MORE_FR "Purge"
+#define MESSAGE_CONTINUE_PRINT_FR "Impression"
+#define EEPROM_SETTINGS_TITLE_FR "Paramètres EEPROM"
+#define EEPROM_SETTINGS_STORE_FR "Stocker les paramètres dans l'EEPROM"
+#define EEPROM_SETTINGS_READ_FR "Lire les paramètres de l'EEPROM"
+#define EEPROM_SETTINGS_REVERT_FR "Rétablir les paramètres par défaut d'usine"
+
+#define EEPROM_STORE_TIPS_FR "Stocker les paramètres dans l'EEPROM?"
+#define EEPROM_READ_TIPS_FR "Lire les paramètres de l'EEPROM?"
+#define EEPROM_REVERT_TIPS_FR "Rétablir les paramètres par défaut d'usine?"
+
+#define MORE_CUSTOM1_TEXT_FR USER_DESC_1
+#define MORE_CUSTOM2_TEXT_FR USER_DESC_2
+#define MORE_CUSTOM3_TEXT_FR USER_DESC_3
+#define MORE_CUSTOM4_TEXT_FR USER_DESC_4
+#define MORE_CUSTOM5_TEXT_FR USER_DESC_5
+#define MORE_CUSTOM6_TEXT_FR USER_DESC_6
+#define MORE_CUSTOM7_TEXT_FR USER_DESC_7
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h
new file mode 100644
index 0000000..2820feb
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h
@@ -0,0 +1,265 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//****************意大利语***************************//
+#define TOOL_TEXT_IT "Strumento"
+#define PREHEAT_TEXT_IT "Prerisc"
+#define MOVE_TEXT_IT "Muovi"
+#define HOME_TEXT_IT "Home"
+#define PRINT_TEXT_IT "Stampa"
+#define EXTRUDE_TEXT_IT "Estrude"
+#define LEVELING_TEXT_IT "Leveling"
+#define AUTO_LEVELING_TEXT_IT "AutoLevel"
+#define SET_TEXT_IT "Imposta"
+#define MORE_TEXT_IT "Di più"
+
+#define ADD_TEXT_IT "Aumentare"
+#define DEC_TEXT_IT "Ridurre"
+#define EXTRUDER_1_TEXT_IT "Estrude1"
+#define EXTRUDER_2_TEXT_IT "Estrude2"
+#define HEATBED_TEXT_IT "Piano"
+#define TEXT_1C_IT "1℃"
+#define TEXT_5C_IT "5℃"
+#define TEXT_10C_IT "10℃"
+#define CLOSE_TEXT_IT "Spento"
+
+#define BACK_TEXT_IT "Indietro"
+
+#define TOOL_PREHEAT_IT "Prerisc"
+#define TOOL_EXTRUDE_IT "Estrude"
+#define TOOL_MOVE_IT "Muovi"
+#define TOOL_HOME_IT "Home"
+#define TOOL_LEVELING_IT "Leveling"
+#define TOOL_AUTO_LEVELING_IT "Autolevel"
+#define TOOL_FILAMENT_IT "Filamento"
+#define TOOL_MORE_IT "Di più"
+
+#define AXIS_X_ADD_TEXT_IT "X+"
+#define AXIS_X_DEC_TEXT_IT "X-"
+#define AXIS_Y_ADD_TEXT_IT "Y+"
+#define AXIS_Y_DEC_TEXT_IT "Y-"
+#define AXIS_Z_ADD_TEXT_IT "Z+"
+#define AXIS_Z_DEC_TEXT_IT "Z-"
+#define TEXT_01MM_IT "0.1mm"
+#define TEXT_1MM_IT "1mm"
+#define TEXT_10MM_IT "10mm"
+
+#define HOME_X_TEXT_IT "X"
+#define HOME_Y_TEXT_IT "Y"
+#define HOME_Z_TEXT_IT "Z"
+#define HOME_ALL_TEXT_IT "All"
+#define HOME_STOPMOVE_IT "Quickstop"
+
+#define PAGE_UP_TEXT_IT "Pagina su"
+#define PAGE_DOWN_TEXT_IT "Pagina giù"
+
+#define EXTRUDER_IN_TEXT_IT "Estru"
+#define EXTRUDER_OUT_TEXT_IT "Ritra"
+#define EXTRUDE_1MM_TEXT_IT "1mm"
+#define EXTRUDE_5MM_TEXT_IT "5mm"
+#define EXTRUDE_10MM_TEXT_IT "10mm"
+#define EXTRUDE_LOW_SPEED_TEXT_IT "Bassa"
+#define EXTRUDE_MEDIUM_SPEED_TEXT_IT "Media"
+#define EXTRUDE_HIGH_SPEED_TEXT_IT "Alta"
+
+#define LEVELING_POINT1_TEXT_IT "Primo"
+#define LEVELING_POINT2_TEXT_IT "Secondo"
+#define LEVELING_POINT3_TEXT_IT "Terzo"
+#define LEVELING_POINT4_TEXT_IT "Quarto"
+#define LEVELING_POINT5_TEXT_IT "Quinto"
+
+#define FILESYS_TEXT_IT "FileSys"
+#define WIFI_TEXT_IT "WIFI"
+#define FAN_TEXT_IT "Ventola"
+#define ABOUT_TEXT_IT "Circa"
+#define BREAK_POINT_TEXT_IT "Continua"
+#define FILAMENT_TEXT_IT "Filamento"
+#define LANGUAGE_TEXT_IT "Lingua"
+#define MOTOR_OFF_TEXT_IT "Motor off"
+#define MOTOR_OFF_XY_TEXT_IT "Off-XY"
+#define SHUTDOWN_TEXT_IT "Spento"
+#define MACHINE_PARA_IT "Config"
+#define EEPROM_SETTINGS_IT "Eeprom Set"
+
+#define U_DISK_TEXT_IT "USB"
+#define SD_CARD_TEXT_IT "SD"
+#define WIFI_NAME_TEXT_IT "WIFI: "
+#define WIFI_KEY_TEXT_IT "KEY: "
+#define WIFI_IP_TEXT_IT "IP: "
+#define WIFI_AP_TEXT_IT "Stato: AP"
+#define WIFI_STA_TEXT_IT "Stato: STA"
+#define WIFI_CONNECTED_TEXT_IT "Connesso"
+#define WIFI_DISCONNECTED_TEXT_IT "Disconnesso"
+#define WIFI_EXCEPTION_TEXT_IT "Eccezione"
+#define WIFI_RECONNECT_TEXT_IT "Reconnect"
+#define CLOUD_TEXT_IT "Cloud"
+#define CLOUD_BIND_IT "Legato"
+#define CLOUD_UNBIND_IT "Libero"
+#define CLOUD_DISCONNECTED_IT "Disconnesso"
+#define CLOUD_UNBINDING_IT "Libero"
+#define CLOUD_UNBINDED_IT "Sciolto"
+#define CLOUD_BINDED_IT "Legato"
+#define CLOUD_DISABLE_IT "Disable"
+
+#define FAN_ADD_TEXT_IT "Aumentare"
+#define FAN_DEC_TEXT_IT "Ridurre"
+#define FAN_OPEN_TEXT_IT "100%"
+#define FAN_HALF_TEXT_IT "50%"
+#define FAN_CLOSE_TEXT_IT "Spento"
+#define FAN_TIPS1_TEXT_IT "Ventola"
+#define FAN_TIPS2_TEXT_IT "Ventola\n0"
+
+#define FILAMENT_IN_TEXT_IT "Inser"
+#define FILAMENT_OUT_TEXT_IT "Estra"
+#define FILAMENT_EXT0_TEXT_IT "Estrude1"
+#define FILAMENT_EXT1_TEXT_IT "Estrude2"
+#define FILAMENT_HEAT_TEXT_IT "Preriscaldamento"
+#define FILAMENT_STOP_TEXT_IT "Stop"
+#define FILAMENT_TIPS2_TEXT_IT "T:"
+#define FILAMENT_TIPS3_TEXT_IT "Inserimento del filamento..."
+#define FILAMENT_TIPS4_TEXT_IT "Estrazione del filamento..."
+#define FILAMENT_TIPS5_TEXT_IT "Temp is too low to go,please heat"
+#define FILAMENT_TIPS6_TEXT_IT "Completato"
+
+#define FILAMENT_CHANGE_TEXT_IT "Please click <Load> \nor <unload>,After \npinter pause."
+#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_IT "Heating up the nozzle,please wait..."
+#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_IT "Heating up the nozzle,please wait..."
+#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_IT "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading."
+#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_IT "Please load filament to extruder,\nand click <confirm> for start loading."
+#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_IT "Heat completed,please \nclick <confirm> for start unloading.!"
+#define FILAMENT_DIALOG_LOADING_TIPS_IT "Is loading ,please wait!"
+#define FILAMENT_DIALOG_UNLOADING_TIPS_IT "Is unloading,please wait!"
+#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_IT "Load filament completed,\nclick <confirm> for return!"
+#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_IT "Unload filament completed,\nclick <confirm> for return!"
+
+#define PRE_HEAT_EXT_TEXT_IT "E"
+#define PRE_HEAT_BED_TEXT_IT "Piano"
+
+#define FILE_LOADING_IT "Caricamento......"
+#define NO_FILE_AND_CHECK_IT "Nessun file,\n per favore controllare di nuovo!"
+#define NO_FILE_IT "Nessun file!"
+
+#define EXTRUDER_TEMP_TEXT_IT "Temper"
+#define EXTRUDER_E_LENGTH1_TEXT_IT "Estrude1"
+#define EXTRUDER_E_LENGTH2_TEXT_IT "Estrude2"
+#define EXTRUDER_E_LENGTH3_TEXT_IT "Estrude3"
+
+#define ABOUT_TYPE_TEXT_IT "Type: "
+#define ABOUT_VERSION_TEXT_IT "Firmware: "
+#define ABOUT_WIFI_TEXT_IT "WiFi: "
+
+#define PRINTING_OPERATION_IT "Opzioni"
+#define PRINTING_PAUSE_IT "Pause"
+#define PRINTING_TEMP_IT "Temp."
+#define PRINTING_CHANGESPEED_IT "Velocità"
+#define PRINTING_RESUME_IT "Recupero"
+#define PRINTING_STOP_IT "Stop"
+#define PRINTING_MORE_IT "Di più"
+#define PRINTING_EXTRUDER_IT "Estrude"
+#define PRINTING_MOVE_IT "Muovi"
+
+#define EXTRUDER_SPEED_IT "Estrude"
+#define MOVE_SPEED_IT "Muovi"
+#define EXTRUDER_SPEED_STATE_IT "Estrusione"
+#define MOVE_SPEED_STATE_IT "Movimento"
+#define STEP_1PERCENT_IT "1%"
+#define STEP_5PERCENT_IT "5%"
+#define STEP_10PERCENT_IT "10%"
+
+#define TITLE_READYPRINT_IT "Pronto"
+#define TITLE_PREHEAT_IT "Preris"
+#define TITLE_MOVE_IT "Muovi"
+#define TITLE_HOME_IT "Home"
+#define TITLE_EXTRUDE_IT "Estrude"
+#define TITLE_LEVELING_IT "Livella"
+#define TITLE_SET_IT "Impostare"
+#define TITLE_MORE_IT "Di più"
+#define TITLE_CHOOSEFILE_IT "File"
+#define TITLE_PRINTING_IT "Stampa"
+#define TITLE_OPERATION_IT "Opzioni"
+#define TITLE_ADJUST_IT "Regolare"
+#define TITLE_WIRELESS_IT "Wireless"
+#define TITLE_FILAMENT_IT "Filamento"
+#define TITLE_ABOUT_IT "Circa"
+#define TITLE_FAN_IT "Ventola"
+#define TITLE_LANGUAGE_IT "Lingua"
+#define TITLE_PAUSE_IT "Pausa"
+#define TITLE_CHANGESPEED_IT "Velocità"
+#define TITLE_CLOUD_TEXT_IT "Cloud"
+#define TITLE_DIALOG_CONFIRM_IT "Confirm"
+#define TITLE_FILESYS_IT "FileSys"
+
+#define AUTO_SHUTDOWN_IT "Auto"
+#define MANUAL_SHUTDOWN_IT "Manuale"
+
+#define DIALOG_CONFIRM_IT "Conferma"
+#define DIALOG_CANCLE_IT "Cancella"
+#define DIALOG_OK_IT "OK"
+#define DIALOG_RESET_IT "Resettare"
+#define DIALOG_RETRY_IT "Riprovare"
+#define DIALOG_DISABLE_IT "Disable"
+#define DIALOG_PRINT_MODEL_IT "Gcode stampa?"
+#define DIALOG_CANCEL_PRINT_IT "Stop stampa?"
+#define DIALOG_STOP_IT "Stop"
+#define DIALOG_REPRINT_FROM_BREAKPOINT_IT "Continua a stampare dal \npunto di interruzione?"
+#define DIALOG_ERROR_TIPS1_IT "Errore: nessun file, \nper favore controllare di nuovo."
+#define DIALOG_ERROR_TIPS2_IT "Errore: operazione non riuscita, \nsi prega di controllare se il baudrate del \ndisplay è lo stesso scheda madre"
+#define DIALOG_ERROR_TIPS3_IT "Errore: il nome del file o il \npercorso è troppo lungo!"
+#define DIALOG_CLOSE_MACHINE_IT "Closing machine......"
+#define DIALOG_UNBIND_PRINTER_IT "Unbind the printer?"
+#define DIALOG_FILAMENT_NO_PRESS_IT "Filament detection switch is not pressed"
+#define DIALOG_PRINT_FINISH_IT "La stampa è completa!"
+#define DIALOG_PRINT_TIME_IT "Tempo di stampa: "
+#define DIALOG_REPRINT_IT "Print again"
+#define DIALOG_WIFI_ENABLE_TIPS_IT "The wifi module is being configured,\nplease wait a moment....."
+#define DIALOG_PAUSING_TIPS_IT "La macchina si ferma ..."
+
+#define MESSAGE_PAUSING_IT "Parcheggiando..."
+#define MESSAGE_CHANGING_IT "Attendere avvio del cambio di filamento"
+#define MESSAGE_UNLOAD_IT "Attendere l'espulsione del filamento"
+#define MESSAGE_WAITING_IT "Premi per riprendere la stampa"
+#define MESSAGE_INSERT_IT "Inserisci il filamento e premi per continuare"
+#define MESSAGE_LOAD_IT "Attendere il caricamento del filamento"
+#define MESSAGE_PURGE_IT "Attendere lo spurgo del filamento"
+#define MESSAGE_RESUME_IT "Attendere la ripresa della stampa..."
+#define MESSAGE_HEAT_IT "Premi per riscaldare ugello"
+#define MESSAGE_HEATING_IT "Riscaldam. ugello Attendere prego..."
+#define MESSAGE_OPTION_IT "Eliminare di più o continuare a stampare?"
+#define MESSAGE_PURGE_MORE_IT "Epurazione"
+#define MESSAGE_CONTINUE_PRINT_IT "Stampa"
+#define EEPROM_SETTINGS_TITLE_IT "Impostazioni EEPROM"
+#define EEPROM_SETTINGS_STORE_IT "Memorizzare le impostazioni su EEPROM"
+#define EEPROM_SETTINGS_READ_IT "Leggi le impostazioni dalla EEPROM"
+#define EEPROM_SETTINGS_REVERT_IT "Ripristina le impostazioni predefinite di fabbrica"
+
+#define EEPROM_STORE_TIPS_IT "Memorizzare le impostazioni su EEPROM?"
+#define EEPROM_READ_TIPS_IT "Leggi le impostazioni dalla EEPROM?"
+#define EEPROM_REVERT_TIPS_IT "Ripristinare le impostazioni predefinite?"
+
+#define MORE_CUSTOM1_TEXT_IT USER_DESC_1
+#define MORE_CUSTOM2_TEXT_IT USER_DESC_2
+#define MORE_CUSTOM3_TEXT_IT USER_DESC_3
+#define MORE_CUSTOM4_TEXT_IT USER_DESC_4
+#define MORE_CUSTOM5_TEXT_IT USER_DESC_5
+#define MORE_CUSTOM6_TEXT_IT USER_DESC_6
+#define MORE_CUSTOM7_TEXT_IT USER_DESC_7
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h
new file mode 100644
index 0000000..04fbf25
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h
@@ -0,0 +1,384 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//****************俄语***************************//
+#define TOOL_TEXT_RU "инструмент"
+#define PREHEAT_TEXT_RU " нагрев"
+#define MOVE_TEXT_RU "движение"
+#define HOME_TEXT_RU "домой"
+#define PRINT_TEXT_RU " печать"
+#define EXTRUDE_TEXT_RU "экструзия"
+#define LEVELING_TEXT_RU "уровень"
+#define AUTO_LEVELING_TEXT_RU "aвтоуровень"
+#define SET_TEXT_RU "настройки"
+#define MORE_TEXT_RU "больше"
+
+#define ADD_TEXT_RU "добавить"
+#define DEC_TEXT_RU "уменьшить"
+#define EXTRUDER_1_TEXT_RU "экструдер1"
+#define EXTRUDER_2_TEXT_RU "экструдер2"
+#define HEATBED_TEXT_RU "стол"
+#define TEXT_1C_RU "1℃"
+#define TEXT_5C_RU "5℃"
+#define TEXT_10C_RU "10℃"
+#define CLOSE_TEXT_RU "выкл"
+
+#define BACK_TEXT_RU "назад"
+
+#define TOOL_PREHEAT_RU "нагрев"
+#define TOOL_EXTRUDE_RU "экструдер"
+#define TOOL_MOVE_RU "движение"
+#define TOOL_HOME_RU "домой"
+#define TOOL_LEVELING_RU "уровень"
+#define TOOL_AUTO_LEVELING_RU "aвтоуровень"
+#define TOOL_FILAMENT_RU "замена"
+#define TOOL_MORE_RU "больше"
+
+#define AXIS_X_ADD_TEXT_RU "X +"
+#define AXIS_X_DEC_TEXT_RU "X -"
+#define AXIS_Y_ADD_TEXT_RU "Y +"
+#define AXIS_Y_DEC_TEXT_RU "Y -"
+#define AXIS_Z_ADD_TEXT_RU "Z +"
+#define AXIS_Z_DEC_TEXT_RU "Z -"
+#define TEXT_01MM_RU "0.1 mm"
+#define TEXT_1MM_RU "1 mm"
+#define TEXT_10MM_RU "10 mm"
+
+#define HOME_X_TEXT_RU "X"
+#define HOME_Y_TEXT_RU "Y"
+#define HOME_Z_TEXT_RU "Z"
+#define HOME_ALL_TEXT_RU "Home"
+#define HOME_STOPMOVE_RU "Quickstop"
+
+#define PAGE_UP_TEXT_RU "вверх"
+#define PAGE_DOWN_TEXT_RU "вниз"
+
+#define EXTRUDER_IN_TEXT_RU "втянуть"
+#define EXTRUDER_OUT_TEXT_RU "выдавить"
+#define EXTRUDE_1MM_TEXT_RU "1 mm"
+#define EXTRUDE_5MM_TEXT_RU "5 mm"
+#define EXTRUDE_10MM_TEXT_RU "10 mm"
+#define EXTRUDE_LOW_SPEED_TEXT_RU "мин"
+#define EXTRUDE_MEDIUM_SPEED_TEXT_RU "сред"
+#define EXTRUDE_HIGH_SPEED_TEXT_RU "выс"
+
+#define LEVELING_POINT1_TEXT_RU "1 точка"
+#define LEVELING_POINT2_TEXT_RU "2 точка"
+#define LEVELING_POINT3_TEXT_RU "3 точка"
+#define LEVELING_POINT4_TEXT_RU "4 точка"
+#define LEVELING_POINT5_TEXT_RU "5 точка"
+
+#define FILESYS_TEXT_RU "система"
+#define WIFI_TEXT_RU "WiFi"
+#define FAN_TEXT_RU "вентилятор"
+#define ABOUT_TEXT_RU "инфо"
+#define BREAK_POINT_TEXT_RU "продолжить"
+#define FILAMENT_TEXT_RU "замена"
+#define LANGUAGE_TEXT_RU "язык"
+#define MOTOR_OFF_TEXT_RU "откл. мотор"
+#define MOTOR_OFF_XY_TEXT_RU "Off-XY"
+#define SHUTDOWN_TEXT_RU "выключение"
+#define MACHINE_PARA_RU "конфиг"
+
+#define U_DISK_TEXT_RU "U диск"
+#define SD_CARD_TEXT_RU "SD диск"
+#define WIFI_NAME_TEXT_RU "WiFi: "
+#define WIFI_KEY_TEXT_RU "пароль: "
+#define WIFI_IP_TEXT_RU "IP: "
+#define WIFI_AP_TEXT_RU "режим: AP"
+#define WIFI_STA_TEXT_RU "режим: STA"
+#define WIFI_CONNECTED_TEXT_RU "подключен"
+#define WIFI_DISCONNECTED_TEXT_RU "не подключен"
+#define WIFI_EXCEPTION_TEXT_RU "исключение"
+#define WIFI_RECONNECT_TEXT_RU "выбор сети"
+#define CLOUD_TEXT_RU "облако"
+#define CLOUD_BIND_RU "соединён"
+#define CLOUD_UNBIND_RU "отсоед."
+#define CLOUD_UNBINDING_RU "отвязано"
+#define CLOUD_DISCONNECTED_RU "отключено"
+#define CLOUD_UNBINDED_RU "несвяз."
+#define CLOUD_BINDED_RU "связано"
+#define CLOUD_DISABLE_RU "Disable"
+
+#define FAN_ADD_TEXT_RU "добавить"
+#define FAN_DEC_TEXT_RU "уменьшить"
+#define FAN_OPEN_TEXT_RU "100%"
+#define FAN_HALF_TEXT_RU "50%"
+#define FAN_CLOSE_TEXT_RU "откл"
+#define FAN_TIPS1_TEXT_RU "вентилятор"
+#define FAN_TIPS2_TEXT_RU "вентилятор\nоткл"
+
+#define FILAMENT_IN_TEXT_RU "втянуть"
+#define FILAMENT_OUT_TEXT_RU "выдавить"
+#define FILAMENT_EXT0_TEXT_RU "экструдер1"
+#define FILAMENT_EXT1_TEXT_RU "экструдер2"
+#define FILAMENT_HEAT_TEXT_RU "нагрев"
+#define FILAMENT_STOP_TEXT_RU "стоп"
+#define FILAMENT_TIPS2_TEXT_RU "T:"
+#define FILAMENT_TIPS3_TEXT_RU "втянуть..."
+#define FILAMENT_TIPS4_TEXT_RU "вядавить..."
+#define FILAMENT_TIPS5_TEXT_RU "Низкая температура, \nнеобходим нагрев"
+#define FILAMENT_TIPS6_TEXT_RU "завершено"
+
+#define FILAMENT_CHANGE_TEXT_RU "Please click <Load> \nor <unload>,After \npinter pause."
+#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_RU "Heating up the nozzle,\nplease wait..."
+#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_RU "Heating up the nozzle,\nplease wait..."
+#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_RU "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading."
+#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_RU "Please load filament to extruder,\nand click <confirm> for start loading."
+#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_RU "Heat completed,please \nclick <confirm> for start unloading.!"
+#define FILAMENT_DIALOG_LOADING_TIPS_RU "Is loading ,please wait!"
+#define FILAMENT_DIALOG_UNLOADING_TIPS_RU "Is unloading,please wait!"
+#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_RU "Load filament completed,\nclick <confirm> for return!"
+#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_RU "Unload filament completed,\nclick <confirm> for return!"
+
+#define PRE_HEAT_EXT_TEXT_RU "E"
+#define PRE_HEAT_BED_TEXT_RU "стол"
+
+#define FILE_LOADING_RU "загрузка......"
+#define NO_FILE_AND_CHECK_RU "нет файла,попробуйте ещё раз!"
+
+#define NO_FILE_RU "нет файла!"
+
+#define EXTRUDER_TEMP_TEXT_RU "температура"
+#define EXTRUDER_E_LENGTH1_TEXT_RU "экструзия1"
+#define EXTRUDER_E_LENGTH2_TEXT_RU "экструзия2"
+#define EXTRUDER_E_LENGTH3_TEXT_RU "экструзия3"
+
+#define ABOUT_TYPE_TEXT_RU "Type: "
+#define ABOUT_VERSION_TEXT_RU "Firmware: "
+#define ABOUT_WIFI_TEXT_RU "WiFi: "
+
+#define PRINTING_OPERATION_RU "опции"
+#define PRINTING_PAUSE_RU "пауза"
+#define PRINTING_TEMP_RU "темп"
+#define PRINTING_CHANGESPEED_RU "скорости"
+#define PRINTING_RESUME_RU "возобн. "
+#define PRINTING_STOP_RU "стоп"
+#define PRINTING_MORE_RU "больше"
+#define PRINTING_EXTRUDER_RU "экстр"
+#define PRINTING_MOVE_RU "движение"
+
+#define EXTRUDER_SPEED_RU "экстр"
+#define MOVE_SPEED_RU "движ"
+#define EXTRUDER_SPEED_STATE_RU "скорость экстр"
+#define MOVE_SPEED_STATE_RU "скорость движ"
+#define STEP_1PERCENT_RU "1%"
+#define STEP_5PERCENT_RU "5%"
+#define STEP_10PERCENT_RU "10%"
+
+#define TITLE_READYPRINT_RU "готов к"
+#define TITLE_PREHEAT_RU "движение"
+#define TITLE_MOVE_RU "движение"
+#define TITLE_HOME_RU "Home"
+#define TITLE_EXTRUDE_RU "экструзия"
+#define TITLE_LEVELING_RU "уровень"
+#define TITLE_MLEVELING_RU "углы"
+#define TITLE_SET_RU "настройки"
+#define TITLE_MORE_RU "больше"
+#define TITLE_CHOOSEFILE_RU "файла"
+#define TITLE_PRINTING_RU "печать"
+#define TITLE_OPERATION_RU "управление"
+#define TITLE_ADJUST_RU "регулировать"
+#define TITLE_WIRELESS_RU "Wireless"
+#define TITLE_FILAMENT_RU "замена"
+#define TITLE_ABOUT_RU "инфо"
+#define TITLE_FAN_RU "вентилятор"
+#define TITLE_LANGUAGE_RU "язык"
+#define TITLE_PAUSE_RU "пауза"
+#define TITLE_CHANGESPEED_RU "скорости"
+#define TILE_TOOL_RU "инструмент"
+#define TITLE_CLOUD_TEXT_RU "Cloud"
+#define TITLE_DIALOG_CONFIRM_RU "Confirm"
+#define TITLE_FILESYS_RU "FileSys"
+
+#define AUTO_SHUTDOWN_RU "авто-откл"
+#define MANUAL_SHUTDOWN_RU "ручн-откл"
+
+#define DIALOG_CONFIRM_RU "да"//"подтвердить"
+#define DIALOG_CANCLE_RU "отмена"
+#define DIALOG_OK_RU "да"
+#define DIALOG_RESET_RU "сброс"
+#define DIALOG_RETRY_RU "повтор"
+#define DIALOG_DISABLE_RU "запретить"
+#define DIALOG_PRINT_MODEL_RU "печать модели?"
+#define DIALOG_CANCEL_PRINT_RU "стоп?"
+#define DIALOG_STOP_RU "стоп"
+#define DIALOG_REPRINT_FROM_BREAKPOINT_RU "продолжить?"
+#define DIALOG_ERROR_TIPS1_RU "ошибка:нет файла, попробуйте ещё раз."
+#define DIALOG_ERROR_TIPS2_RU "ошибка:сбой передачи. установите скорость \nпередачи данных как на плате управления!"
+#define DIALOG_ERROR_TIPS3_RU "ошибка: имя файла слишком длинное!"
+#define DIALOG_CLOSE_MACHINE_RU "Closing machine......"
+#define DIALOG_UNBIND_PRINTER_RU "Unbind the printer?"
+#define DIALOG_FILAMENT_NO_PRESS_RU "Filament detection switch is not pressed"
+#define DIALOG_PRINT_FINISH_RU "печать завершена!"
+#define DIALOG_PRINT_TIME_RU "Время печати: "
+#define DIALOG_REPRINT_RU "Print again"
+#define DIALOG_WIFI_ENABLE_TIPS_RU "The wifi module is being configured,\nplease wait a moment....."
+#define DIALOG_PAUSING_TIPS_RU "Машина останавливается ..."
+
+#define MESSAGE_PAUSING_RU "Стоянка..."
+#define MESSAGE_CHANGING_RU "Подождите, пока начнется смена филамента"
+#define MESSAGE_UNLOAD_RU "Дождитесь выгрузки нити"
+#define MESSAGE_WAITING_RU "Нажмите кнопку,чтобы возобновить печать"
+#define MESSAGE_INSERT_RU "Вставьте нить и нажмите кнопку,чтобы продолжить"
+#define MESSAGE_LOAD_RU "Дождитесь загрузки нити"
+#define MESSAGE_PURGE_RU "Дождитесь чистки нити"
+#define MESSAGE_RESUME_RU "Подождите,пока печать возобновится ..."
+#define MESSAGE_HEAT_RU "Нажмите кнопку, чтобы нагреть форсунку"
+#define MESSAGE_HEATING_RU "Подогрев форсунки Пожалуйста, подождите ..."
+#define MESSAGE_OPTION_RU "Очистить больше или продолжить печать?"
+#define MESSAGE_PURGE_MORE_RU "чистка"
+#define MESSAGE_CONTINUE_PRINT_RU "Распечатать"
+#define EEPROM_SETTINGS_TITLE_RU "Настройки EEPROM"
+#define EEPROM_SETTINGS_STORE_RU "Cохранение настроек в EEPROM"
+#define EEPROM_SETTINGS_READ_RU "Чтение настроек из EEPROM"
+#define EEPROM_SETTINGS_REVERT_RU "Bосстановить заводские настройки по умолчанию"
+
+#define MORE_CUSTOM1_TEXT_RU USER_DESC_1
+#define MORE_CUSTOM2_TEXT_RU USER_DESC_2
+#define MORE_CUSTOM3_TEXT_RU USER_DESC_3
+#define MORE_CUSTOM4_TEXT_RU USER_DESC_4
+#define MORE_CUSTOM5_TEXT_RU USER_DESC_5
+#define MORE_CUSTOM6_TEXT_RU USER_DESC_6
+#define MORE_CUSTOM7_TEXT_RU USER_DESC_7
+
+//Malderin translate
+//
+//
+#define EEPROM_STORE_TIPS_RU "Cохранить настройки в EEPROM?"
+#define EEPROM_READ_TIPS_RU "читать настройки из EEPROM?"
+#define EEPROM_REVERT_TIPS_RU "Cбросить настройки к значениям по умолчанию?"
+#define EEPROM_SETTINGS_RU "EEPROM"
+
+
+#define NEXT_RU "след."
+#define PREVIOUS_RU "пред."
+#define ENABLE_RU "да "
+#define DISABLE_RU "нет"
+#define KEY_CONFIRM_RU "OK"
+
+#define MACHINE_PARA_TITLE_RU "настройки"
+#define MACHINE_TYPE_CNOFIG_RU "Hастройки принтера"
+#define MOTOR_CONFIG_RU "Hастройки моторов"
+#define MACHINE_LEVELING_CONFIG_RU "Hастройки уровня"
+#define ADVANCE_CONFIG_RU "Pасширенные настройки"
+#define MACHINE_FILAMENT_CONFIG_RU "Hастройки филамента"
+#define ENCODER_SETTINGS_RU "Hастройки энкодера"
+
+
+#define LEVELING_CONF_TITLE_RU "Hастройки принтера>Hастройки уровня"
+#define LEVELING_PARA_CONF_RU "настройки уровня"
+#define LEVELING_MANUAL_POS_RU "настройки координат для уровня"
+#define LEVELING_AUTO_COMMAND_RU "настройки комманд увтоуровня"
+#define LEVELING_AUTO_ZOFFSET_RU "координаты смещения сопла"
+#define LEVELING_TOUCHMI_RU "Settings-TouchMi-Probe"
+#define TM_INIT_RU "Init"
+#define TM_ZOFFSETPOS_RU "Zoffset+"
+#define TM_ZOFFSETNEG_RU "Zoffset-"
+#define TM_SAVE_RU "Save"
+#define TM_TEST_RU "Test"
+
+#define BLTOUCH_LEVELING_TITTLE_RU "Settings>BL-Touch Probe"
+#define BLTOUCH_LEVELING_RU "BL-Touch Probe"
+#define BLTOUCH_INIT_RU "Init"
+#define BLTOUCH_ZOFFSETPOS_RU "Zoffset+"
+#define BLTOUCH_ZOFFSETNEG_RU "Zoffset-"
+#define BLTOUCH_SAVE_RU "Save"
+#define BLTOUCH_TEST_RU "Test"
+
+#define MACHINE_CONFIG_TITLE_RU "Hастройки принтера>настройки притера"
+#define MAXFEEDRATE_CONF_RU "настройки максимальной скорости"
+#define ACCELERATION_CONF_RU "настройки ускорений"
+#define JERKCONF_RU "настройки рывков"
+
+#define MOTOR_CONF_TITLE_RU "Hастройки принтера>Hастройки моторов"
+#define STEPSCONF_RU "настройки шагов"
+#define TMC_CURRENT_RU "TMC настройки токов"
+#define TMC_STEP_MODE_RU "TMC настрйоки режима шагов"
+
+#define ACCELERATION_CONF_TITLE_RU "Hастройки принтера>ускорения"
+#define PRINT_ACCELERATION_RU "ускорение печати"
+#define RETRACT_ACCELERATION_RU "ускорение ретракта"
+#define TRAVEL_ACCELERATION_RU "ускорение перемещений"
+#define X_ACCELERATION_RU "ускорение оси X"
+#define Y_ACCELERATION_RU "ускорение оси Y"
+#define Z_ACCELERATION_RU "ускорение оси Z"
+#define E0_ACCELERATION_RU "ускорение E0"
+#define E1_ACCELERATION_RU "ускорение E1"
+
+#define MAXFEEDRATE_CONF_TITLE_RU "Hастройки принтера>максимальная скорость"
+#define X_MAXFEEDRATE_RU "максимальная скорость оси X"
+#define Y_MAXFEEDRATE_RU "максимальная скорость оси Y"
+#define Z_MAXFEEDRATE_RU "максимальная скорость оси Z"
+#define E0_MAXFEEDRATE_RU "максимальная скорость E0"
+#define E1_MAXFEEDRATE_RU "максимальная скорость E1"
+
+#define JERK_CONF_TITLE_RU "Hастройки принтера>скорость рывка"
+#define X_JERK_RU "скорость рывка оси X"
+#define Y_JERK_RU "скорость рывка оси Y"
+#define Z_JERK_RU "скорость рывка оси Z"
+#define E_JERK_RU "скорость рывка оси E"
+
+#define STEPS_CONF_TITLE_RU "Hастройки принтера>настройки шагов"
+#define X_STEPS_RU "шаги оси X"
+#define Y_STEPS_RU "шаги оси Y"
+#define Z_STEPS_RU "шаги оси Z"
+#define E0_STEPS_RU "шаги E0"
+#define E1_STEPS_RU "шаги E1"
+
+#define TMC_CURRENT_CONF_TITLE_RU "Hастройки принтера>TMC настройка токов"
+#define X_TMC_CURRENT_RU "ток оси X (mA)"
+#define Y_TMC_CURRENT_RU "ток оси Y (mA)"
+#define Z_TMC_CURRENT_RU "ток оси Z (mA)"
+#define E0_TMC_CURRENT_RU "ток E0 (mA)"
+#define E1_TMC_CURRENT_RU "ток E1 (mA)"
+
+#define TMC_MODE_CONF_TITLE_RU "Hастройки принтера>TMC настройки режима шагов"
+#define X_TMC_MODE_RU "включает ли двигатель X режим StealthChop"
+#define Y_TMC_MODE_RU "включает ли ось Y режим StealthChop"
+#define Z_TMC_MODE_RU "включает ли ось Z режим StealthChop"
+#define E0_TMC_MODE_RU "включает ли E0 режим StealthChop"
+#define E1_TMC_MODE_RU "включает ли E1 режим StealthChop"
+
+#define ADVANCED_CONF_TITLE_RU "Hастройки принтера>Pасширенные"
+#define PAUSE_POSITION_RU "Hастройки позиции паузы печати"
+#define PAUSE_POSITION_X_RU "положение по X (абс. полож., -1 недействит.)"
+#define PAUSE_POSITION_Y_RU "положение по Y (абс. полож., -1 недействит.)"
+#define PAUSE_POSITION_Z_RU "положение по Z (абс. полож., -1 недействит.)"
+
+#define OFFSET_TITLE_RU "Hастройки принтера>отступ"
+#define OFFSET_X_RU "X отступ"
+#define OFFSET_Y_RU "Y отступ"
+#define OFFSET_Z_RU "Z отступ"
+
+#define FILAMENT_CONF_TITLE_RU "Hастройки принтера>Hастройки филамента"
+#define FILAMENT_IN_LENGTH_RU "длинна загрузки"
+#define FILAMENT_IN_SPEED_RU "скорость загрузки"
+#define FILAMENT_TEMPERATURE_RU "температура филамента"
+#define FILAMENT_OUT_LENGTH_RU "длинна извлечения"
+#define FILAMENT_OUT_SPEED_RU "скорость извлечения"
+
+#define ENCODER_CONF_TITLE_RU "Hастройки принтера>Hастройки энкодера"
+#define ENCODER_CONF_TEXT_RU "энкодер используется?"
+
+//end of Malderin translate
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h
new file mode 100644
index 0000000..4623749
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h
@@ -0,0 +1,518 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//*************简体中文***********************//
+#define NEXT_CN "下一页"
+#define PREVIOUS_CN "上一页"
+#define DEFAULT_CN "默认值"
+#define KEY_BACK_CN "退格"
+#define KEY_REST_CN "重置"
+#define KEY_CONFIRM_CN "确定"
+
+#define MACHINE_PARA_TITLE_CN "机器参数"
+#define MACHINE_TYPE_CNOFIG_CN "机器设置"
+#define MOTOR_CONFIG_CN "电机设置"
+#define MACHINE_LEVELING_CONFIG_CN "调平设置"
+#define ADVANCE_CONFIG_CN "高级设置"
+
+#define MACHINE_CONFIG_TITLE_CN "机器参数>机器配置"
+#define MACHINE_TYPE_CN "机型选择"
+#define MACHINE_STROKE_CN "行程设置"
+#define MACHINE_HOMEDIR_CN "归零方向"
+#define MACHINE_ENDSTOP_TYPE_CN "限位开关类型"
+#define MACHINE_FILAMENT_CONFIG_CN "换料设置"
+
+#define MACHINE_TYPE_CONFIG_TITLE_CN "机器参数>机型选择"
+#define MACHINE_TYPE_XYZ_CN "XYZ机型"
+#define MACHINE_TYPE_DELTA_CN "Delta机型"
+#define MACHINE_TYPE_COREXY_CN "Corexy机型"
+
+#define MACHINE_STROKE_CONF_TITLE_CN "机器参数>机器行程"
+#define X_MAX_LENGTH_CN "X轴最大行程"
+#define Y_MAX_LENGTH_CN "Y轴最大行程"
+#define Z_MAX_LENGTH_CN "Z轴最大行程"
+
+#define X_MIN_LENGTH_CN "X轴最小行程"
+#define Y_MIN_LENGTH_CN "Y轴最小行程"
+#define Z_MIN_LENGTH_CN "Z轴最小行程"
+
+#define HOME_DIR_CONF_TITLE_CN "机器参数>归零方向"
+#define HOME_DIR_X_CN "X轴归零方向"
+#define HOME_DIR_Y_CN "Y轴归零方向"
+#define HOME_DIR_Z_CN "Z轴归零方向"
+#define HOME_MIN_CN "MIN"
+#define HOME_MAX_CN "MAX"
+
+#define ENDSTOP_CONF_TITLE_CN "机器参数>限位开关"
+#define MIN_ENDSTOP_X_CN "X轴最小限位"
+#define MIN_ENDSTOP_Y_CN "Y轴最小限位"
+#define MIN_ENDSTOP_Z_CN "Z轴最小限位"
+#define MAX_ENDSTOP_X_CN "X轴最大限位"
+#define MAX_ENDSTOP_Y_CN "Y轴最大限位"
+#define MAX_ENDSTOP_Z_CN "Z轴最大限位"
+#define ENDSTOP_FIL_CN "断料开关类型"
+#define ENDSTOP_LEVEL_CN "调平开关类型"
+#define ENDSTOP_OPENED_CN "常开"
+#define ENDSTOP_CLOSED_CN "常闭"
+
+#define FILAMENT_CONF_TITLE_CN "换料设置"
+#define FILAMENT_IN_LENGTH_CN "进料长度"
+#define FILAMENT_IN_SPEED_CN "进料速度"
+#define FILAMENT_TEMPERATURE_CN "换料温度"
+#define FILAMENT_OUT_LENGTH_CN "退料长度"
+#define FILAMENT_OUT_SPEED_CN "退料速度"
+
+#define LEVELING_CONF_TITLE_CN "机器参数>调平设置"
+#define LEVELING_PARA_CONF_CN "调平设置"
+#define LEVELING_MANUAL_POS_CN "手动调平坐标设置"
+#define LEVELING_AUTO_COMMAND_CN "自动调平指令设置"
+#define LEVELING_AUTO_ZOFFSET_CN "挤出头与调平开关偏移设置"
+
+#define BLTOUCH_LEVELING_TITTLE_CN "机器参数>BL-Touch Probe"
+#define BLTOUCH_LEVELING_CN "BL-Touch Probe"
+#define BLTOUCH_INIT_CN "初始化"
+#define BLTOUCH_ZOFFSETPOS_CN "Zoffset+"
+#define BLTOUCH_ZOFFSETNEG_CN "Zoffset-"
+#define BLTOUCH_SAVE_CN "保存"
+#define BLTOUCH_TEST_CN "测试"
+
+#define LEVELING_TOUCHMI_CN "机器参数>TouchMi-Probe"
+#define TM_INIT_CN "初始化"
+#define TM_ZOFFSETPOS_CN "Zoffset+"
+#define TM_ZOFFSETNEG_CN "Zoffset-"
+#define TM_SAVE_CN "保存"
+#define TM_TEST_CN "测试"
+
+#define LEVELING_PARA_CONF_TITLE_CN "调平参数"
+#define AUTO_LEVELING_ENABLE_CN "自动调平"
+#define BLTOUCH_LEVELING_ENABLE_CN "启动BLtouch"
+#define PROBE_PORT_CN "调平探针接口"
+#define PROBE_X_OFFSET_CN "探针X方向偏移"
+#define PROBE_Y_OFFSET_CN "探针Y方向偏移"
+#define PROBE_Z_OFFSET_CN "探针Z方向偏移"
+#define PROBE_XY_SPEED_CN "探针XY方向移动速度"
+#define PROBE_Z_SPEED_CN "探针Z方向移动速度"
+#define ENABLE_CN "是"
+#define DISABLE_CN "否"
+#define LOCKED_CN "否"
+#define Z_MIN_CN "ZMin"
+#define Z_MAX_CN "ZMax"
+
+#define DELTA_LEVEL_CONF_TITLE_CN "Delta机器参数"
+#define DELTA_LEVEL_CONF_CN "Delta机器调平"
+#define DELTA_MACHINE_RADIUS_CN "机器半径"
+#define DELTA_DIAGONAL_ROD_CN "机器杆长"
+#define DELTA_PRINT_RADIUS_CN "打印半径"
+#define DELTA_HEIGHT_CN "打印高度"
+#define SMOOTH_ROD_OFFSET_CN "滑块偏移"
+#define EFFECTOR_OFFSET_CN "效应器偏移"
+#define CALIBRATION_RADIUS_CN "调平半径"
+
+#define XYZ_LEVEL_CONF_TITLE_CN "XYZ机器参数"
+#define PROBE_REACH_MAX_LEFT_CN "探针达到最左位置"
+#define PROBE_REACH_MAX_RIGHT_CN "探针达到最右位置"
+#define PROBE_REACH_MAX_FRONT_CN "探针达到最前位置"
+#define PROBE_REACH_MAX_BACK_CN "探针达到最后位置"
+
+#define TEMPERATURE_CONF_TITLE_CN "机器参数>温度设置"
+#define NOZZLE_CONF_CN "喷头设置"
+#define HOTBED_CONF_CN "热床设置"
+#define PREHEAT_TEMPER_CN "预设温度"
+
+#define NOZZLE_CONF_TITLE_CN "机器参数>喷头设置"
+#define NOZZLECNT_CN "喷头数量"
+#define NOZZLE_TYPE_CN "E0温感类型"
+#define NOZZLE_ADJUST_TYPE_CN "PID调温"
+#define NOZZLE_MIN_TEMPERATURE_CN "最低温度"
+#define NOZZLE_MAX_TEMPERATURE_CN "最高温度"
+#define EXTRUD_MIN_TEMPER_CN "最低挤出温度"
+
+#define HOTBED_CONF_TITLE_CN "机器参数>热床设置"
+#define HOTBED_ADJUST_CN "PID调温"
+#define HOTBED_MIN_TEMPERATURE_CN "最低温度"
+#define HOTBED_MAX_TEMPERATURE_CN "最高温度"
+
+#define MOTOR_CONF_TITLE_CN "机器参数>电机设置"
+#define MAXFEEDRATE_CONF_CN "最大速度设置"
+#define ACCELERATION_CONF_CN "加速度设置"
+#define JERKCONF_CN "突变速度设置"
+#define STEPSCONF_CN "脉冲设置"
+#define TMC_CURRENT_CN "TMC 驱动电流设置"
+#define TMC_STEP_MODE_CN "TMC 驱动模式设置"
+#define MOTORDIRCONF_CN "电机方向设置"
+#define HOMEFEEDRATECONF_CN "归零速度设置"
+#define HOMING_SENSITIVITY_CONF_CN "无限位回零灵敏度调节"
+
+#define MAXFEEDRATE_CONF_TITLE_CN "机器参数>最大速度"
+#define X_MAXFEEDRATE_CN "X轴最大速度"
+#define Y_MAXFEEDRATE_CN "Y轴最大速度"
+#define Z_MAXFEEDRATE_CN "Z轴最大速度"
+#define E0_MAXFEEDRATE_CN "E0轴最大速度"
+#define E1_MAXFEEDRATE_CN "E1轴最大速度"
+
+#define ACCELERATION_CONF_TITLE_CN "机器参数>加速度"
+#define PRINT_ACCELERATION_CN "打印加速度"
+#define RETRACT_ACCELERATION_CN "回抽加速度"
+#define TRAVEL_ACCELERATION_CN "空载加速度"
+#define X_ACCELERATION_CN "X轴加速度"
+#define Y_ACCELERATION_CN "Y轴加速度"
+#define Z_ACCELERATION_CN "Z轴加速度"
+#define E0_ACCELERATION_CN "E0轴加速度"
+#define E1_ACCELERATION_CN "E1轴加速度"
+
+#define JERK_CONF_TITLE_CN "机器参数>突变速度"
+#define X_JERK_CN "X轴突变速度"
+#define Y_JERK_CN "Y轴突变速度"
+#define Z_JERK_CN "Z轴突变速度"
+#define E_JERK_CN "E轴突变速度"
+
+#define STEPS_CONF_TITLE_CN "机器参数>脉冲设置"
+#define X_STEPS_CN "X轴脉冲"
+#define Y_STEPS_CN "Y轴脉冲"
+#define Z_STEPS_CN "Z轴脉冲"
+#define E0_STEPS_CN "E0轴脉冲"
+#define E1_STEPS_CN "E1轴脉冲"
+
+#define TMC_CURRENT_CONF_TITLE_CN "机器参数>TMC电流设置"
+#define X_TMC_CURRENT_CN "X轴电流(毫安)"
+#define Y_TMC_CURRENT_CN "Y轴电流(毫安)"
+#define Z_TMC_CURRENT_CN "Z轴电流(毫安)"
+#define E0_TMC_CURRENT_CN "E0轴电流(毫安)"
+#define E1_TMC_CURRENT_CN "E1轴电流(毫安)"
+
+#define TMC_MODE_CONF_TITLE_CN "机器参数>TMC模式设置"
+#define X_TMC_MODE_CN "X轴是否使能静音模式"
+#define Y_TMC_MODE_CN "Y轴是否使能静音模式"
+#define Z_TMC_MODE_CN "Z轴是否使能静音模式"
+#define E0_TMC_MODE_CN "E0轴是否使能静音模式"
+#define E1_TMC_MODE_CN "E1轴是否使能静音模式"
+
+#define MOTORDIR_CONF_TITLE_CN "机器参数>电机方向"
+#define X_MOTORDIR_CN "X轴电机方向"
+#define Y_MOTORDIR_CN "Y轴电机方向"
+#define Z_MOTORDIR_CN "Z轴电机方向"
+#define E0_MOTORDIR_CN "E0轴电机方向"
+#define E1_MOTORDIR_CN "E1轴电机方向"
+#define INVERT_P_CN "正向"
+#define INVERT_N_CN "反向"
+
+#define HOMEFEEDRATE_CONF_TITLE_CN "机器参数>归零速度"
+#define X_HOMESPEED_CN "XY轴归零速度"
+#define Y_HOMESPEED_CN "Y轴归零速度"
+#define Z_HOMESPEED_CN "Z轴归零速度"
+
+#define ADVANCED_CONF_TITLE_CN "机器参数>高级设置"
+#define PWROFF_DECTION_CN "断电检测模块"
+#define PWROFF_AFTER_PRINT_CN "启动打完关机功能"
+#define HAVE_UPS_CN "机器配备UPS电源"
+#define Z2_AND_Z2ENDSTOP_CONF_CN "双Z轴双限位功能设置"
+#define ENABLE_PINS_CONF_CN "电机使能脚电平设置"
+#define WIFI_SETTINGS_CN "Wi-Fi参数设置"
+#define ENCODER_SETTINGS_CN "旋钮设置"
+
+#define Z2_AND_Z2ENDSTOP_CONF_TITLE_CN "双z双限位设置"
+#define Z2_ENABLE_CN "启用Z2轴"
+#define Z2_ENDSTOP_CN "启用Z2限位"
+#define Z2_PORT_CN "Z2限位接口"
+
+#define ENABLE_PINS_CONF_TITLE_CN "电机使能脚电平"
+#define X_ENABLE_PINS_INVERT_CN "X轴电机使能电平"
+#define Y_ENABLE_PINS_INVERT_CN "Y轴电机使能电平"
+#define Z_ENABLE_PINS_INVERT_CN "Z轴电机使能电平"
+#define E_ENABLE_PINS_INVERT_CN "E轴电机使能电平"
+
+#define PAUSE_POSITION_CN "打印暂停位置设置"
+#define PAUSE_POSITION_X_CN "X轴暂停位置(绝对位置,-1无效)"
+#define PAUSE_POSITION_Y_CN "Y轴暂停位置(绝对位置,-1无效)"
+#define PAUSE_POSITION_Z_CN "Z轴暂停位置(相对位置,-1无效)"
+#define WIFI_SETTINGS_TITLE_CN "机器参数>Wi-Fi设置"
+#define WIFI_SETTINGS_MODE_CN "Wi-Fi 模式"
+#define WIFI_SETTINGS_NAME_CN "Wi-Fi 名称: "
+#define WIFI_SETTINGS_PASSWORD_CN "Wi-Fi 密码: "
+#define WIFI_SETTINGS_CLOUD_CN "是否使用云服务?"
+#define WIFI_SETTINGS_CONFIG_CN "配置"
+#define WIFI_SETTINGS_EDIT_CN "编辑"
+#define WIFI_CONFIG_TIPS_CN "进行Wi-Fi配置?"
+
+#define OFFSET_TITLE_CN "机器参数>偏移设置"
+#define OFFSET_X_CN "X轴与调平开关偏移"
+#define OFFSET_Y_CN "Y轴与调平开关偏移"
+#define OFFSET_Z_CN "Z轴与调平开关偏移"
+
+#define HOMING_SENSITIVITY_CONF_TITLE_CN "机器参数>灵敏度调节"
+#define X_SENSITIVITY_CN "X轴灵敏度"
+#define Y_SENSITIVITY_CN "Y轴灵敏度"
+#define Z_SENSITIVITY_CN "Z轴灵敏度"
+#define Z2_SENSITIVITY_CN "Z2轴灵敏度"
+
+#define ENCODER_CONF_TITLE_CN "机器参数>旋钮设置"
+#define ENCODER_CONF_TEXT_CN "是否使用旋钮功能?"
+
+#define TOOL_TEXT_CN "工具"
+#define PREHEAT_TEXT_CN "预热"
+#define MOVE_TEXT_CN "移动"
+#define HOME_TEXT_CN "回零"
+#define PRINT_TEXT_CN "打印"
+#define EXTRUDE_TEXT_CN "挤出"
+#define LEVELING_TEXT_CN "调平"
+#define AUTO_LEVELING_TEXT_CN "自动调平"
+#define SET_TEXT_CN "设置"
+#define MORE_TEXT_CN "更多"
+
+#define ADD_TEXT_CN "增加"
+#define DEC_TEXT_CN "减少"
+#define EXTRUDER_1_TEXT_CN "喷头1"
+#define EXTRUDER_2_TEXT_CN "喷头2"
+#define HEATBED_TEXT_CN "热床"
+#define TEXT_1C_CN "1℃"
+#define TEXT_5C_CN "5℃"
+#define TEXT_10C_CN "10℃"
+#define CLOSE_TEXT_CN "关闭"
+
+#define BACK_TEXT_CN "返回"
+
+#define TOOL_PREHEAT_CN "预热"
+#define TOOL_EXTRUDE_CN "挤出"
+#define TOOL_MOVE_CN "移动"
+#define TOOL_HOME_CN "回零"
+#define TOOL_LEVELING_CN "调平"
+#define TOOL_AUTO_LEVELING_CN "自动调平"
+#define TOOL_FILAMENT_CN "换料"
+#define TOOL_MORE_CN "更多"
+
+#define AXIS_X_ADD_TEXT_CN "X+"
+#define AXIS_X_DEC_TEXT_CN "X-"
+#define AXIS_Y_ADD_TEXT_CN "Y+"
+#define AXIS_Y_DEC_TEXT_CN "Y-"
+#define AXIS_Z_ADD_TEXT_CN "Z+"
+#define AXIS_Z_DEC_TEXT_CN "Z-"
+#define TEXT_01MM_CN "0.1mm"
+#define TEXT_1MM_CN "1mm"
+#define TEXT_10MM_CN "10mm"
+
+#define HOME_X_TEXT_CN "X"
+#define HOME_Y_TEXT_CN "Y"
+#define HOME_Z_TEXT_CN "Z"
+#define HOME_ALL_TEXT_CN "回零"
+#define HOME_STOPMOVE_CN "急停"
+
+#define PAGE_UP_TEXT_CN "上一页"
+#define PAGE_DOWN_TEXT_CN "下一页"
+
+#define EXTRUDER_IN_TEXT_CN "进料"
+#define EXTRUDER_OUT_TEXT_CN "退料"
+#define EXTRUDE_1MM_TEXT_CN "1mm"
+#define EXTRUDE_5MM_TEXT_CN "5mm"
+#define EXTRUDE_10MM_TEXT_CN "10mm"
+#define EXTRUDE_LOW_SPEED_TEXT_CN "低速"
+#define EXTRUDE_MEDIUM_SPEED_TEXT_CN "常速"
+#define EXTRUDE_HIGH_SPEED_TEXT_CN "高速"
+
+#define LEVELING_POINT1_TEXT_CN "第一点"
+#define LEVELING_POINT2_TEXT_CN "第二点"
+#define LEVELING_POINT3_TEXT_CN "第三点"
+#define LEVELING_POINT4_TEXT_CN "第四点"
+#define LEVELING_POINT5_TEXT_CN "第五点"
+
+#define FILESYS_TEXT_CN "文件系统"
+#define WIFI_TEXT_CN "WIFI"
+#define FAN_TEXT_CN "风扇"
+#define ABOUT_TEXT_CN "关于"
+#define BREAK_POINT_TEXT_CN "断点续打"
+#define FILAMENT_TEXT_CN "换料"
+#define LANGUAGE_TEXT_CN "语言"
+#define MOTOR_OFF_TEXT_CN "关闭电机"
+#define MOTOR_OFF_XY_TEXT_CN "关闭XY"
+#define SHUTDOWN_TEXT_CN "关机"
+#define MACHINE_PARA_CN "机器参数"
+#define EEPROM_SETTINGS_CN "Eeprom设置"
+
+#define U_DISK_TEXT_CN "U盘"
+#define SD_CARD_TEXT_CN "SD卡"
+#define WIFI_NAME_TEXT_CN "无线网络:"
+#define WIFI_KEY_TEXT_CN "密码: "
+#define WIFI_IP_TEXT_CN "IP: "
+#define WIFI_AP_TEXT_CN "状态: AP"
+#define WIFI_STA_TEXT_CN "状态: STA"
+#define WIFI_CONNECTED_TEXT_CN "已连接"
+#define WIFI_DISCONNECTED_TEXT_CN "未连接"
+#define WIFI_EXCEPTION_TEXT_CN "模块异常"
+#define CLOUD_TEXT_CN "云服务"
+#define CLOUD_BIND_CN "已绑定"
+#define CLOUD_UNBIND_CN "解绑"
+#define CLOUD_UNBINDING_CN "解绑中"
+#define CLOUD_DISCONNECTED_CN "未连接"
+#define CLOUD_UNBINDED_CN "未绑定"
+#define CLOUD_BINDED_CN "已绑定"
+#define CLOUD_DISABLE_CN "已禁用"
+
+#define FAN_ADD_TEXT_CN "增加"
+#define FAN_DEC_TEXT_CN "减少"
+#define FAN_OPEN_TEXT_CN "100%"
+#define FAN_HALF_TEXT_CN "50%"
+#define FAN_CLOSE_TEXT_CN "关闭"
+#define FAN_TIPS1_TEXT_CN "风扇"
+#define FAN_TIPS2_TEXT_CN "FAN\nClose"
+
+#define FILAMENT_IN_TEXT_CN "进料"
+#define FILAMENT_OUT_TEXT_CN "退料"
+#define FILAMENT_EXT0_TEXT_CN "喷头1"
+#define FILAMENT_EXT1_TEXT_CN "喷头2"
+#define FILAMENT_HEAT_TEXT_CN "预热"
+#define FILAMENT_STOP_TEXT_CN "停止"
+#define FILAMENT_CHANGE_TEXT_CN "待打印机暂停后,\n请按<进料>或<退料>"
+
+#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_CN "准备进料,正在加热,请稍等!"
+#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_CN "准备退料,正在加热,请稍等!"
+#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_CN "加热完成,请装载耗材后,按<确定>开始进料!"
+#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_CN "请装载耗材,按<确定>开始进料!"
+#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_CN "加热完成,请按<确定>开始退料!"
+#define FILAMENT_DIALOG_LOADING_TIPS_CN "正在进料,请等待耗材加载完成!"
+#define FILAMENT_DIALOG_UNLOADING_TIPS_CN "正在退料,请等待耗材卸载完成!"
+#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_CN "进料完成,请按<确定>返回"
+#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_CN "退料完成,请按<确定>返回"
+
+#define FILAMENT_TIPS3_TEXT_CN "正在进料"
+#define FILAMENT_TIPS4_TEXT_CN "正在退料"
+#define FILAMENT_TIPS5_TEXT_CN "温度太低,请先预热"
+#define FILAMENT_TIPS6_TEXT_CN "换料完成"
+
+#define PRE_HEAT_EXT_TEXT_CN "喷头"
+#define PRE_HEAT_BED_TEXT_CN "热床"
+
+#define FILE_LOADING_CN "正在载入......"
+#define NO_FILE_AND_CHECK_CN "无文件!请插入sd卡或u盘!"
+#define NO_FILE_CN "无文件!"
+
+#define EXTRUDER_TEMP_TEXT_CN "温度"
+#define EXTRUDER_E_LENGTH1_TEXT_CN "喷头"
+#define EXTRUDER_E_LENGTH2_TEXT_CN "喷头"
+#define EXTRUDER_E_LENGTH3_TEXT_CN "喷头"
+
+#define ABOUT_TYPE_TEXT_CN "Type: "
+#define ABOUT_VERSION_TEXT_CN "Firmware: "
+#define ABOUT_WIFI_TEXT_CN "Wifi: "
+
+#define PRINTING_OPERATION_CN "操作"
+#define PRINTING_PAUSE_CN "暂停"
+#define PRINTING_TEMP_CN "温度"
+#define PRINTING_CHANGESPEED_CN "变速"
+#define PRINTING_RESUME_CN "恢复"
+#define PRINTING_STOP_CN "停止"
+#define PRINTING_MORE_CN "更多"
+#define PRINTING_EXTRUDER_CN "挤出"
+#define PRINTING_MOVE_CN "移动"
+
+#define EXTRUDER_SPEED_CN "挤出"
+#define MOVE_SPEED_CN "移动"
+#define EXTRUDER_SPEED_STATE_CN "挤出速度"
+#define MOVE_SPEED_STATE_CN "移动速度"
+#define STEP_1PERCENT_CN "1%"
+#define STEP_5PERCENT_CN "5%"
+#define STEP_10PERCENT_CN "10%"
+
+#define TITLE_READYPRINT_CN "准备打印"
+#define TITLE_PREHEAT_CN "预热"
+#define TITLE_MOVE_CN "移动"
+#define TITLE_HOME_CN "回零"
+#define TITLE_EXTRUDE_CN "挤出"
+#define TITLE_LEVELING_CN "调平"
+#define TITLE_SET_CN "设置"
+#define TITLE_MORE_CN "更多"
+#define TITLE_CHOOSEFILE_CN "选择文件"
+#define TITLE_PRINTING_CN "正在打印"
+#define TITLE_OPERATION_CN "操作"
+#define TITLE_ADJUST_CN "调整"
+#define TITLE_WIRELESS_CN "无线网络"
+#define TITLE_FILAMENT_CN "换料"
+#define TITLE_ABOUT_CN "关于"
+#define TITLE_FAN_CN "风扇"
+#define TITLE_LANGUAGE_CN "语言"
+#define TITLE_PAUSE_CN "暂停"
+#define TITLE_CHANGESPEED_CN "变速"
+#define TITLE_CLOUD_TEXT_CN "云服务"
+#define TITLE_DIALOG_CONFIRM_CN "确认"
+#define TITLE_FILESYS_CN "文件系统"
+
+#define AUTO_SHUTDOWN_CN "自动关机"
+#define MANUAL_SHUTDOWN_CN "手动关机"
+
+#define DIALOG_CONFIRM_CN "确定"
+#define DIALOG_CANCLE_CN "取消"
+#define DIALOG_OK_CN "确认"
+#define DIALOG_RESET_CN "重置"
+#define DIALOG_DISABLE_CN "禁用"
+#define DIALOG_PRINT_MODEL_CN "打印模型?"
+#define DIALOG_CANCEL_PRINT_CN "停止打印?"
+#define DIALOG_RETRY_CN "重试"
+#define DIALOG_STOP_CN "停止"
+#define DIALOG_REPRINT_FROM_BREAKPOINT_CN "从断点续打?"
+#define DIALOG_ERROR_TIPS1_CN "错误:找不到文件,请插入sd卡/u盘!"
+#define DIALOG_ERROR_TIPS2_CN "错误:通信失败,请检查波特率或主板硬件!"
+#define DIALOG_ERROR_TIPS3_CN "错误:文件名或文件路径太长 !"
+#define DIALOG_CLOSE_MACHINE_CN "正在关机......"
+#define DIALOG_UNBIND_PRINTER_CN "解除绑定?"
+#define DIALOG_FILAMENT_NO_PRESS_CN "请先装载耗材!"
+#define DIALOG_PRINT_FINISH_CN "打印完成!"
+#define DIALOG_PRINT_TIME_CN "打印时间: "
+#define DIALOG_REPRINT_CN "再打印一次"
+#define DIALOG_WIFI_ENABLE_TIPS_CN "wifi模块正在配置中,请稍等......"
+#define DIALOG_PAUSING_TIPS_CN "机器暂停中..."
+
+#define TEXT_VALUE_CN "%d℃/%d℃"
+#define EXTRUDE_TEXT_VALUE_T_CN ": %d℃"
+#define WIFI_RECONNECT_TEXT_CN "重新连接"
+
+#define PRINTING_GBK "正在打印"
+#define PRINTING_OPERATION_GBK "操作"
+#define PRINTING_PAUSE_GBK "暂停"
+
+#define MESSAGE_PAUSING_CN "暂停中..."
+#define MESSAGE_CHANGING_CN "等待换料开始..."
+#define MESSAGE_UNLOAD_CN "退料中,请稍等..."
+#define MESSAGE_WAITING_CN "点击按钮恢复打印"
+#define MESSAGE_INSERT_CN "装载耗材后,点击按钮开始打印"
+#define MESSAGE_LOAD_CN "进料中,请稍等..."
+#define MESSAGE_PURGE_CN "等待挤出..."
+#define MESSAGE_RESUME_CN "等待恢复打印..."
+#define MESSAGE_HEAT_CN "按下按钮,加热喷头"
+#define MESSAGE_HEATING_CN "喷头加热中,请等待..."
+#define MESSAGE_OPTION_CN "挤出更多还是继续打印?"
+#define MESSAGE_PURGE_MORE_CN "挤出"
+#define MESSAGE_CONTINUE_PRINT_CN "打印"
+#define EEPROM_SETTINGS_TITLE_CN "EEPROM 设置"
+#define EEPROM_SETTINGS_STORE_CN "保存参数至EEPROM"
+#define EEPROM_SETTINGS_READ_CN "读取EEPROM参数"
+#define EEPROM_SETTINGS_REVERT_CN "恢复默认参数"
+
+#define EEPROM_STORE_TIPS_CN "是否保存参数到EEPROM?"
+#define EEPROM_READ_TIPS_CN "是否使用EEPROM参数?"
+#define EEPROM_REVERT_TIPS_CN "是否恢复默认参数?"
+
+#define MORE_CUSTOM1_TEXT_CN USER_DESC_1
+#define MORE_CUSTOM2_TEXT_CN USER_DESC_2
+#define MORE_CUSTOM3_TEXT_CN USER_DESC_3
+#define MORE_CUSTOM4_TEXT_CN USER_DESC_4
+#define MORE_CUSTOM5_TEXT_CN USER_DESC_5
+#define MORE_CUSTOM6_TEXT_CN USER_DESC_6
+#define MORE_CUSTOM7_TEXT_CN USER_DESC_7
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h
new file mode 100644
index 0000000..675af55
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h
@@ -0,0 +1,274 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//****************西班牙语***************************
+#define TOOL_TEXT_SP "Ajustes"
+#define PREHEAT_TEXT_SP "Precalentar"
+#define MOVE_TEXT_SP "Mover"
+#define HOME_TEXT_SP "Origen"
+#define PRINT_TEXT_SP "Imprimir"
+#define EXTRUDE_TEXT_SP "Extrusor"
+#define LEVELING_TEXT_SP "Leveling"
+#define MLEVELING_TEXT_SP "Leveling"
+#define AUTO_LEVELING_TEXT_SP "Autolevel"
+#define SET_TEXT_SP "Config"
+#define MORE_TEXT_SP "Más"
+
+#define ADD_TEXT_SP "Más"
+#define DEC_TEXT_SP "Menos"
+#define EXTRUDER_1_TEXT_SP "Extrusor1: "
+#define EXTRUDER_2_TEXT_SP "Extrusor2: "
+#define HEATBED_TEXT_SP "Cama: "
+#define TEXT_1C_SP "1℃"
+#define TEXT_5C_SP "5℃"
+#define TEXT_10C_SP "10℃"
+#define CLOSE_TEXT_SP "Apagar"
+
+#define BACK_TEXT_SP "Atrás"
+
+#define TOOL_PREHEAT_SP "Precalentar"
+#define TOOL_EXTRUDE_SP "Extrusor"
+#define TOOL_MOVE_SP "Mover"
+#define TOOL_HOME_SP "Origen"
+#define TOOL_LEVELING_SP "Leveling"
+#define TOOL_MLEVELING_SP "Leveling"
+#define TOOL_AUTO_LEVELING_SP "Autolevel"
+#define TOOL_FILAMENT_SP "Filamento"
+#define TOOL_MORE_SP "Más"
+
+#define AXIS_X_ADD_TEXT_SP "X+"
+#define AXIS_X_DEC_TEXT_SP "X-"
+#define AXIS_Y_ADD_TEXT_SP "Y+"
+#define AXIS_Y_DEC_TEXT_SP "Y-"
+#define AXIS_Z_ADD_TEXT_SP "Z+"
+#define AXIS_Z_DEC_TEXT_SP "Z-"
+#define TEXT_01MM_SP "0.1mm"
+#define TEXT_1MM_SP "1mm"
+#define TEXT_10MM_SP "10mm"
+
+#define HOME_X_TEXT_SP "EJE X"
+#define HOME_Y_TEXT_SP "EJE Y"
+#define HOME_Z_TEXT_SP "EJE Z"
+#define HOME_ALL_TEXT_SP "TODOS"
+#define HOME_STOPMOVE_SP "Quickstop"
+
+#define PAGE_UP_TEXT_SP "Arriba"
+#define PAGE_DOWN_TEXT_SP "Abajo"
+
+#define EXTRUDER_IN_TEXT_SP "Dentro"
+#define EXTRUDER_OUT_TEXT_SP "Fuera"
+#define EXTRUDE_1MM_TEXT_SP "1mm"
+#define EXTRUDE_5MM_TEXT_SP "5mm"
+#define EXTRUDE_10MM_TEXT_SP "10mm"
+#define EXTRUDE_LOW_SPEED_TEXT_SP "Baja"
+#define EXTRUDE_MEDIUM_SPEED_TEXT_SP "Media"
+#define EXTRUDE_HIGH_SPEED_TEXT_SP "Alta"
+
+#define LEVELING_POINT1_TEXT_SP "Primero"
+#define LEVELING_POINT2_TEXT_SP "Segundo"
+#define LEVELING_POINT3_TEXT_SP "Tercero"
+#define LEVELING_POINT4_TEXT_SP "Cuarto"
+#define LEVELING_POINT5_TEXT_SP "Quinto"
+
+#define FILESYS_TEXT_SP "Puerto"
+#define WIFI_TEXT_SP "WiFi"
+#define FAN_TEXT_SP "Ventilador"
+#define ABOUT_TEXT_SP "Acerca"
+#define BREAK_POINT_TEXT_SP "Continuar"
+#define FILAMENT_TEXT_SP "Filamento"
+#define LANGUAGE_TEXT_SP "Language"
+#define MOTOR_OFF_TEXT_SP "Apagar motor"
+#define MOTOR_OFF_XY_TEXT_SP "Off-XY"
+#define SHUTDOWN_TEXT_SP "Apagar"
+#define MACHINE_PARA_SP "Config"
+#define EEPROM_SETTINGS_SP "Eeprom Set"
+
+#define U_DISK_TEXT_SP "PENDRIVE"
+#define SD_CARD_TEXT_SP "SD"
+#define WIFI_NAME_TEXT_SP "WIFI: "
+#define WIFI_KEY_TEXT_SP "Contraseña: "
+#define WIFI_IP_TEXT_SP "IP: "
+#define WIFI_AP_TEXT_SP "Estado: AP"
+#define WIFI_STA_TEXT_SP "Estado: STA"
+#define WIFI_CONNECTED_TEXT_SP "Conectado"
+#define WIFI_DISCONNECTED_TEXT_SP "Desconectado"
+#define WIFI_EXCEPTION_TEXT_SP "Excepción"
+#define WIFI_RECONNECT_TEXT_SP "Reconnect"
+#define CLOUD_TEXT_SP "Nube"
+#define CLOUD_BIND_SP "Atado"
+#define CLOUD_UNBIND_SP "Sin atar"
+#define CLOUD_UNBINDING_SP "Unbinding"
+#define CLOUD_DISCONNECTED_SP "Disconnected"
+#define CLOUD_UNBINDED_SP "Unbinded"
+#define CLOUD_BINDED_SP "Binded"
+#define CLOUD_DISABLE_SP "Disable"
+
+#define FAN_ADD_TEXT_SP "Más"
+#define FAN_DEC_TEXT_SP "Menos"
+#define FAN_OPEN_TEXT_SP "100%"
+#define FAN_HALF_TEXT_SP "50%"
+#define FAN_CLOSE_TEXT_SP "0%"
+#define FAN_TIPS1_TEXT_SP "ventilador"
+#define FAN_TIPS2_TEXT_SP "ventilador\n0"
+
+#define FILAMENT_IN_TEXT_SP "Dentro"
+#define FILAMENT_OUT_TEXT_SP "Fuera"
+#define FILAMENT_EXT0_TEXT_SP "Extrusor1"
+#define FILAMENT_EXT1_TEXT_SP "Extrusor2"
+#define FILAMENT_HEAT_TEXT_SP "Precalentar"
+#define FILAMENT_STOP_TEXT_SP "Parar"
+#define FILAMENT_TIPS2_TEXT_SP "T:"
+#define FILAMENT_TIPS3_TEXT_SP "Dentro..."
+#define FILAMENT_TIPS4_TEXT_SP "Fuera..."
+#define FILAMENT_TIPS5_TEXT_SP "Temperatura demasiado baja, por favor calentar"
+#define FILAMENT_TIPS6_TEXT_SP "Completado"
+
+#define FILAMENT_CHANGE_TEXT_SP "Please click <Load> \nor <unload>,After \npinter pause."
+#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_SP "Calentando el extrusor,\npor favor espere..."
+#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_SP "Calentando el extrusor,\npor favor espere..."
+#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_SP "Temperatura alcanzada.Inserte el \nfilamento y luego presione\"Confirmar\"\npara comenzar la carga."
+#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_SP "Inserte el filamento y \nluego presione\"Confirmar\"para \ncomenzar la carga."
+#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_SP "Temperatura alcanzada.\nPresione\"Confirmar\"para retirar \nel filamento."
+#define FILAMENT_DIALOG_LOADING_TIPS_SP "Cargando filamento,\npor favor espere."
+#define FILAMENT_DIALOG_UNLOADING_TIPS_SP "Retirando filamento,\npor favor espere."
+#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_SP "Filamento cargado,\npresione\"Confirmar\"."
+#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_SP "Filamento retirado,\npresione\"Confirmar\"."
+
+#define PRE_HEAT_EXT_TEXT_SP "Extrusor"
+#define PRE_HEAT_BED_TEXT_SP "cama"
+
+#define FILE_LOADING_SP "Cargando......"
+#define NO_FILE_AND_CHECK_SP "Archivo no encontrado,\n por favor insertar SD o disco USB!"
+#define NO_FILE_SP "Sin archivo!"
+
+#define EXTRUDER_TEMP_TEXT_SP "Temper"
+#define EXTRUDER_E_LENGTH1_TEXT_SP "Extrusor1"
+#define EXTRUDER_E_LENGTH2_TEXT_SP "Extrusor2"
+#define EXTRUDER_E_LENGTH3_TEXT_SP "Extrusor3"
+
+#define ABOUT_TYPE_TEXT_SP "Pantalla: "
+#define ABOUT_VERSION_TEXT_SP "Firmware: "
+#define ABOUT_WIFI_TEXT_SP "WiFi: "
+
+#define PRINTING_OPERATION_SP "Ajustes"
+#define PRINTING_PAUSE_SP "Pausar"
+#define PRINTING_TEMP_SP "Temp."
+#define PRINTING_CHANGESPEED_SP "Velocidad"
+#define PRINTING_RESUME_SP "Resumir"
+#define PRINTING_STOP_SP "Detener"
+#define PRINTING_MORE_SP "Más"
+#define PRINTING_EXTRUDER_SP "Extrusor"
+#define PRINTING_MOVE_SP "Mover"
+
+#define EXTRUDER_SPEED_SP "Extrusor"
+#define MOVE_SPEED_SP "Mover"
+#define EXTRUDER_SPEED_STATE_SP "Extrusión"
+#define MOVE_SPEED_STATE_SP "Movimiento"
+#define STEP_1PERCENT_SP "1%"
+#define STEP_5PERCENT_SP "5%"
+#define STEP_10PERCENT_SP "10%"
+
+#define TITLE_READYPRINT_SP "Inicio"
+#define TITLE_PREHEAT_SP "Precalentar"
+#define TITLE_MOVE_SP "Mover"
+#define TITLE_HOME_SP "Origen"
+#define TITLE_EXTRUDE_SP "Extrusor"
+#define TITLE_LEVELING_SP "Leveling"
+#define TITLE_SET_SP "Config"
+#define TITLE_MORE_SP "Más"
+#define TITLE_CHOOSEFILE_SP "Imprimir"
+#define TITLE_PRINTING_SP "Imprimir"
+#define TITLE_OPERATION_SP "Ajustes"
+#define TITLE_ADJUST_SP "Temp."
+#define TITLE_WIRELESS_SP "Wireless"
+#define TITLE_FILAMENT_SP "Filamento"
+#define TITLE_ABOUT_SP "Acerca"
+#define TITLE_FAN_SP "Ventilador"
+#define TITLE_LANGUAGE_SP "Language"
+#define TITLE_PAUSE_SP "Pausar"
+#define TITLE_CHANGESPEED_SP "Velocidad"
+#define TILE_TOOL_SP "Ajustes"
+#define TITLE_CLOUD_TEXT_SP "Cloud"
+#define TITLE_DIALOG_CONFIRM_SP "Confirmar"
+#define TITLE_FILESYS_SP "Puerto"
+
+#define AUTO_SHUTDOWN_SP "Auto"
+#define MANUAL_SHUTDOWN_SP "manual"
+
+#define DIALOG_CONFIRM_SP "Confirmar"
+#define DIALOG_CANCLE_SP "Cancelar"
+#define DIALOG_OK_SP "OK"
+#define DIALOG_RESET_SP "Resetear"
+#define DIALOG_RETRY_SP "Reintentar"
+#define DIALOG_DISABLE_SP "Desactivar"
+#define DIALOG_PRINT_MODEL_SP "¿Está seguro?"
+#define DIALOG_CANCEL_PRINT_SP "¿Está seguro que desea detener la impresión?"
+
+#define DIALOG_RETRY_SP "Reintentar"
+#define DIALOG_STOP_SP "Stop"
+#define DIALOG_REPRINT_FROM_BREAKPOINT_SP "Reprint from breakpoint?"
+#define DIALOG_ERROR_TIPS1_SP "Error:archivo no encontrado, \npor favor insertar SD o disco USB."
+#define DIALOG_ERROR_TIPS2_SP "error:transacción fallida, \nconfigurar baudrate del \ndisplay para la placa base!"
+#define DIALOG_ERROR_TIPS3_SP "Error : nombre de archivo o \nruta demasiado largo!"
+#define DIALOG_CLOSE_MACHINE_SP "Closing machine......"
+#define DIALOG_UNBIND_PRINTER_SP "Unbind the printer?"
+#define DIALOG_FILAMENT_NO_PRESS_SP "Filament detection switch is not pressed"
+#define DIALOG_PRINT_FINISH_SP "¡La impresión está completa!"
+#define DIALOG_PRINT_TIME_SP "Tiempo de impresión: "
+#define DIALOG_REPRINT_SP "Print again"
+#define DIALOG_WIFI_ENABLE_TIPS_SP "The wifi module is being configured,\nplease wait a moment....."
+#define DIALOG_PAUSING_TIPS_SP "La máquina se detiene ..."
+
+#define PRINTING_SP "Imprimiendo"
+#define PRINTING_AJUSTES_SP "Ajustes"
+#define PRINTING_PAUSAR_SP "Pausar"
+
+#define MESSAGE_PAUSING_SP "Aparcando..."
+#define MESSAGE_CHANGING_SP "Esperando para iniciar el cambio de filamento"
+#define MESSAGE_UNLOAD_SP "Espere para liberar el filamento"
+#define MESSAGE_WAITING_SP "Pulsar el botón para reanudar impresión"
+#define MESSAGE_INSERT_SP "Inserte el filamento y pulse el botón para continuar..."
+#define MESSAGE_LOAD_SP "Espere para purgar el filamento"
+#define MESSAGE_PURGE_SP "Espere para purgar el filamento"
+#define MESSAGE_RESUME_SP "Esperando impresora para reanudar..."
+#define MESSAGE_HEAT_SP "Pulse el botón para calentar la boquilla"
+#define MESSAGE_HEATING_SP "Calentando boquilla Espere por favor..."
+#define MESSAGE_OPTION_SP "¿Purgar más o continuar con la impresión?"
+#define MESSAGE_PURGE_MORE_SP "Purga"
+#define MESSAGE_CONTINUE_PRINT_SP "Impresión"
+#define EEPROM_SETTINGS_TITLE_SP "Configuraciones EEPROM"
+#define EEPROM_SETTINGS_STORE_SP "Guardar configuración en EEPROM"
+#define EEPROM_SETTINGS_READ_SP "Leer la configuración de EEPROM"
+#define EEPROM_SETTINGS_REVERT_SP "Revert settings to factory defaults"
+
+#define EEPROM_STORE_TIPS_SP "¿Guardar ajustes en EEPROM?"
+#define EEPROM_READ_TIPS_SP "Leer la configuración de EEPROM?"
+#define EEPROM_REVERT_TIPS_SP "Revert settings to factory defaults?"
+
+#define MORE_CUSTOM1_TEXT_SP USER_DESC_1
+#define MORE_CUSTOM2_TEXT_SP USER_DESC_2
+#define MORE_CUSTOM3_TEXT_SP USER_DESC_3
+#define MORE_CUSTOM4_TEXT_SP USER_DESC_4
+#define MORE_CUSTOM5_TEXT_SP USER_DESC_5
+#define MORE_CUSTOM6_TEXT_SP USER_DESC_6
+#define MORE_CUSTOM7_TEXT_SP USER_DESC_7
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h
new file mode 100644
index 0000000..e97c63c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h
@@ -0,0 +1,515 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+//***************繁体中文**********************//
+#define NEXT_T_CN "下一頁"
+#define PREVIOUS_T_CN "上一頁"
+#define DEFAULT_T_CN "默認值"
+#define KEY_BACK_T_CN "退格"
+#define KEY_REST_T_CN "重置"
+#define KEY_CONFIRM_T_CN "確定"
+
+#define MACHINE_PARA_TITLE_T_CN "機器參數"
+#define MACHINE_TYPE_CNOFIG_T_CN "機器設置"
+#define MOTOR_CONFIG_T_CN "電機設置"
+#define MACHINE_LEVELING_CONFIG_T_CN "調平設置"
+#define ADVANCE_CONFIG_T_CN "高級設置"
+
+#define MACHINE_CONFIG_TITLE_T_CN "機器參數>機器配置"
+#define MACHINE_TYPE_T_CN "機型選擇"
+#define MACHINE_STROKE_T_CN "行程設置"
+#define MACHINE_HOMEDIR_T_CN "歸零方向"
+#define MACHINE_ENDSTOP_TYPE_T_CN "限位開關類型"
+#define MACHINE_FILAMENT_CONFIG_T_CN "換料設置"
+
+#define MACHINE_TYPE_CONFIG_TITLE_T_CN "機器參數>機型選擇"
+#define MACHINE_TYPE_XYZ_T_CN "XYZ機型"
+#define MACHINE_TYPE_DELTA_T_CN "Delta機型"
+#define MACHINE_TYPE_COREXY_T_CN "Corexy機型"
+
+#define MACHINE_STROKE_CONF_TITLE_T_CN "機器參數>機器行程"
+#define X_MAX_LENGTH_T_CN "X軸最大行程"
+#define Y_MAX_LENGTH_T_CN "Y軸最大行程"
+#define Z_MAX_LENGTH_T_CN "Z軸最大行程"
+
+#define X_MIN_LENGTH_T_CN "X軸最小行程"
+#define Y_MIN_LENGTH_T_CN "Y軸最小行程"
+#define Z_MIN_LENGTH_T_CN "Z軸最小行程"
+
+#define HOME_DIR_CONF_TITLE_T_CN "機器參數>歸零方向"
+#define HOME_DIR_X_T_CN "X軸歸零方向"
+#define HOME_DIR_Y_T_CN "Y軸歸零方向"
+#define HOME_DIR_Z_T_CN "Z軸歸零方向"
+#define HOME_MIN_T_CN "MIN"
+#define HOME_MAX_T_CN "MAX"
+
+#define ENDSTOP_CONF_TITLE_T_CN "機器參數>限位開關"
+#define MIN_ENDSTOP_X_T_CN "X軸最小限位"
+#define MIN_ENDSTOP_Y_T_CN "Y軸最小限位"
+#define MIN_ENDSTOP_Z_T_CN "Z軸最小限位"
+#define MAX_ENDSTOP_X_T_CN "X軸最大限位"
+#define MAX_ENDSTOP_Y_T_CN "Y軸最大限位"
+#define MAX_ENDSTOP_Z_T_CN "Z軸最大限位"
+#define ENDSTOP_FIL_T_CN "斷料開關類型"
+#define ENDSTOP_LEVEL_T_CN "調平開關類型"
+#define ENDSTOP_OPENED_T_CN "常開"
+#define ENDSTOP_CLOSED_T_CN "常閉"
+
+#define FILAMENT_CONF_TITLE_T_CN "換料設置"
+#define FILAMENT_IN_LENGTH_T_CN "進料長度"
+#define FILAMENT_IN_SPEED_T_CN "進料速度"
+#define FILAMENT_TEMPERATURE_T_CN "換料溫度"
+#define FILAMENT_OUT_LENGTH_T_CN "退料長度"
+#define FILAMENT_OUT_SPEED_T_CN "退料速度"
+
+#define LEVELING_CONF_TITLE_T_CN "機器參數>調平設置"
+#define LEVELING_PARA_CONF_T_CN "調平設置"
+#define LEVELING_MANUAL_POS_T_CN "手動調平坐標設置"
+#define LEVELING_AUTO_COMMAND_T_CN "自動調平指令設置"
+#define LEVELING_AUTO_ZOFFSET_T_CN "擠出頭與調平開關偏移設置"
+#define LEVELING_TOUCHMI_T_CN "機器參數>TouchMi-Probe"
+#define TM_INIT_T_CN "初始化"
+#define TM_ZOFFSETPOS_T_CN "Zoffset+"
+#define TM_ZOFFSETNEG_T_CN "Zoffset-"
+#define TM_SAVE_T_CN "保存"
+#define TM_TEST_T_CN "測試"
+
+#define BLTOUCH_LEVELING_TITTLE_T_CN "機器參數>BL-Touch Probe"
+#define BLTOUCH_LEVELING_T_CN "BL-Touch Probe"
+#define BLTOUCH_INIT_T_CN "初始化"
+#define BLTOUCH_ZOFFSETPOS_T_CN "Zoffset+"
+#define BLTOUCH_ZOFFSETNEG_T_CN "Zoffset-"
+#define BLTOUCH_SAVE_T_CN "保存"
+#define BLTOUCH_TEST_T_CN "測試"
+
+#define LEVELING_PARA_CONF_TITLE_T_CN "調平參數"
+#define AUTO_LEVELING_ENABLE_T_CN "自動調平"
+#define BLTOUCH_LEVELING_ENABLE_T_CN "啟動BLtouch"
+#define PROBE_PORT_T_CN "調平探針接口"
+#define PROBE_X_OFFSET_T_CN "探針X方向偏移"
+#define PROBE_Y_OFFSET_T_CN "探针Y方向偏移"
+#define PROBE_Z_OFFSET_T_CN "探针Z方向偏移"
+#define PROBE_XY_SPEED_T_CN "探针XY方向移動速度"
+#define PROBE_Z_SPEED_T_CN "探针Z方向移動速度"
+#define ENABLE_T_CN "是"
+#define DISABLE_T_CN "否"
+#define LOCKED_T_CN "否"
+#define Z_MIN_T_CN "ZMin"
+#define Z_MAX_T_CN "ZMax"
+
+#define DELTA_LEVEL_CONF_TITLE_T_CN "Delta機器參數"
+#define DELTA_LEVEL_CONF_T_CN "Delta機器調平"
+#define DELTA_MACHINE_RADIUS_T_CN "機器半徑"
+#define DELTA_DIAGONAL_ROD_T_CN "機器桿長"
+#define DELTA_PRINT_RADIUS_T_CN "打印半徑"
+#define DELTA_HEIGHT_T_CN "打印高度"
+#define SMOOTH_ROD_OFFSET_T_CN "滑塊偏移"
+#define EFFECTOR_OFFSET_T_CN "效應器偏移"
+#define CALIBRATION_RADIUS_T_CN "調平半徑"
+
+#define XYZ_LEVEL_CONF_TITLE_T_CN "XYZ機器參數"
+#define PROBE_REACH_MAX_LEFT_T_CN "探针達到最左位置"
+#define PROBE_REACH_MAX_RIGHT_T_CN "探针達到最右位置"
+#define PROBE_REACH_MAX_FRONT_T_CN "探针達到最前位置"
+#define PROBE_REACH_MAX_BACK_T_CN "探针達到最後位置"
+
+#define TEMPERATURE_CONF_TITLE_T_CN "機器參數>溫度設置"
+#define NOZZLE_CONF_T_CN "噴頭設置"
+#define HOTBED_CONF_T_CN "熱床設置"
+#define PREHEAT_TEMPER_T_CN "預設溫度"
+
+#define NOZZLE_CONF_TITLE_T_CN "機器參數>噴頭設置"
+#define NOZZLECNT_T_CN "噴頭數量"
+#define NOZZLE_TYPE_T_CN "E0溫感類型"
+#define NOZZLE_ADJUST_TYPE_T_CN "PID調溫"
+#define NOZZLE_MIN_TEMPERATURE_T_CN "最低溫度"
+#define NOZZLE_MAX_TEMPERATURE_T_CN "最高溫度"
+#define EXTRUD_MIN_TEMPER_T_CN "最低擠出溫度"
+
+#define HOTBED_CONF_TITLE_T_CN "機器參數>熱床設置"
+#define HOTBED_ADJUST_T_CN "PID調溫"
+#define HOTBED_MIN_TEMPERATURE_T_CN "最低溫度"
+#define HOTBED_MAX_TEMPERATURE_T_CN "最高溫度"
+
+#define MOTOR_CONF_TITLE_T_CN "機器參數>電機設置"
+#define MAXFEEDRATE_CONF_T_CN "最大速度設置"
+#define ACCELERATION_CONF_T_CN "加速度設置"
+#define JERKCONF_T_CN "突變速度設置"
+#define STEPSCONF_T_CN "脈沖設置"
+#define TMC_CURRENT_T_CN "TMC 驅動電流設置"
+#define TMC_STEP_MODE_T_CN "TMC 驅動模式設置"
+#define MOTORDIRCONF_T_CN "電機方向設置"
+#define HOMEFEEDRATECONF_T_CN "歸零速度設置"
+#define HOMING_SENSITIVITY_CONF_T_CN "無限位回零靈敏度調節"
+
+#define MAXFEEDRATE_CONF_TITLE_T_CN "機器參數>最大速度"
+#define X_MAXFEEDRATE_T_CN "X軸最大速度"
+#define Y_MAXFEEDRATE_T_CN "Y軸最大速度"
+#define Z_MAXFEEDRATE_T_CN "Z軸最大速度"
+#define E0_MAXFEEDRATE_T_CN "E0軸最大速度"
+#define E1_MAXFEEDRATE_T_CN "E1軸最大速度"
+
+#define ACCELERATION_CONF_TITLE_T_CN "機器參數>加速度"
+#define PRINT_ACCELERATION_T_CN "打印加速度"
+#define RETRACT_ACCELERATION_T_CN "回抽加速度"
+#define TRAVEL_ACCELERATION_T_CN "空載加速度"
+#define X_ACCELERATION_T_CN "X軸加速度"
+#define Y_ACCELERATION_T_CN "Y軸加速度"
+#define Z_ACCELERATION_T_CN "Z軸加速度"
+#define E0_ACCELERATION_T_CN "E0軸加速度"
+#define E1_ACCELERATION_T_CN "E1軸加速度"
+
+#define JERK_CONF_TITLE_T_CN "機器參數>突變速度"
+#define X_JERK_T_CN "X軸突變速度"
+#define Y_JERK_T_CN "Y軸突變速度"
+#define Z_JERK_T_CN "Z軸突變速度"
+#define E_JERK_T_CN "E軸突變速度"
+
+#define STEPS_CONF_TITLE_T_CN "機器參數>脈衝設置"
+#define X_STEPS_T_CN "X軸脈沖"
+#define Y_STEPS_T_CN "Y軸脈沖"
+#define Z_STEPS_T_CN "Z軸脈沖"
+#define E0_STEPS_T_CN "E0軸脈沖"
+#define E1_STEPS_T_CN "E1軸脈沖"
+
+#define TMC_CURRENT_CONF_TITLE_T_CN "機器參數>TMC電流設置"
+#define X_TMC_CURRENT_T_CN "X軸電流(毫安)"
+#define Y_TMC_CURRENT_T_CN "Y軸電流(毫安)"
+#define Z_TMC_CURRENT_T_CN "Z軸電流(毫安)"
+#define E0_TMC_CURRENT_T_CN "E0軸電流(毫安)"
+#define E1_TMC_CURRENT_T_CN "E1軸電流(毫安)"
+
+#define TMC_MODE_CONF_TITLE_T_CN "機器參數>TMC模式設置"
+#define X_TMC_MODE_T_CN "X軸是否使能靜音模式"
+#define Y_TMC_MODE_T_CN "Y軸是否使能靜音模式"
+#define Z_TMC_MODE_T_CN "Z軸是否使能靜音模式"
+#define E0_TMC_MODE_T_CN "E0軸是否使能靜音模式"
+#define E1_TMC_MODE_T_CN "E1軸是否使能靜音模式"
+
+#define MOTORDIR_CONF_TITLE_T_CN "機器參數>電機方向"
+#define X_MOTORDIR_T_CN "X軸電機方向"
+#define Y_MOTORDIR_T_CN "Y軸電機方向"
+#define Z_MOTORDIR_T_CN "Z軸電機方向"
+#define E0_MOTORDIR_T_CN "E0軸電機方向"
+#define E1_MOTORDIR_T_CN "E1軸電機方向"
+#define INVERT_P_T_CN "正向"
+#define INVERT_N_T_CN "反向"
+
+#define HOMEFEEDRATE_CONF_TITLE_T_CN "機器參數>歸零速度"
+#define X_HOMESPEED_T_CN "XY軸歸零速度"
+#define Y_HOMESPEED_T_CN "Y軸歸零速度"
+#define Z_HOMESPEED_T_CN "Z軸歸零速度"
+
+#define ADVANCED_CONF_TITLE_T_CN "機器參數>高級設置"
+#define PWROFF_DECTION_T_CN "斷電檢測模塊"
+#define PWROFF_AFTER_PRINT_T_CN "啟動打完關機功能"
+#define HAVE_UPS_T_CN "機器配備UPS電壓"
+#define Z2_AND_Z2ENDSTOP_CONF_T_CN "雙z軸雙限位功能設置"
+#define ENABLE_PINS_CONF_T_CN "電機使能腳電平設置"
+#define WIFI_SETTINGS_T_CN "Wi-Fi參數設置"
+#define ENCODER_SETTINGS_T_CN "旋鈕設置"
+
+#define Z2_AND_Z2ENDSTOP_CONF_TITLE_T_CN "雙z軸雙限位設置"
+#define Z2_ENABLE_T_CN "啟用Z2軸"
+#define Z2_ENDSTOP_T_CN "啟用Z2限位"
+#define Z2_PORT_T_CN "Z2限位接口"
+
+#define ENABLE_PINS_CONF_TITLE_T_CN "電機使能腳電平"
+#define X_ENABLE_PINS_INVERT_T_CN "X軸電機使能電平"
+#define Y_ENABLE_PINS_INVERT_T_CN "Y軸電機使能電平"
+#define Z_ENABLE_PINS_INVERT_T_CN "Z軸電機使能電平"
+#define E_ENABLE_PINS_INVERT_T_CN "E軸電機使能電平"
+
+#define PAUSE_POSITION_T_CN "打印暫停位置設置"
+#define PAUSE_POSITION_X_T_CN "X軸暫停位置(絕對位置,-1無效)"
+#define PAUSE_POSITION_Y_T_CN "Y軸暫停位置(絕對位置,-1無效)"
+#define PAUSE_POSITION_Z_T_CN "Z軸暫停位置(相對位置,-1無效)"
+#define WIFI_SETTINGS_TITLE_T_CN "機器參數>Wi-Fi設置"
+#define WIFI_SETTINGS_MODE_T_CN "Wi-Fi 模式"
+#define WIFI_SETTINGS_NAME_T_CN "Wi-Fi 名稱: "
+#define WIFI_SETTINGS_PASSWORD_T_CN "Wi-Fi 密碼: "
+#define WIFI_SETTINGS_CLOUD_T_CN "是否使用雲服務?"
+#define WIFI_SETTINGS_CONFIG_T_CN "配置"
+#define WIFI_SETTINGS_EDIT_T_CN "編輯"
+#define WIFI_CONFIG_TIPS_T_CN "進行Wi-Fi配置?"
+
+#define OFFSET_TITLE_T_CN "機器參數>偏移設置"
+#define OFFSET_X_T_CN "X軸與調平開關偏移"
+#define OFFSET_Y_T_CN "Y軸與調平開關偏移"
+#define OFFSET_Z_T_CN "Z軸與調平開關偏移"
+
+#define HOMING_SENSITIVITY_CONF_TITLE_T_CN "機器參數>靈敏度調節"
+#define X_SENSITIVITY_T_CN "X軸靈敏度"
+#define Y_SENSITIVITY_T_CN "Y軸靈敏度"
+#define Z_SENSITIVITY_T_CN "Z軸靈敏度"
+#define Z2_SENSITIVITY_T_CN "Z2軸靈敏度"
+
+#define ENCODER_CONF_TITLE_T_CN "機器參數>旋鈕設置"
+#define ENCODER_CONF_TEXT_T_CN "是否使用旋鈕功能?"
+
+#define TOOL_TEXT_T_CN "工具"
+#define PREHEAT_TEXT_T_CN "預熱"
+#define MOVE_TEXT_T_CN "移動"
+#define HOME_TEXT_T_CN "回零"
+#define PRINT_TEXT_T_CN "打印"
+#define EXTRUDE_TEXT_T_CN "擠出"
+#define LEVELING_TEXT_T_CN "調平"
+#define AUTO_LEVELING_TEXT_T_CN "自動調平"
+#define SET_TEXT_T_CN "設置"
+#define MORE_TEXT_T_CN "更多"
+
+#define ADD_TEXT_T_CN "增加"
+#define DEC_TEXT_T_CN "減少"
+#define EXTRUDER_1_TEXT_T_CN "噴頭1"
+#define EXTRUDER_2_TEXT_T_CN "噴頭2"
+#define HEATBED_TEXT_T_CN "熱床"
+#define TEXT_1C_T_CN "1℃"
+#define TEXT_5C_T_CN "5℃"
+#define TEXT_10C_T_CN "10℃"
+#define CLOSE_TEXT_T_CN "關閉"
+
+#define BACK_TEXT_T_CN "返回"
+
+#define TOOL_PREHEAT_T_CN "預熱"
+#define TOOL_EXTRUDE_T_CN "擠出"
+#define TOOL_MOVE_T_CN "移動"
+#define TOOL_HOME_T_CN "回零"
+#define TOOL_LEVELING_T_CN "調平"
+#define TOOL_AUTO_LEVELING_T_CN "自動調平"
+#define TOOL_FILAMENT_T_CN "換料"
+#define TOOL_MORE_T_CN "更多"
+
+#define AXIS_X_ADD_TEXT_T_CN "X+"
+#define AXIS_X_DEC_TEXT_T_CN "X-"
+#define AXIS_Y_ADD_TEXT_T_CN "Y+"
+#define AXIS_Y_DEC_TEXT_T_CN "Y-"
+#define AXIS_Z_ADD_TEXT_T_CN "Z+"
+#define AXIS_Z_DEC_TEXT_T_CN "Z-"
+#define TEXT_01MM_T_CN "0.1mm"
+#define TEXT_1MM_T_CN "1mm"
+#define TEXT_10MM_T_CN "10mm"
+
+#define HOME_X_TEXT_T_CN "X"
+#define HOME_Y_TEXT_T_CN "Y"
+#define HOME_Z_TEXT_T_CN "Z"
+#define HOME_ALL_TEXT_T_CN "回零"
+#define HOME_STOPMOVE_T_CN "急停"
+
+#define PAGE_UP_TEXT_T_CN "上一頁"
+#define PAGE_DOWN_TEXT_T_CN "下一頁"
+
+#define EXTRUDER_IN_TEXT_T_CN "進料"
+#define EXTRUDER_OUT_TEXT_T_CN "退料"
+#define EXTRUDE_1MM_TEXT_T_CN "1mm"
+#define EXTRUDE_5MM_TEXT_T_CN "5mm"
+#define EXTRUDE_10MM_TEXT_T_CN "10mm"
+#define EXTRUDE_LOW_SPEED_TEXT_T_CN "低速"
+#define EXTRUDE_MEDIUM_SPEED_TEXT_T_CN "常速"
+#define EXTRUDE_HIGH_SPEED_TEXT_T_CN "高速"
+
+#define LEVELING_POINT1_TEXT_T_CN "第一點"
+#define LEVELING_POINT2_TEXT_T_CN "第二點"
+#define LEVELING_POINT3_TEXT_T_CN "第三點"
+#define LEVELING_POINT4_TEXT_T_CN "第四點"
+#define LEVELING_POINT5_TEXT_T_CN "第五點"
+
+#define FILESYS_TEXT_T_CN "文件系統"
+#define WIFI_TEXT_T_CN "WIFI"
+#define FAN_TEXT_T_CN "風扇"
+#define ABOUT_TEXT_T_CN "關於"
+#define BREAK_POINT_TEXT_T_CN "斷點續打"
+#define FILAMENT_TEXT_T_CN "換料"
+#define LANGUAGE_TEXT_T_CN "語言"
+#define MOTOR_OFF_TEXT_T_CN "關閉電機"
+#define MOTOR_OFF_XY_TEXT_T_CN "關閉XY"
+#define SHUTDOWN_TEXT_T_CN "關機"
+#define MACHINE_PARA_T_CN "機器參數"
+#define EEPROM_SETTINGS_T_CN "Eeprom設置"
+
+#define U_DISK_TEXT_T_CN "U盤"
+#define SD_CARD_TEXT_T_CN "SD卡"
+#define WIFI_NAME_TEXT_T_CN "無線網絡:"
+#define WIFI_KEY_TEXT_T_CN "密碼: "
+#define WIFI_IP_TEXT_T_CN "IP: "
+#define WIFI_AP_TEXT_T_CN "狀態: AP"
+#define WIFI_STA_TEXT_T_CN "狀態: STA"
+#define WIFI_CONNECTED_TEXT_T_CN "已連接"
+#define WIFI_DISCONNECTED_TEXT_T_CN "未連接"
+#define WIFI_EXCEPTION_TEXT_T_CN "模塊異常"
+#define CLOUD_TEXT_T_CN "雲服務"
+#define CLOUD_BIND_T_CN "已綁定"
+#define CLOUD_UNBIND_T_CN "解綁"
+#define CLOUD_UNBINDING_T_CN "解绑中"
+#define CLOUD_DISCONNECTED_T_CN "未連接"
+#define CLOUD_UNBINDED_T_CN "未綁定"
+#define CLOUD_BINDED_T_CN "已綁定"
+#define CLOUD_DISABLE_T_CN "已禁用"
+
+#define FAN_ADD_TEXT_T_CN "增加"
+#define FAN_DEC_TEXT_T_CN "減少"
+#define FAN_OPEN_TEXT_T_CN "100%"
+#define FAN_HALF_TEXT_T_CN "50%"
+#define FAN_CLOSE_TEXT_T_CN "關閉"
+#define FAN_TIPS1_TEXT_T_CN "風扇"
+#define FAN_TIPS2_TEXT_T_CN "FAN\nClose"
+
+#define FILAMENT_IN_TEXT_T_CN "進料"
+#define FILAMENT_OUT_TEXT_T_CN "退料"
+#define FILAMENT_EXT0_TEXT_T_CN "噴頭1"
+#define FILAMENT_EXT1_TEXT_T_CN "噴頭2"
+#define FILAMENT_HEAT_TEXT_T_CN "預熱"
+#define FILAMENT_STOP_TEXT_T_CN "停止"
+#define FILAMENT_TIPS2_TEXT_T_CN "T:"
+#define FILAMENT_TIPS3_TEXT_T_CN "正在進料"
+#define FILAMENT_TIPS4_TEXT_T_CN "正在退料"
+#define FILAMENT_TIPS5_TEXT_T_CN "溫度太低,請先預熱"
+#define FILAMENT_TIPS6_TEXT_T_CN "換料完成"
+#define FILAMENT_CHANGE_TEXT_T_CN "待打印機暫停后,\n請按<進料>或<退料>"
+
+#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_T_CN "準備進料,正在加熱,請稍等"
+#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_T_CN "準備退料,正在加熱,請稍等"
+#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_T_CN "加熱完成,請裝載耗材后,按<確定>開始進料"
+#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_T_CN "請裝載耗,按<確定>開始進料!"
+#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_T_CN "加熱完成,请按<確定>開始退料!"
+#define FILAMENT_DIALOG_LOADING_TIPS_T_CN "正在進料,请等待耗材加載完成!"
+#define FILAMENT_DIALOG_UNLOADING_TIPS_T_CN "正在退料,请等待耗材卸載完成!"
+#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_T_CN "進料完成,请按<確定>返回"
+#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_T_CN "退料完成,请按<確定>返回"
+
+#define PRE_HEAT_EXT_TEXT_T_CN "噴頭"
+#define PRE_HEAT_BED_TEXT_T_CN "熱床"
+
+#define FILE_LOADING_T_CN "正在載入......"
+#define NO_FILE_AND_CHECK_T_CN "無文件!請插入sd卡/u盤!"
+#define NO_FILE_T_CN "無文件!"
+
+#define EXTRUDER_TEMP_TEXT_T_CN "溫度"
+#define EXTRUDER_E_LENGTH1_TEXT_T_CN "噴頭"
+#define EXTRUDER_E_LENGTH2_TEXT_T_CN "噴頭"
+#define EXTRUDER_E_LENGTH3_TEXT_T_CN "噴頭"
+
+#define ABOUT_TYPE_TEXT_T_CN "Type: "
+#define ABOUT_VERSION_TEXT_T_CN "Firmware: "
+#define ABOUT_WIFI_TEXT_T_CN "Wifi: "
+
+#define PRINTING_OPERATION_T_CN "操作"
+#define PRINTING_PAUSE_T_CN "暫停"
+#define PRINTING_TEMP_T_CN "溫度"
+#define PRINTING_CHANGESPEED_T_CN "變速"
+#define PRINTING_RESUME_T_CN "恢復"
+#define PRINTING_STOP_T_CN "停止"
+#define PRINTING_MORE_T_CN "更多"
+#define PRINTING_EXTRUDER_T_CN "擠出"
+#define PRINTING_MOVE_T_CN "移動"
+
+#define EXTRUDER_SPEED_T_CN "擠出"
+#define MOVE_SPEED_T_CN "移動"
+#define EXTRUDER_SPEED_STATE_T_CN "擠出速度"
+#define MOVE_SPEED_STATE_T_CN "移動速度"
+#define STEP_1PERCENT_T_CN "1%%"
+#define STEP_5PERCENT_T_CN "5%%"
+#define STEP_10PERCENT_T_CN "10%%"
+
+#define TITLE_READYPRINT_T_CN "準備打印"
+#define TITLE_PREHEAT_T_CN "預熱"
+#define TITLE_MOVE_T_CN "移動"
+#define TITLE_HOME_T_CN "回零"
+#define TITLE_EXTRUDE_T_CN "擠出"
+#define TITLE_LEVELING_T_CN "調平"
+#define TITLE_SET_T_CN "設置"
+#define TITLE_MORE_T_CN "更多"
+#define TITLE_CHOOSEFILE_T_CN "選擇文件"
+#define TITLE_PRINTING_T_CN "正在打印"
+#define TITLE_OPERATION_T_CN "操作"
+#define TITLE_ADJUST_T_CN "調整"
+#define TITLE_WIRELESS_T_CN "無線網絡"
+#define TITLE_FILAMENT_T_CN "換料"
+#define TITLE_ABOUT_T_CN "關於"
+#define TITLE_FAN_T_CN "風扇"
+#define TITLE_LANGUAGE_T_CN "語言"
+#define TITLE_PAUSE_T_CN "暫停"
+#define TITLE_CHANGESPEED_T_CN "變速"
+#define TITLE_CLOUD_TEXT_T_CN "雲服務"
+#define TITLE_DIALOG_CONFIRM_T_CN "確認"
+#define TITLE_FILESYS_T_CN "文件系統"
+
+#define AUTO_SHUTDOWN_T_CN "自動關機"
+#define MANUAL_SHUTDOWN_T_CN "手動關機"
+
+#define DIALOG_CONFIRM_T_CN "確定"
+#define DIALOG_CANCLE_T_CN "取消"
+#define DIALOG_OK_T_CN "確認"
+#define DIALOG_RESET_T_CN "重設"
+#define DIALOG_RETRY_T_CN "重試"
+#define DIALOG_DISABLE_T_CN "禁用"
+#define DIALOG_PRINT_MODEL_T_CN "打印模型?"
+#define DIALOG_CANCEL_PRINT_T_CN "停止打印?"
+#define DIALOG_RETRY_T_CN "重試"
+#define DIALOG_STOP_T_CN "停止"
+#define DIALOG_REPRINT_FROM_BREAKPOINT_T_CN "從斷點續打?"
+#define DIALOG_ERROR_TIPS1_T_CN "錯誤:找不到文件,請插入sd卡/u盤!"
+#define DIALOG_ERROR_TIPS2_T_CN "錯誤:通信失敗,請檢查波特率或主板硬件!"
+#define DIALOG_ERROR_TIPS3_T_CN "錯誤:文件名或文件路徑太長!"
+#define DIALOG_CLOSE_MACHINE_T_CN "正在關機......"
+#define DIALOG_UNBIND_PRINTER_T_CN "解除綁定?"
+#define DIALOG_FILAMENT_NO_PRESS_T_CN "請先裝載耗材!"
+#define DIALOG_PRINT_FINISH_T_CN "打印完成!"
+#define DIALOG_PRINT_TIME_T_CN "打印時間: "
+#define DIALOG_REPRINT_T_CN "再打印壹次"
+#define DIALOG_WIFI_ENABLE_TIPS_T_CN "wifi模塊正在配置中,請稍等......"
+#define DIALOG_PAUSING_TIPS_T_CN "機器暫停中..."
+
+#define TEXT_VALUE_T_CN "%d℃/%d℃"
+#define EXTRUDE_TEXT_VALUE_T_T_CN ": %d℃"
+#define WIFI_RECONNECT_TEXT_T_CN "重新連接"
+
+#define MESSAGE_PAUSING_T_CN "暫停中..."
+#define MESSAGE_CHANGING_T_CN "等待換料開始..."
+#define MESSAGE_UNLOAD_T_CN "退料中,請稍等..."
+#define MESSAGE_WAITING_T_CN "點擊按鈕恢復打印"
+#define MESSAGE_INSERT_T_CN "裝載耗材後,點擊按鈕開始打印"
+#define MESSAGE_LOAD_T_CN "進料中,請稍等..."
+#define MESSAGE_PURGE_T_CN "等待擠出..."
+#define MESSAGE_RESUME_T_CN "等待恢復打印..."
+#define MESSAGE_HEAT_T_CN "按下按鈕,加熱噴頭"
+#define MESSAGE_HEATING_T_CN "噴頭加熱中,請等待..."
+#define MESSAGE_OPTION_T_CN "擠出更多還是繼續打印"
+#define MESSAGE_PURGE_MORE_T_CN "擠出"
+#define MESSAGE_CONTINUE_PRINT_T_CN "打印"
+
+#define EEPROM_SETTINGS_TITLE_T_CN "EEPROM 設置"
+#define EEPROM_SETTINGS_STORE_T_CN "保存參數至EEPROM"
+#define EEPROM_SETTINGS_READ_T_CN "讀取EEPROM參數"
+#define EEPROM_SETTINGS_REVERT_T_CN "恢復默認參數"
+
+#define EEPROM_STORE_TIPS_T_CN "是否保存參數到EEPROM?"
+#define EEPROM_READ_TIPS_T_CN "是否使用EEPROM參數?"
+#define EEPROM_REVERT_TIPS_T_CN "是否恢復默認參數?"
+
+#define MORE_CUSTOM1_TEXT_T_CN USER_DESC_1
+#define MORE_CUSTOM2_TEXT_T_CN USER_DESC_2
+#define MORE_CUSTOM3_TEXT_T_CN USER_DESC_3
+#define MORE_CUSTOM4_TEXT_T_CN USER_DESC_4
+#define MORE_CUSTOM5_TEXT_T_CN USER_DESC_5
+#define MORE_CUSTOM6_TEXT_T_CN USER_DESC_6
+#define MORE_CUSTOM7_TEXT_T_CN USER_DESC_7
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
new file mode 100644
index 0000000..d7b08fe
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp
@@ -0,0 +1,584 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "SPI_TFT.h"
+
+#include "tft_lvgl_configuration.h"
+#include "draw_ready_print.h"
+
+#include "pic_manager.h"
+#include "mks_hardware_test.h"
+#include "draw_ui.h"
+#include "SPIFlashStorage.h"
+#include <lvgl.h>
+
+#include "../../../../MarlinCore.h"
+#include "../../../../inc/MarlinConfig.h"
+
+#include HAL_PATH(../../../../HAL, tft/xpt2046.h)
+#include "../../../marlinui.h"
+XPT2046 touch;
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if HAS_SERVOS
+ #include "../../../../module/servo.h"
+#endif
+
+#if EITHER(PROBE_TARE, HAS_Z_SERVO_PROBE)
+ #include "../../../../module/probe.h"
+#endif
+
+#if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ #include "../../../tft_io/touch_calibration.h"
+ #include "draw_touch_calibration.h"
+#endif
+
+#if ENABLED(MKS_WIFI_MODULE)
+ #include "wifi_module.h"
+#endif
+
+#include <SPI.h>
+
+#ifndef TFT_WIDTH
+ #define TFT_WIDTH 480
+#endif
+#ifndef TFT_HEIGHT
+ #define TFT_HEIGHT 320
+#endif
+
+#if HAS_SPI_FLASH_FONT
+ extern void init_gb2312_font();
+#endif
+
+static lv_disp_buf_t disp_buf;
+lv_group_t* g;
+#if ENABLED(SDSUPPORT)
+ extern void UpdateAssets();
+#endif
+uint16_t DeviceCode = 0x9488;
+extern uint8_t sel_id;
+
+uint8_t bmp_public_buf[14 * 1024];
+uint8_t public_buf[513];
+
+extern bool flash_preview_begin, default_preview_flg, gcode_preview_over;
+
+void SysTick_Callback() {
+ lv_tick_inc(1);
+ print_time_count();
+ #if ENABLED(MKS_WIFI_MODULE)
+ if (tips_disp.timer == TIPS_TIMER_START)
+ tips_disp.timer_count++;
+ #endif
+ if (uiCfg.filament_loading_time_flg == 1) {
+ uiCfg.filament_loading_time_cnt++;
+ uiCfg.filament_rate = (uint32_t)(((uiCfg.filament_loading_time_cnt / (uiCfg.filament_loading_time * 1000.0)) * 100.0) + 0.5);
+ if (uiCfg.filament_loading_time_cnt >= (uiCfg.filament_loading_time * 1000)) {
+ uiCfg.filament_loading_time_cnt = 0;
+ uiCfg.filament_loading_time_flg = 0;
+ uiCfg.filament_loading_completed = 1;
+ }
+ }
+ if (uiCfg.filament_unloading_time_flg == 1) {
+ uiCfg.filament_unloading_time_cnt++;
+ uiCfg.filament_rate = (uint32_t)(((uiCfg.filament_unloading_time_cnt / (uiCfg.filament_unloading_time * 1000.0)) * 100.0) + 0.5);
+ if (uiCfg.filament_unloading_time_cnt >= (uiCfg.filament_unloading_time * 1000)) {
+ uiCfg.filament_unloading_time_cnt = 0;
+ uiCfg.filament_unloading_time_flg = 0;
+ uiCfg.filament_unloading_completed = 1;
+ uiCfg.filament_rate = 100;
+ }
+ }
+}
+
+void tft_lvgl_init() {
+
+ W25QXX.init(SPI_QUARTER_SPEED);
+
+ gCfgItems_init();
+ ui_cfg_init();
+ disp_language_init();
+
+ watchdog_refresh(); // LVGL init takes time
+
+ #if MB(MKS_ROBIN_NANO)
+ OUT_WRITE(PB0, LOW); // HE1
+ #endif
+
+ // Init TFT first!
+ SPI_TFT.spi_init(SPI_FULL_SPEED);
+ SPI_TFT.LCD_init();
+
+ #if ENABLED(USB_FLASH_DRIVE_SUPPORT)
+ uint16_t usb_flash_loop = 1000;
+ do {
+ Sd2Card::idle();
+ watchdog_refresh();
+ delay(2);
+ } while((!Sd2Card::isInserted()) && (usb_flash_loop--));
+ card.mount();
+ #elif HAS_LOGO_IN_FLASH
+ delay(2000);
+ #endif
+
+ watchdog_refresh(); // LVGL init takes time
+
+ #if ENABLED(SDSUPPORT)
+ UpdateAssets();
+ watchdog_refresh(); // LVGL init takes time
+ #endif
+
+ mks_test_get();
+
+ touch.Init();
+
+ lv_init();
+
+ lv_disp_buf_init(&disp_buf, bmp_public_buf, nullptr, LV_HOR_RES_MAX * 14); /*Initialize the display buffer*/
+
+ lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
+ lv_disp_drv_init(&disp_drv); /*Basic initialization*/
+ disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
+ disp_drv.buffer = &disp_buf; /*Assign the buffer to the display*/
+ lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
+
+ lv_indev_drv_t indev_drv;
+ lv_indev_drv_init(&indev_drv); /*Descriptor of a input device driver*/
+ indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
+ indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
+ lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
+
+ #if HAS_ROTARY_ENCODER
+ g = lv_group_create();
+ lv_indev_drv_t enc_drv;
+ lv_indev_drv_init(&enc_drv);
+ enc_drv.type = LV_INDEV_TYPE_ENCODER;
+ enc_drv.read_cb = my_mousewheel_read;
+ lv_indev_t * enc_indev = lv_indev_drv_register(&enc_drv);
+ lv_indev_set_group(enc_indev, g);
+ #endif
+
+ lv_fs_drv_t spi_flash_drv;
+ lv_fs_drv_init(&spi_flash_drv);
+ spi_flash_drv.letter = 'F';
+ spi_flash_drv.open_cb = spi_flash_open_cb;
+ spi_flash_drv.close_cb = spi_flash_close_cb;
+ spi_flash_drv.read_cb = spi_flash_read_cb;
+ spi_flash_drv.seek_cb = spi_flash_seek_cb;
+ spi_flash_drv.tell_cb = spi_flash_tell_cb;
+ lv_fs_drv_register(&spi_flash_drv);
+
+ lv_fs_drv_t sd_drv;
+ lv_fs_drv_init(&sd_drv);
+ sd_drv.letter = 'S';
+ sd_drv.open_cb = sd_open_cb;
+ sd_drv.close_cb = sd_close_cb;
+ sd_drv.read_cb = sd_read_cb;
+ sd_drv.seek_cb = sd_seek_cb;
+ sd_drv.tell_cb = sd_tell_cb;
+ lv_fs_drv_register(&sd_drv);
+
+ systick_attach_callback(SysTick_Callback);
+
+ #if HAS_SPI_FLASH_FONT
+ init_gb2312_font();
+ #endif
+
+ tft_style_init();
+
+ filament_pin_setup();
+
+ lv_encoder_pin_init();
+
+ #if ENABLED(MKS_WIFI_MODULE)
+ mks_esp_wifi_init();
+ //WIFISERIAL.begin(WIFI_BAUDRATE);
+ //uint32_t serial_connect_timeout = millis() + 1000UL;
+ //while (/*!WIFISERIAL && */PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+ mks_wifi_firmware_upddate();
+ #endif
+ TERN_(HAS_SERVOS, servo_init());
+ TERN_(HAS_Z_SERVO_PROBE, probe.servo_probe_init());
+ bool ready = true;
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ recovery.load();
+ if (recovery.valid()) {
+ ready = false;
+ if (gCfgItems.from_flash_pic)
+ flash_preview_begin = true;
+ else
+ default_preview_flg = true;
+
+ uiCfg.print_state = REPRINTING;
+
+ #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
+ strncpy(public_buf_m, recovery.info.sd_filename, sizeof(public_buf_m));
+ card.printLongPath(public_buf_m);
+ strncpy(list_file.long_name[sel_id], card.longFilename, sizeof(list_file.long_name[sel_id]));
+ #else
+ strncpy(list_file.long_name[sel_id], recovery.info.sd_filename, sizeof(list_file.long_name[sel_id]));
+ #endif
+ lv_draw_printing();
+ }
+ #endif
+
+ if (ready) {
+ lv_draw_ready_print();
+ }
+
+ if (mks_test_flag == 0x1E)
+ mks_gpio_test();
+}
+
+void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) {
+ uint16_t width = area->x2 - area->x1 + 1,
+ height = area->y2 - area->y1 + 1;
+
+ SPI_TFT.setWindow((uint16_t)area->x1, (uint16_t)area->y1, width, height);
+
+ for (uint16_t i = 0; i < height; i++)
+ SPI_TFT.tftio.WriteSequence((uint16_t*)(color_p + width * i), width);
+
+ lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
+
+ W25QXX.init(SPI_QUARTER_SPEED);
+}
+
+void lv_fill_rect(lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2, lv_color_t bk_color) {
+ uint16_t width, height;
+ width = x2 - x1 + 1;
+ height = y2 - y1 + 1;
+
+ SPI_TFT.setWindow((uint16_t)x1, (uint16_t)y1, width, height);
+ #if ENABLED(TFT_LVGL_UI_FSMC)
+ SPI_TFT.tftio.WriteReg(0x002C);
+ #endif
+
+ #ifdef LCD_USE_DMA_FSMC
+ SPI_TFT.tftio.WriteMultiple(bk_color.full, width * height);
+ #else
+ for (uint32_t i = 0; i < width * height; i++)
+ SPI_TFT.tftio.WriteData(bk_color.full);
+ #endif
+
+ #if ENABLED(TFT_LVGL_UI_SPI)
+ W25QXX.init(SPI_QUARTER_SPEED);
+ #endif
+}
+
+#define TICK_CYCLE 1
+
+unsigned int getTickDiff(unsigned int curTick, unsigned int lastTick) {
+ return TICK_CYCLE * (lastTick <= curTick ? (curTick - lastTick) : (0xFFFFFFFF - lastTick + curTick));
+}
+
+static bool get_point(int16_t *x, int16_t *y) {
+ bool is_touched = touch.getRawPoint(x, y);
+
+ if (!is_touched) return false;
+
+ #if ENABLED(TOUCH_SCREEN_CALIBRATION)
+ const calibrationState state = touch_calibration.get_calibration_state();
+ if (state >= CALIBRATION_TOP_LEFT && state <= CALIBRATION_BOTTOM_RIGHT) {
+ if (touch_calibration.handleTouch(*x, *y)) lv_update_touch_calibration_screen();
+ return false;
+ }
+ *x = int16_t((int32_t(*x) * touch_calibration.calibration.x) >> 16) + touch_calibration.calibration.offset_x;
+ *y = int16_t((int32_t(*y) * touch_calibration.calibration.y) >> 16) + touch_calibration.calibration.offset_y;
+ #else
+ *x = int16_t((int32_t(*x) * TOUCH_CALIBRATION_X) >> 16) + TOUCH_OFFSET_X;
+ *y = int16_t((int32_t(*y) * TOUCH_CALIBRATION_Y) >> 16) + TOUCH_OFFSET_Y;
+ #endif
+
+ return true;
+}
+
+bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) {
+ static int16_t last_x = 0, last_y = 0;
+ static uint8_t last_touch_state = LV_INDEV_STATE_REL;
+ static int32_t touch_time1 = 0;
+ uint32_t tmpTime, diffTime = 0;
+
+ tmpTime = millis();
+ diffTime = getTickDiff(tmpTime, touch_time1);
+ if (diffTime > 20) {
+ if (get_point(&last_x, &last_y)) {
+
+ if (last_touch_state == LV_INDEV_STATE_PR) return false;
+ data->state = LV_INDEV_STATE_PR;
+
+ // Set the coordinates (if released use the last-pressed coordinates)
+ #if TFT_ROTATION == TFT_ROTATE_180
+ data->point.x = TFT_WIDTH - last_x;
+ data->point.y = TFT_HEIGHT -last_y;
+ #else
+ data->point.x = last_x;
+ data->point.y = last_y;
+ #endif
+
+ last_x = last_y = 0;
+ last_touch_state = LV_INDEV_STATE_PR;
+ }
+ else {
+ if (last_touch_state == LV_INDEV_STATE_PR)
+ data->state = LV_INDEV_STATE_REL;
+ last_touch_state = LV_INDEV_STATE_REL;
+ }
+
+ touch_time1 = tmpTime;
+ }
+
+ return false; // Return `false` since no data is buffering or left to read
+}
+
+int16_t enc_diff = 0;
+lv_indev_state_t state = LV_INDEV_STATE_REL;
+
+bool my_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) {
+ (void) indev_drv; /*Unused*/
+
+ data->state = state;
+ data->enc_diff = enc_diff;
+ enc_diff = 0;
+
+ return false; /*No more data to read so return false*/
+}
+
+extern uint8_t currentFlashPage;
+
+//spi_flash
+uint32_t pic_read_base_addr = 0, pic_read_addr_offset = 0;
+lv_fs_res_t spi_flash_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) {
+ static char last_path_name[30];
+ if (strcasecmp(last_path_name, path) != 0) {
+ pic_read_base_addr = lv_get_pic_addr((uint8_t *)path);
+ strcpy(last_path_name, path);
+ }
+ else {
+ W25QXX.init(SPI_QUARTER_SPEED);
+ currentFlashPage = 0;
+ }
+ pic_read_addr_offset = pic_read_base_addr;
+ return LV_FS_RES_OK;
+}
+
+lv_fs_res_t spi_flash_close_cb (lv_fs_drv_t * drv, void * file_p) {
+ lv_fs_res_t res = LV_FS_RES_OK;
+ /* Add your code here*/
+ pic_read_addr_offset = pic_read_base_addr;
+ return res;
+}
+
+lv_fs_res_t spi_flash_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) {
+ lv_pic_test((uint8_t *)buf, pic_read_addr_offset, btr);
+ *br = btr;
+ return LV_FS_RES_OK;
+}
+
+lv_fs_res_t spi_flash_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos) {
+ #if HAS_SPI_FLASH_COMPRESSION
+ if (pos == 4) {
+ uint8_t bmp_header[4];
+ SPIFlash.beginRead(pic_read_base_addr);
+ SPIFlash.readData(bmp_header, 4);
+ currentFlashPage = 1;
+ }
+ pic_read_addr_offset = pic_read_base_addr;
+ #else
+ pic_read_addr_offset = pic_read_base_addr + pos;
+ #endif
+ return LV_FS_RES_OK;
+}
+
+lv_fs_res_t spi_flash_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) {
+ *pos_p = pic_read_addr_offset - pic_read_base_addr;
+ return LV_FS_RES_OK;
+}
+
+//sd
+char *cur_namefff;
+uint32_t sd_read_base_addr = 0, sd_read_addr_offset = 0, small_image_size = 409;
+char last_path[(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + strlen("S:/") + 1];
+lv_fs_res_t sd_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) {
+ if (path != nullptr && card.isFileOpen() && strcmp((const char*)path, (const char*)last_path) == 0) return LV_FS_RES_OK;
+ strcpy(last_path, path);
+ lv_close_gcode_file();
+ char name_buf[100];
+ *name_buf = '/';
+ strcpy(name_buf + 1, path);
+ char *temp = strstr(name_buf, ".bin");
+ if (temp) strcpy(temp, ".GCO");
+ sd_read_base_addr = lv_open_gcode_file((char *)name_buf);
+ sd_read_addr_offset = sd_read_base_addr;
+ if (sd_read_addr_offset == UINT32_MAX) return LV_FS_RES_NOT_EX;
+ // find small image size
+ card.read(public_buf, 512);
+ public_buf[511] = '\0';
+ char* eol = strpbrk((const char*)public_buf, "\n\r");
+ small_image_size = (uintptr_t)eol - (uintptr_t)((uint32_t *)(&public_buf[0])) + 1;
+ return LV_FS_RES_OK;
+}
+
+lv_fs_res_t sd_close_cb (lv_fs_drv_t * drv, void * file_p) {
+ /* Add your code here*/
+ //lv_close_gcode_file();
+ return LV_FS_RES_OK;
+}
+
+lv_fs_res_t sd_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) {
+ if (btr == 200) {
+ lv_gcode_file_read((uint8_t *)buf);
+ //pic_read_addr_offset += 208;
+ *br = 200;
+ }
+ else if (btr == 4) {
+ uint8_t header_pic[4] = { 0x04, 0x90, 0x81, 0x0C };
+ memcpy(buf, header_pic, 4);
+ *br = 4;
+ }
+ return LV_FS_RES_OK;
+}
+
+lv_fs_res_t sd_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos) {
+ sd_read_addr_offset = sd_read_base_addr + (pos - 4) / 200 * small_image_size;
+ lv_gcode_file_seek(sd_read_addr_offset);
+ return LV_FS_RES_OK;
+}
+
+lv_fs_res_t sd_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) {
+ if (sd_read_addr_offset) *pos_p = 0;
+ else *pos_p = (sd_read_addr_offset - sd_read_base_addr) / small_image_size * 200 + 4;
+ return LV_FS_RES_OK;
+}
+
+void lv_encoder_pin_init() {
+ #if BUTTON_EXISTS(EN1)
+ SET_INPUT_PULLUP(BTN_EN1);
+ #endif
+ #if BUTTON_EXISTS(EN2)
+ SET_INPUT_PULLUP(BTN_EN2);
+ #endif
+ #if BUTTON_EXISTS(ENC)
+ SET_INPUT_PULLUP(BTN_ENC);
+ #endif
+
+ #if BUTTON_EXISTS(BACK)
+ SET_INPUT_PULLUP(BTN_BACK);
+ #endif
+
+ #if BUTTON_EXISTS(UP)
+ SET_INPUT(BTN_UP);
+ #endif
+ #if BUTTON_EXISTS(DWN)
+ SET_INPUT(BTN_DWN);
+ #endif
+ #if BUTTON_EXISTS(LFT)
+ SET_INPUT(BTN_LFT);
+ #endif
+ #if BUTTON_EXISTS(RT)
+ SET_INPUT(BTN_RT);
+ #endif
+}
+
+#if 1 // HAS_ENCODER_ACTION
+ void lv_update_encoder() {
+ static uint32_t encoder_time1;
+ uint32_t tmpTime, diffTime = 0;
+ tmpTime = millis();
+ diffTime = getTickDiff(tmpTime, encoder_time1);
+ if (diffTime > 50) {
+
+ #if HAS_ENCODER_WHEEL
+
+ #if ANY_BUTTON(EN1, EN2, ENC, BACK)
+
+ uint8_t newbutton = 0;
+
+ #if BUTTON_EXISTS(EN1)
+ if (BUTTON_PRESSED(EN1)) newbutton |= EN_A;
+ #endif
+ #if BUTTON_EXISTS(EN2)
+ if (BUTTON_PRESSED(EN2)) newbutton |= EN_B;
+ #endif
+ #if BUTTON_EXISTS(ENC)
+ if (BUTTON_PRESSED(ENC)) newbutton |= EN_C;
+ #endif
+ #if BUTTON_EXISTS(BACK)
+ if (BUTTON_PRESSED(BACK)) newbutton |= EN_D;
+ #endif
+
+ #else
+
+ constexpr uint8_t newbutton = 0;
+
+ #endif
+
+
+ static uint8_t buttons = 0;
+ buttons = newbutton;
+ static uint8_t lastEncoderBits;
+
+ #define encrot0 0
+ #define encrot1 1
+ #define encrot2 2
+
+ uint8_t enc = 0;
+ if (buttons & EN_A) enc |= B01;
+ if (buttons & EN_B) enc |= B10;
+ if (enc != lastEncoderBits) {
+ switch (enc) {
+ case encrot1:
+ if (lastEncoderBits == encrot0) {
+ enc_diff--;
+ encoder_time1 = tmpTime;
+ }
+ break;
+ case encrot2:
+ if (lastEncoderBits == encrot0) {
+ enc_diff++;
+ encoder_time1 = tmpTime;
+ }
+ break;
+ }
+ lastEncoderBits = enc;
+ }
+ static uint8_t last_button_state = LV_INDEV_STATE_REL;
+ const uint8_t enc_c = (buttons & EN_C) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
+ if (enc_c != last_button_state) {
+ state = enc_c ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
+ last_button_state = enc_c;
+ }
+
+ #endif // HAS_ENCODER_WHEEL
+
+ } // next_button_update_ms
+ }
+
+#endif // HAS_ENCODER_ACTION
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.h
new file mode 100644
index 0000000..018f737
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.h
@@ -0,0 +1,69 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * @file lcd/extui/lib/mks_ui/tft_lvgl_configuration.h
+ * @date 2020-02-21
+ */
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+#include <lvgl.h>
+
+//#define TFT_ROTATION TFT_ROTATE_180
+
+extern uint8_t bmp_public_buf[14 * 1024];
+extern uint8_t public_buf[513];
+
+extern void tft_lvgl_init();
+extern void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p);
+extern bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data);
+extern bool my_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
+
+extern void LCD_Clear(uint16_t Color);
+extern void tft_set_point(uint16_t x, uint16_t y, uint16_t point);
+extern void LCD_setWindowArea(uint16_t StartX, uint16_t StartY, uint16_t width, uint16_t heigh);
+extern void LCD_WriteRAM_Prepare(void);
+extern void lcd_draw_logo();
+extern void lv_encoder_pin_init();
+extern void lv_update_encoder();
+
+extern lv_fs_res_t spi_flash_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode);
+extern lv_fs_res_t spi_flash_close_cb (lv_fs_drv_t * drv, void * file_p);
+extern lv_fs_res_t spi_flash_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
+extern lv_fs_res_t spi_flash_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos);
+extern lv_fs_res_t spi_flash_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
+
+extern lv_fs_res_t sd_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode);
+extern lv_fs_res_t sd_close_cb (lv_fs_drv_t * drv, void * file_p);
+extern lv_fs_res_t sd_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
+extern lv_fs_res_t sd_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos);
+extern lv_fs_res_t sd_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
+
+extern void lv_fill_rect(lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2, lv_color_t bk_color);
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp
new file mode 100644
index 0000000..f05874a
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp
@@ -0,0 +1,2920 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "../../../../MarlinCore.h"
+
+#include "draw_ui.h"
+#include "tft_multi_language.h"
+
+// ********************************************* //
+
+common_menu_def common_menu;
+main_menu_def main_menu;
+preheat_menu_def preheat_menu;
+move_menu_def move_menu;
+home_menu_def home_menu;
+file_menu_def file_menu;
+extrude_menu_def extrude_menu;
+leveling_menu_def leveling_menu;
+set_menu_def set_menu;
+more_menu_def more_menu;
+wifi_menu_def wifi_menu;
+cloud_menu_def cloud_menu;
+about_menu_def about_menu;
+fan_menu_def fan_menu;
+filament_menu_def filament_menu;
+printing_menu_def printing_menu;
+operation_menu_def operation_menu;
+pause_menu_def pause_menu;
+speed_menu_def speed_menu;
+printing_more_menu_def printing_more_menu;
+dialog_menu_def dialog_menu;
+language_menu_def language_menu;
+print_file_dialog_menu_def print_file_dialog_menu;
+filesys_menu_def filesys_menu;
+tool_menu_def tool_menu;
+MachinePara_menu_def MachinePara_menu;
+pause_msg_def pause_msg_menu;
+eeprom_def eeprom_menu;
+touchmi_menu_def touchmi_menu;
+
+machine_common_def machine_menu;
+void machine_setting_disp() {
+ if (gCfgItems.language == LANG_SIMPLE_CHINESE) {
+ MachinePara_menu.title = MACHINE_PARA_TITLE_CN;
+ MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_CN;
+ MachinePara_menu.MotorSetting = MOTOR_CONFIG_CN;
+ MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_CN;
+ MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_CN;
+
+ machine_menu.default_value = DEFAULT_CN;
+ machine_menu.next = NEXT_CN;
+ machine_menu.previous = PREVIOUS_CN;
+
+ machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_CN;
+ machine_menu.MachineType = MACHINE_TYPE_CN;
+ machine_menu.Stroke = MACHINE_STROKE_CN;
+ machine_menu.HomeDir = MACHINE_HOMEDIR_CN;
+ machine_menu.EndStopType = MACHINE_ENDSTOP_TYPE_CN;
+ machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_CN;
+
+ machine_menu.MachineTypeConfTitle = MACHINE_TYPE_CONFIG_TITLE_CN;
+ machine_menu.xyz = MACHINE_TYPE_XYZ_CN;
+ machine_menu.delta = MACHINE_TYPE_DELTA_CN;
+ machine_menu.corexy = MACHINE_TYPE_COREXY_CN;
+
+ machine_menu.StrokeConfTitle = MACHINE_STROKE_CONF_TITLE_CN;
+ machine_menu.xStroke = X_MAX_LENGTH_CN;
+ machine_menu.yStroke = Y_MAX_LENGTH_CN;
+ machine_menu.zStroke = Z_MAX_LENGTH_CN;
+
+ machine_menu.xmin = X_MIN_LENGTH_CN;
+ machine_menu.ymin = Y_MIN_LENGTH_CN;
+ machine_menu.zmin = Z_MIN_LENGTH_CN;
+
+ machine_menu.HomeDirConfTitle = HOME_DIR_CONF_TITLE_CN;
+ machine_menu.xHomeDir = HOME_DIR_X_CN;
+ machine_menu.yHomeDir = HOME_DIR_Y_CN;
+ machine_menu.zHomeDir = HOME_DIR_Z_CN;
+ machine_menu.min = HOME_MIN_CN;
+ machine_menu.max = HOME_MAX_CN;
+
+ machine_menu.EndstopConfTitle = ENDSTOP_CONF_TITLE_CN;
+ machine_menu.xEndstop_min = MIN_ENDSTOP_X_CN;
+ machine_menu.yEndstop_min = MIN_ENDSTOP_Y_CN;
+ machine_menu.zEndstop_min = MIN_ENDSTOP_Z_CN;
+ machine_menu.xEndstop_max = MAX_ENDSTOP_X_CN;
+ machine_menu.yEndstop_max = MAX_ENDSTOP_Y_CN;
+ machine_menu.zEndstop_max = MAX_ENDSTOP_Z_CN;
+ machine_menu.FilamentEndstop = ENDSTOP_FIL_CN;
+ machine_menu.LevelingEndstop = ENDSTOP_LEVEL_CN;
+ machine_menu.opened = ENDSTOP_OPENED_CN;
+ machine_menu.closed = ENDSTOP_CLOSED_CN;
+
+ machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_CN;
+ machine_menu.InLength = FILAMENT_IN_LENGTH_CN;
+ machine_menu.InSpeed = FILAMENT_IN_SPEED_CN;
+ machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_CN;
+ machine_menu.OutLength = FILAMENT_OUT_LENGTH_CN;
+ machine_menu.OutSpeed = FILAMENT_OUT_SPEED_CN;
+
+ machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_CN;
+ machine_menu.LevelingParaConf = LEVELING_PARA_CONF_CN;
+ machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_CN;
+ machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_CN;
+ machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_CN;
+
+ machine_menu.LevelingSubConfTitle = LEVELING_PARA_CONF_TITLE_CN;
+ machine_menu.AutoLevelEnable = AUTO_LEVELING_ENABLE_CN;
+ machine_menu.BLtouchEnable = BLTOUCH_LEVELING_ENABLE_CN;
+ machine_menu.ProbePort = PROBE_PORT_CN;
+ machine_menu.ProbeXoffset = PROBE_X_OFFSET_CN;
+ machine_menu.ProbeYoffset = PROBE_Y_OFFSET_CN;
+ machine_menu.ProbeZoffset = PROBE_Z_OFFSET_CN;
+ machine_menu.ProbeXYspeed = PROBE_XY_SPEED_CN;
+ machine_menu.ProbeZspeed = PROBE_Z_SPEED_CN;
+ machine_menu.enable = ENABLE_CN;
+ machine_menu.disable = DISABLE_CN;
+ machine_menu.locked = LOCKED_CN;
+ machine_menu.z_min = Z_MIN_CN;
+ machine_menu.z_max = Z_MAX_CN;
+
+ machine_menu.LevelingSubDeltaConfTitle = DELTA_LEVEL_CONF_TITLE_CN;
+ machine_menu.MachineRadius = DELTA_MACHINE_RADIUS_CN;
+ machine_menu.DiagonalRod = DELTA_DIAGONAL_ROD_CN;
+ machine_menu.PrintableRadius = DELTA_PRINT_RADIUS_CN;
+ machine_menu.DeltaHeight = DELTA_HEIGHT_CN;
+ machine_menu.SmoothRodOffset = SMOOTH_ROD_OFFSET_CN;
+ machine_menu.EffectorOffset = EFFECTOR_OFFSET_CN;
+ machine_menu.CalibrationRadius = CALIBRATION_RADIUS_CN;
+
+ machine_menu.LevelingSubXYZConfTitle = XYZ_LEVEL_CONF_TITLE_CN;
+
+ machine_menu.TemperatureConfTitle = TEMPERATURE_CONF_TITLE_CN;
+ machine_menu.NozzleConf = NOZZLE_CONF_CN;
+ machine_menu.HotBedConf = HOTBED_CONF_CN;
+ machine_menu.PreheatTemperConf = PREHEAT_TEMPER_CN;
+
+ machine_menu.NozzleConfTitle = NOZZLE_CONF_TITLE_CN;
+ machine_menu.NozzleCnt = NOZZLECNT_CN;
+ machine_menu.NozzleType = NOZZLE_TYPE_CN;
+ machine_menu.NozzleAdjustType = NOZZLE_ADJUST_TYPE_CN;
+ machine_menu.NozzleMinTemperature = NOZZLE_MIN_TEMPERATURE_CN;
+ machine_menu.NozzleMaxTemperature = NOZZLE_MAX_TEMPERATURE_CN;
+ machine_menu.Extrude_Min_Temper = EXTRUD_MIN_TEMPER_CN;
+
+ machine_menu.HotbedConfTitle = HOTBED_CONF_TITLE_CN;
+ machine_menu.HotbedAjustType = HOTBED_ADJUST_CN;
+ machine_menu.HotbedMinTemperature = HOTBED_MIN_TEMPERATURE_CN;
+ machine_menu.HotbedMaxTemperature = HOTBED_MAX_TEMPERATURE_CN;
+
+ machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_CN;
+ machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_CN;
+ machine_menu.AccelerationConf = ACCELERATION_CONF_CN;
+ machine_menu.JerkConf = JERKCONF_CN;
+ machine_menu.StepsConf = STEPSCONF_CN;
+ machine_menu.TMCcurrentConf = TMC_CURRENT_CN;
+ machine_menu.TMCStepModeConf = TMC_STEP_MODE_CN;
+ machine_menu.MotorDirConf = MOTORDIRCONF_CN;
+ machine_menu.HomeFeedRateConf = HOMEFEEDRATECONF_CN;
+ machine_menu.PausePosition = PAUSE_POSITION_CN;
+ machine_menu.WifiSettings = WIFI_SETTINGS_CN;
+ machine_menu.HomingSensitivityConf = HOMING_SENSITIVITY_CONF_CN;
+ machine_menu.EncoderSettings = ENCODER_SETTINGS_CN;
+
+ machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_CN;
+ machine_menu.XMaxFeedRate = X_MAXFEEDRATE_CN;
+ machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_CN;
+ machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_CN;
+ machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_CN;
+ machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_CN;
+
+ machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_CN;
+ machine_menu.PrintAcceleration = PRINT_ACCELERATION_CN;
+ machine_menu.RetractAcceleration = RETRACT_ACCELERATION_CN;
+ machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_CN;
+ machine_menu.X_Acceleration = X_ACCELERATION_CN;
+ machine_menu.Y_Acceleration = Y_ACCELERATION_CN;
+ machine_menu.Z_Acceleration = Z_ACCELERATION_CN;
+ machine_menu.E0_Acceleration = E0_ACCELERATION_CN;
+ machine_menu.E1_Acceleration = E1_ACCELERATION_CN;
+
+ machine_menu.JerkConfTitle = JERK_CONF_TITLE_CN;
+ machine_menu.X_Jerk = X_JERK_CN;
+ machine_menu.Y_Jerk = Y_JERK_CN;
+ machine_menu.Z_Jerk = Z_JERK_CN;
+ machine_menu.E_Jerk = E_JERK_CN;
+
+ machine_menu.StepsConfTitle = STEPS_CONF_TITLE_CN;
+ machine_menu.X_Steps = X_STEPS_CN;
+ machine_menu.Y_Steps = Y_STEPS_CN;
+ machine_menu.Z_Steps = Z_STEPS_CN;
+ machine_menu.E0_Steps = E0_STEPS_CN;
+ machine_menu.E1_Steps = E1_STEPS_CN;
+
+ machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_CN;
+ machine_menu.X_Current = X_TMC_CURRENT_CN;
+ machine_menu.Y_Current = Y_TMC_CURRENT_CN;
+ machine_menu.Z_Current = Z_TMC_CURRENT_CN;
+ machine_menu.E0_Current = E0_TMC_CURRENT_CN;
+ machine_menu.E1_Current = E1_TMC_CURRENT_CN;
+
+ machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_CN;
+ machine_menu.X_StepMode = X_TMC_MODE_CN;
+ machine_menu.Y_StepMode = Y_TMC_MODE_CN;
+ machine_menu.Z_StepMode = Z_TMC_MODE_CN;
+ machine_menu.E0_StepMode = E0_TMC_MODE_CN;
+ machine_menu.E1_StepMode = E1_TMC_MODE_CN;
+
+ machine_menu.MotorDirConfTitle = MOTORDIR_CONF_TITLE_CN;
+ machine_menu.X_MotorDir = X_MOTORDIR_CN;
+ machine_menu.Y_MotorDir = Y_MOTORDIR_CN;
+ machine_menu.Z_MotorDir = Z_MOTORDIR_CN;
+ machine_menu.E0_MotorDir = E0_MOTORDIR_CN;
+ machine_menu.E1_MotorDir = E1_MOTORDIR_CN;
+ machine_menu.Invert_0 = INVERT_P_CN;
+ machine_menu.Invert_1 = INVERT_N_CN;
+
+ machine_menu.HomeFeedRateConfTitle = HOMEFEEDRATE_CONF_TITLE_CN;
+ machine_menu.XY_HomeFeedRate = X_HOMESPEED_CN;
+ machine_menu.Z_HomeFeedRate = Z_HOMESPEED_CN;
+
+ machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_CN;
+ machine_menu.PwrOffDection = PWROFF_DECTION_CN;
+ machine_menu.PwrOffAfterPrint = PWROFF_AFTER_PRINT_CN;
+ machine_menu.HaveUps = HAVE_UPS_CN;
+ machine_menu.Z2andZ2Endstop = Z2_AND_Z2ENDSTOP_CONF_CN;
+ machine_menu.EnablePinsInvert = ENABLE_PINS_CONF_CN;
+
+ machine_menu.Z2ConfTitle = Z2_AND_Z2ENDSTOP_CONF_TITLE_CN;
+ machine_menu.Z2Enable = Z2_ENABLE_CN;
+ machine_menu.Z2EndstopEnable = Z2_ENDSTOP_CN;
+ machine_menu.Z2Port = Z2_PORT_CN;
+
+ machine_menu.EnablePinsInvertTitle = ENABLE_PINS_CONF_TITLE_CN;
+ machine_menu.XInvert = X_ENABLE_PINS_INVERT_CN;
+ machine_menu.YInvert = Y_ENABLE_PINS_INVERT_CN;
+ machine_menu.ZInvert = Z_ENABLE_PINS_INVERT_CN;
+ machine_menu.EInvert = E_ENABLE_PINS_INVERT_CN;
+
+ machine_menu.key_back = KEY_BACK_CN;
+ machine_menu.key_reset = KEY_REST_CN;
+ machine_menu.key_confirm = KEY_CONFIRM_CN;
+
+ machine_menu.PausePosText = PAUSE_POSITION_CN;
+ machine_menu.xPos = PAUSE_POSITION_X_CN;
+ machine_menu.yPos = PAUSE_POSITION_Y_CN;
+ machine_menu.zPos = PAUSE_POSITION_Z_CN;
+ machine_menu.WifiConfTitle = WIFI_SETTINGS_TITLE_CN;
+ machine_menu.wifiMode = WIFI_SETTINGS_MODE_CN;
+ machine_menu.wifiName = WIFI_SETTINGS_NAME_CN;
+ machine_menu.wifiPassWord = WIFI_SETTINGS_PASSWORD_CN;
+ machine_menu.wifiCloud = WIFI_SETTINGS_CLOUD_CN;
+ machine_menu.wifiConfig = WIFI_SETTINGS_CONFIG_CN;
+ machine_menu.wifiEdit = WIFI_SETTINGS_EDIT_CN;
+ machine_menu.wifiConfigTips = WIFI_CONFIG_TIPS_CN;
+
+ machine_menu.OffsetConfTitle = OFFSET_TITLE_CN;
+ machine_menu.Xoffset = OFFSET_X_CN;
+ machine_menu.Yoffset = OFFSET_Y_CN;
+ machine_menu.Zoffset = OFFSET_Z_CN;
+
+ machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_CN;
+ machine_menu.TouchmiInit = TM_INIT_CN;
+ machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_CN;
+ machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_CN;
+ machine_menu.TouchmiSave = TM_SAVE_CN;
+ machine_menu.TouchmiTest = TM_TEST_CN;
+
+ machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_CN;
+ machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_CN;
+ machine_menu.BLTouchInit = BLTOUCH_INIT_CN;
+ machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_CN;
+ machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_CN;
+ machine_menu.BLTouchSave = BLTOUCH_SAVE_CN;
+ machine_menu.BLTouchTest = BLTOUCH_TEST_CN;
+
+ machine_menu.HomingSensitivityConfTitle = HOMING_SENSITIVITY_CONF_TITLE_CN;
+ machine_menu.X_Sensitivity = X_SENSITIVITY_CN;
+ machine_menu.Y_Sensitivity = Y_SENSITIVITY_CN;
+ machine_menu.Z_Sensitivity = Z_SENSITIVITY_CN;
+ machine_menu.Z2_Sensitivity = Z2_SENSITIVITY_CN;
+
+ machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_CN;
+ machine_menu.EncoderConfText = ENCODER_CONF_TEXT_CN;
+ }
+ else if (gCfgItems.language == LANG_COMPLEX_CHINESE) {
+ MachinePara_menu.title = MACHINE_PARA_TITLE_T_CN;
+ MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_T_CN;
+ MachinePara_menu.MotorSetting = MOTOR_CONFIG_T_CN;
+ MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_T_CN;
+ MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_T_CN;
+
+ machine_menu.default_value = DEFAULT_T_CN;
+ machine_menu.next = NEXT_T_CN;
+ machine_menu.previous = PREVIOUS_T_CN;
+
+ machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_T_CN;
+ machine_menu.MachineType = MACHINE_TYPE_T_CN;
+ machine_menu.Stroke = MACHINE_STROKE_T_CN;
+ machine_menu.HomeDir = MACHINE_HOMEDIR_T_CN;
+ machine_menu.EndStopType = MACHINE_ENDSTOP_TYPE_T_CN;
+ machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_T_CN;
+
+ machine_menu.MachineTypeConfTitle = MACHINE_TYPE_CONFIG_TITLE_T_CN;
+ machine_menu.xyz = MACHINE_TYPE_XYZ_T_CN;
+ machine_menu.delta = MACHINE_TYPE_DELTA_T_CN;
+ machine_menu.corexy = MACHINE_TYPE_COREXY_T_CN;
+
+ machine_menu.StrokeConfTitle = MACHINE_STROKE_CONF_TITLE_T_CN;
+ machine_menu.xStroke = X_MAX_LENGTH_T_CN;
+ machine_menu.yStroke = Y_MAX_LENGTH_T_CN;
+ machine_menu.zStroke = Z_MAX_LENGTH_T_CN;
+
+ machine_menu.xmin = X_MIN_LENGTH_T_CN;
+ machine_menu.ymin = Y_MIN_LENGTH_T_CN;
+ machine_menu.zmin = Z_MIN_LENGTH_T_CN;
+
+ machine_menu.HomeDirConfTitle = HOME_DIR_CONF_TITLE_T_CN;
+ machine_menu.xHomeDir = HOME_DIR_X_T_CN;
+ machine_menu.yHomeDir = HOME_DIR_Y_T_CN;
+ machine_menu.zHomeDir = HOME_DIR_Z_T_CN;
+ machine_menu.min = HOME_MIN_T_CN;
+ machine_menu.max = HOME_MAX_T_CN;
+
+ machine_menu.EndstopConfTitle = ENDSTOP_CONF_TITLE_T_CN;
+ machine_menu.xEndstop_min = MIN_ENDSTOP_X_T_CN;
+ machine_menu.yEndstop_min = MIN_ENDSTOP_Y_T_CN;
+ machine_menu.zEndstop_min = MIN_ENDSTOP_Z_T_CN;
+ machine_menu.xEndstop_max = MAX_ENDSTOP_X_T_CN;
+ machine_menu.yEndstop_max = MAX_ENDSTOP_Y_T_CN;
+ machine_menu.zEndstop_max = MAX_ENDSTOP_Z_T_CN;
+ machine_menu.FilamentEndstop = ENDSTOP_FIL_T_CN;
+ machine_menu.LevelingEndstop = ENDSTOP_LEVEL_T_CN;
+ machine_menu.opened = ENDSTOP_OPENED_T_CN;
+ machine_menu.closed = ENDSTOP_CLOSED_T_CN;
+
+ machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_T_CN;
+ machine_menu.InLength = FILAMENT_IN_LENGTH_T_CN;
+ machine_menu.InSpeed = FILAMENT_IN_SPEED_T_CN;
+ machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_T_CN;
+ machine_menu.OutLength = FILAMENT_OUT_LENGTH_T_CN;
+ machine_menu.OutSpeed = FILAMENT_OUT_SPEED_T_CN;
+
+ machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_T_CN;
+ machine_menu.LevelingParaConf = LEVELING_PARA_CONF_T_CN;
+ machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_T_CN;
+ machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_T_CN;
+ machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_T_CN;
+
+ machine_menu.LevelingSubConfTitle = LEVELING_PARA_CONF_TITLE_T_CN;
+ machine_menu.AutoLevelEnable = AUTO_LEVELING_ENABLE_T_CN;
+ machine_menu.BLtouchEnable = BLTOUCH_LEVELING_ENABLE_T_CN;
+ machine_menu.ProbePort = PROBE_PORT_T_CN;
+ machine_menu.ProbeXoffset = PROBE_X_OFFSET_T_CN;
+ machine_menu.ProbeYoffset = PROBE_Y_OFFSET_T_CN;
+ machine_menu.ProbeZoffset = PROBE_Z_OFFSET_T_CN;
+ machine_menu.ProbeXYspeed = PROBE_XY_SPEED_T_CN;
+ machine_menu.ProbeZspeed = PROBE_Z_SPEED_T_CN;
+ machine_menu.enable = ENABLE_T_CN;
+ machine_menu.disable = DISABLE_T_CN;
+ machine_menu.locked = LOCKED_T_CN;
+ machine_menu.z_min = Z_MIN_T_CN;
+ machine_menu.z_max = Z_MAX_T_CN;
+
+ machine_menu.LevelingSubDeltaConfTitle = DELTA_LEVEL_CONF_TITLE_T_CN;
+ machine_menu.MachineRadius = DELTA_MACHINE_RADIUS_T_CN;
+ machine_menu.DiagonalRod = DELTA_DIAGONAL_ROD_T_CN;
+ machine_menu.PrintableRadius = DELTA_PRINT_RADIUS_T_CN;
+ machine_menu.DeltaHeight = DELTA_HEIGHT_T_CN;
+ machine_menu.SmoothRodOffset = SMOOTH_ROD_OFFSET_T_CN;
+ machine_menu.EffectorOffset = EFFECTOR_OFFSET_T_CN;
+ machine_menu.CalibrationRadius = CALIBRATION_RADIUS_T_CN;
+
+ machine_menu.LevelingSubXYZConfTitle = XYZ_LEVEL_CONF_TITLE_T_CN;
+
+ machine_menu.TemperatureConfTitle = TEMPERATURE_CONF_TITLE_T_CN;
+ machine_menu.NozzleConf = NOZZLE_CONF_T_CN;
+ machine_menu.HotBedConf = HOTBED_CONF_T_CN;
+ machine_menu.PreheatTemperConf = PREHEAT_TEMPER_T_CN;
+
+ machine_menu.NozzleConfTitle = NOZZLE_CONF_TITLE_T_CN;
+ machine_menu.NozzleCnt = NOZZLECNT_T_CN;
+ machine_menu.NozzleType = NOZZLE_TYPE_T_CN;
+ machine_menu.NozzleAdjustType = NOZZLE_ADJUST_TYPE_T_CN;
+ machine_menu.NozzleMinTemperature = NOZZLE_MIN_TEMPERATURE_T_CN;
+ machine_menu.NozzleMaxTemperature = NOZZLE_MAX_TEMPERATURE_T_CN;
+ machine_menu.Extrude_Min_Temper = EXTRUD_MIN_TEMPER_T_CN;
+
+ machine_menu.HotbedConfTitle = HOTBED_CONF_TITLE_T_CN;
+ machine_menu.HotbedAjustType = HOTBED_ADJUST_T_CN;
+ machine_menu.HotbedMinTemperature = HOTBED_MIN_TEMPERATURE_T_CN;
+ machine_menu.HotbedMaxTemperature = HOTBED_MAX_TEMPERATURE_T_CN;
+
+ machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_T_CN;
+ machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_T_CN;
+ machine_menu.AccelerationConf = ACCELERATION_CONF_T_CN;
+ machine_menu.JerkConf = JERKCONF_T_CN;
+ machine_menu.StepsConf = STEPSCONF_T_CN;
+ machine_menu.TMCcurrentConf = TMC_CURRENT_T_CN;
+ machine_menu.TMCStepModeConf = TMC_STEP_MODE_T_CN;
+ machine_menu.MotorDirConf = MOTORDIRCONF_T_CN;
+ machine_menu.HomeFeedRateConf = HOMEFEEDRATECONF_T_CN;
+ machine_menu.PausePosition = PAUSE_POSITION_T_CN;
+ machine_menu.WifiSettings = WIFI_SETTINGS_T_CN;
+ machine_menu.HomingSensitivityConf = HOMING_SENSITIVITY_CONF_T_CN;
+ machine_menu.EncoderSettings = ENCODER_SETTINGS_T_CN;
+
+ machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_T_CN;
+ machine_menu.XMaxFeedRate = X_MAXFEEDRATE_T_CN;
+ machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_T_CN;
+ machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_T_CN;
+ machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_T_CN;
+ machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_T_CN;
+
+ machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_T_CN;
+ machine_menu.PrintAcceleration = PRINT_ACCELERATION_T_CN;
+ machine_menu.RetractAcceleration = RETRACT_ACCELERATION_T_CN;
+ machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_T_CN;
+ machine_menu.X_Acceleration = X_ACCELERATION_T_CN;
+ machine_menu.Y_Acceleration = Y_ACCELERATION_T_CN;
+ machine_menu.Z_Acceleration = Z_ACCELERATION_T_CN;
+ machine_menu.E0_Acceleration = E0_ACCELERATION_T_CN;
+ machine_menu.E1_Acceleration = E1_ACCELERATION_T_CN;
+
+ machine_menu.JerkConfTitle = JERK_CONF_TITLE_T_CN;
+ machine_menu.X_Jerk = X_JERK_T_CN;
+ machine_menu.Y_Jerk = Y_JERK_T_CN;
+ machine_menu.Z_Jerk = Z_JERK_T_CN;
+ machine_menu.E_Jerk = E_JERK_T_CN;
+
+ machine_menu.StepsConfTitle = STEPS_CONF_TITLE_T_CN;
+ machine_menu.X_Steps = X_STEPS_T_CN;
+ machine_menu.Y_Steps = Y_STEPS_T_CN;
+ machine_menu.Z_Steps = Z_STEPS_T_CN;
+ machine_menu.E0_Steps = E0_STEPS_T_CN;
+ machine_menu.E1_Steps = E1_STEPS_T_CN;
+
+ machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_T_CN;
+ machine_menu.X_Current = X_TMC_CURRENT_T_CN;
+ machine_menu.Y_Current = Y_TMC_CURRENT_T_CN;
+ machine_menu.Z_Current = Z_TMC_CURRENT_T_CN;
+ machine_menu.E0_Current = E0_TMC_CURRENT_T_CN;
+ machine_menu.E1_Current = E1_TMC_CURRENT_T_CN;
+
+ machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_T_CN;
+ machine_menu.X_StepMode = X_TMC_MODE_T_CN;
+ machine_menu.Y_StepMode = Y_TMC_MODE_T_CN;
+ machine_menu.Z_StepMode = Z_TMC_MODE_T_CN;
+ machine_menu.E0_StepMode = E0_TMC_MODE_T_CN;
+ machine_menu.E1_StepMode = E1_TMC_MODE_T_CN;
+
+ machine_menu.MotorDirConfTitle = MOTORDIR_CONF_TITLE_T_CN;
+ machine_menu.X_MotorDir = X_MOTORDIR_T_CN;
+ machine_menu.Y_MotorDir = Y_MOTORDIR_T_CN;
+ machine_menu.Z_MotorDir = Z_MOTORDIR_T_CN;
+ machine_menu.E0_MotorDir = E0_MOTORDIR_T_CN;
+ machine_menu.E1_MotorDir = E1_MOTORDIR_T_CN;
+ machine_menu.Invert_0 = INVERT_P_T_CN;
+ machine_menu.Invert_1 = INVERT_N_T_CN;
+
+ machine_menu.HomeFeedRateConfTitle = HOMEFEEDRATE_CONF_TITLE_T_CN;
+ machine_menu.XY_HomeFeedRate = X_HOMESPEED_T_CN;
+ machine_menu.Z_HomeFeedRate = Z_HOMESPEED_T_CN;
+
+ machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_T_CN;
+ machine_menu.PwrOffDection = PWROFF_DECTION_T_CN;
+ machine_menu.PwrOffAfterPrint = PWROFF_AFTER_PRINT_T_CN;
+ machine_menu.HaveUps = HAVE_UPS_T_CN;
+ machine_menu.Z2andZ2Endstop = Z2_AND_Z2ENDSTOP_CONF_T_CN;
+ machine_menu.EnablePinsInvert = ENABLE_PINS_CONF_T_CN;
+
+ machine_menu.Z2ConfTitle = Z2_AND_Z2ENDSTOP_CONF_TITLE_T_CN;
+ machine_menu.Z2Enable = Z2_ENABLE_T_CN;
+ machine_menu.Z2EndstopEnable = Z2_ENDSTOP_T_CN;
+ machine_menu.Z2Port = Z2_PORT_T_CN;
+
+ machine_menu.EnablePinsInvertTitle = ENABLE_PINS_CONF_TITLE_T_CN;
+ machine_menu.XInvert = X_ENABLE_PINS_INVERT_T_CN;
+ machine_menu.YInvert = Y_ENABLE_PINS_INVERT_T_CN;
+ machine_menu.ZInvert = Z_ENABLE_PINS_INVERT_T_CN;
+ machine_menu.EInvert = E_ENABLE_PINS_INVERT_T_CN;
+
+ machine_menu.key_back = KEY_BACK_T_CN;
+ machine_menu.key_reset = KEY_REST_T_CN;
+ machine_menu.key_confirm = KEY_CONFIRM_T_CN;
+
+ machine_menu.PausePosText = PAUSE_POSITION_T_CN;
+ machine_menu.xPos = PAUSE_POSITION_X_T_CN;
+ machine_menu.yPos = PAUSE_POSITION_Y_T_CN;
+ machine_menu.zPos = PAUSE_POSITION_Z_T_CN;
+
+ machine_menu.WifiConfTitle = WIFI_SETTINGS_TITLE_T_CN;
+ machine_menu.wifiMode = WIFI_SETTINGS_MODE_T_CN;
+ machine_menu.wifiName = WIFI_SETTINGS_NAME_T_CN;
+ machine_menu.wifiPassWord = WIFI_SETTINGS_PASSWORD_T_CN;
+ machine_menu.wifiCloud = WIFI_SETTINGS_CLOUD_T_CN;
+ machine_menu.wifiConfig = WIFI_SETTINGS_CONFIG_T_CN;
+ machine_menu.wifiEdit = WIFI_SETTINGS_EDIT_T_CN;
+ machine_menu.wifiConfigTips = WIFI_CONFIG_TIPS_T_CN;
+
+ machine_menu.OffsetConfTitle = OFFSET_TITLE_T_CN;
+ machine_menu.Xoffset = OFFSET_X_T_CN;
+ machine_menu.Yoffset = OFFSET_Y_T_CN;
+ machine_menu.Zoffset = OFFSET_Z_T_CN;
+
+ machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_T_CN;
+ machine_menu.TouchmiInit = TM_INIT_T_CN;
+ machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_T_CN;
+ machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_T_CN;
+ machine_menu.TouchmiSave = TM_SAVE_T_CN;
+ machine_menu.TouchmiTest = TM_TEST_T_CN;
+
+ machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_T_CN;
+ machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_T_CN;
+ machine_menu.BLTouchInit = BLTOUCH_INIT_T_CN;
+ machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_T_CN;
+ machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_T_CN;
+ machine_menu.BLTouchSave = BLTOUCH_SAVE_T_CN;
+ machine_menu.BLTouchTest = BLTOUCH_TEST_T_CN;
+
+ machine_menu.HomingSensitivityConfTitle = HOMING_SENSITIVITY_CONF_TITLE_T_CN;
+ machine_menu.X_Sensitivity = X_SENSITIVITY_T_CN;
+ machine_menu.Y_Sensitivity = Y_SENSITIVITY_T_CN;
+ machine_menu.Z_Sensitivity = Z_SENSITIVITY_T_CN;
+ machine_menu.Z2_Sensitivity = Z2_SENSITIVITY_T_CN;
+
+ machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_T_CN;
+ machine_menu.EncoderConfText = ENCODER_CONF_TEXT_T_CN;
+ }
+ else {
+ MachinePara_menu.title = MACHINE_PARA_TITLE_EN;
+ MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_EN;
+ MachinePara_menu.MotorSetting = MOTOR_CONFIG_EN;
+ MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_EN;
+ MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_EN;
+
+ machine_menu.default_value = DEFAULT_EN;
+ machine_menu.next = NEXT_EN;
+ machine_menu.previous = PREVIOUS_EN;
+
+ machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_EN;
+ machine_menu.MachineType = MACHINE_TYPE_EN;
+ machine_menu.Stroke = MACHINE_STROKE_EN;
+ machine_menu.HomeDir = MACHINE_HOMEDIR_EN;
+ machine_menu.EndStopType = MACHINE_ENDSTOP_TYPE_EN;
+ machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_EN;
+
+ machine_menu.MachineTypeConfTitle = MACHINE_TYPE_CONFIG_TITLE_EN;
+ machine_menu.xyz = MACHINE_TYPE_XYZ_EN;
+ machine_menu.delta = MACHINE_TYPE_DELTA_EN;
+ machine_menu.corexy = MACHINE_TYPE_COREXY_EN;
+
+ machine_menu.StrokeConfTitle = MACHINE_STROKE_CONF_TITLE_EN;
+ machine_menu.xStroke = X_MAX_LENGTH_EN;
+ machine_menu.yStroke = Y_MAX_LENGTH_EN;
+ machine_menu.zStroke = Z_MAX_LENGTH_EN;
+
+ machine_menu.xmin = X_MIN_LENGTH_EN;
+ machine_menu.ymin = Y_MIN_LENGTH_EN;
+ machine_menu.zmin = Z_MIN_LENGTH_EN;
+
+ machine_menu.HomeDirConfTitle = HOME_DIR_CONF_TITLE_EN;
+ machine_menu.xHomeDir = HOME_DIR_X_EN;
+ machine_menu.yHomeDir = HOME_DIR_Y_EN;
+ machine_menu.zHomeDir = HOME_DIR_Z_EN;
+ machine_menu.min = HOME_MIN_EN;
+ machine_menu.max = HOME_MAX_EN;
+
+ machine_menu.EndstopConfTitle = ENDSTOP_CONF_TITLE_EN;
+ machine_menu.xEndstop_min = MIN_ENDSTOP_X_EN;
+ machine_menu.yEndstop_min = MIN_ENDSTOP_Y_EN;
+ machine_menu.zEndstop_min = MIN_ENDSTOP_Z_EN;
+ machine_menu.xEndstop_max = MAX_ENDSTOP_X_EN;
+ machine_menu.yEndstop_max = MAX_ENDSTOP_Y_EN;
+ machine_menu.zEndstop_max = MAX_ENDSTOP_Z_EN;
+ machine_menu.FilamentEndstop = ENDSTOP_FIL_EN;
+ machine_menu.LevelingEndstop = ENDSTOP_LEVEL_EN;
+ machine_menu.opened = ENDSTOP_OPENED_EN;
+ machine_menu.closed = ENDSTOP_CLOSED_EN;
+
+ machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_EN;
+ machine_menu.InLength = FILAMENT_IN_LENGTH_EN;
+ machine_menu.InSpeed = FILAMENT_IN_SPEED_EN;
+ machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_EN;
+ machine_menu.OutLength = FILAMENT_OUT_LENGTH_EN;
+ machine_menu.OutSpeed = FILAMENT_OUT_SPEED_EN;
+
+ machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_EN;
+ machine_menu.LevelingParaConf = LEVELING_PARA_CONF_EN;
+ machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_EN;
+ machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_EN;
+ machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_EN;
+
+ machine_menu.LevelingSubConfTitle = LEVELING_PARA_CONF_TITLE_EN;
+ machine_menu.AutoLevelEnable = AUTO_LEVELING_ENABLE_EN;
+ machine_menu.BLtouchEnable = BLTOUCH_LEVELING_ENABLE_EN;
+ machine_menu.ProbePort = PROBE_PORT_EN;
+ machine_menu.ProbeXoffset = PROBE_X_OFFSET_EN;
+ machine_menu.ProbeYoffset = PROBE_Y_OFFSET_EN;
+ machine_menu.ProbeZoffset = PROBE_Z_OFFSET_EN;
+ machine_menu.ProbeXYspeed = PROBE_XY_SPEED_EN;
+ machine_menu.ProbeZspeed = PROBE_Z_SPEED_EN;
+ machine_menu.enable = ENABLE_EN;
+ machine_menu.disable = DISABLE_EN;
+ machine_menu.locked = LOCKED_EN;
+ machine_menu.z_min = Z_MIN_EN;
+ machine_menu.z_max = Z_MAX_EN;
+
+ machine_menu.LevelingSubDeltaConfTitle = DELTA_LEVEL_CONF_TITLE_EN;
+ machine_menu.MachineRadius = DELTA_MACHINE_RADIUS_EN;
+ machine_menu.DiagonalRod = DELTA_DIAGONAL_ROD_EN;
+ machine_menu.PrintableRadius = DELTA_PRINT_RADIUS_EN;
+ machine_menu.DeltaHeight = DELTA_HEIGHT_EN;
+ machine_menu.SmoothRodOffset = SMOOTH_ROD_OFFSET_EN;
+ machine_menu.EffectorOffset = EFFECTOR_OFFSET_EN;
+ machine_menu.CalibrationRadius = CALIBRATION_RADIUS_EN;
+
+ machine_menu.LevelingSubXYZConfTitle = XYZ_LEVEL_CONF_TITLE_EN;
+
+ machine_menu.TemperatureConfTitle = TEMPERATURE_CONF_TITLE_EN;
+ machine_menu.NozzleConf = NOZZLE_CONF_EN;
+ machine_menu.HotBedConf = HOTBED_CONF_EN;
+ machine_menu.PreheatTemperConf = PREHEAT_TEMPER_EN;
+
+ machine_menu.NozzleConfTitle = NOZZLE_CONF_TITLE_EN;
+ machine_menu.NozzleCnt = NOZZLECNT_EN;
+ machine_menu.NozzleType = NOZZLE_TYPE_EN;
+ machine_menu.NozzleAdjustType = NOZZLE_ADJUST_TYPE_EN;
+ machine_menu.NozzleMinTemperature = NOZZLE_MIN_TEMPERATURE_EN;
+ machine_menu.NozzleMaxTemperature = NOZZLE_MAX_TEMPERATURE_EN;
+ machine_menu.Extrude_Min_Temper = EXTRUD_MIN_TEMPER_EN;
+
+ machine_menu.HotbedEnable = HOTBED_ENABLE_EN;
+ machine_menu.HotbedConfTitle = HOTBED_CONF_TITLE_EN;
+ machine_menu.HotbedAjustType = HOTBED_ADJUST_EN;
+ machine_menu.HotbedMinTemperature = HOTBED_MIN_TEMPERATURE_EN;
+ machine_menu.HotbedMaxTemperature = HOTBED_MAX_TEMPERATURE_EN;
+
+ machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_EN;
+ machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_EN;
+ machine_menu.AccelerationConf = ACCELERATION_CONF_EN;
+ machine_menu.JerkConf = JERKCONF_EN;
+ machine_menu.StepsConf = STEPSCONF_EN;
+ machine_menu.TMCcurrentConf = TMC_CURRENT_EN;
+ machine_menu.TMCStepModeConf = TMC_STEP_MODE_EN;
+ machine_menu.MotorDirConf = MOTORDIRCONF_EN;
+ machine_menu.HomeFeedRateConf = HOMEFEEDRATECONF_EN;
+ machine_menu.PausePosition = PAUSE_POSITION_EN;
+ machine_menu.WifiSettings = WIFI_SETTINGS_EN;
+ machine_menu.HomingSensitivityConf = HOMING_SENSITIVITY_CONF_EN;
+ machine_menu.EncoderSettings = ENCODER_SETTINGS_EN;
+
+ machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_EN;
+ machine_menu.XMaxFeedRate = X_MAXFEEDRATE_EN;
+ machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_EN;
+ machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_EN;
+ machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_EN;
+ machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_EN;
+
+ machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_EN;
+ machine_menu.PrintAcceleration = PRINT_ACCELERATION_EN;
+ machine_menu.RetractAcceleration = RETRACT_ACCELERATION_EN;
+ machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_EN;
+ machine_menu.X_Acceleration = X_ACCELERATION_EN;
+ machine_menu.Y_Acceleration = Y_ACCELERATION_EN;
+ machine_menu.Z_Acceleration = Z_ACCELERATION_EN;
+ machine_menu.E0_Acceleration = E0_ACCELERATION_EN;
+ machine_menu.E1_Acceleration = E1_ACCELERATION_EN;
+
+ machine_menu.JerkConfTitle = JERK_CONF_TITLE_EN;
+ machine_menu.X_Jerk = X_JERK_EN;
+ machine_menu.Y_Jerk = Y_JERK_EN;
+ machine_menu.Z_Jerk = Z_JERK_EN;
+ machine_menu.E_Jerk = E_JERK_EN;
+
+ machine_menu.StepsConfTitle = STEPS_CONF_TITLE_EN;
+ machine_menu.X_Steps = X_STEPS_EN;
+ machine_menu.Y_Steps = Y_STEPS_EN;
+ machine_menu.Z_Steps = Z_STEPS_EN;
+ machine_menu.E0_Steps = E0_STEPS_EN;
+ machine_menu.E1_Steps = E1_STEPS_EN;
+
+ machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_EN;
+ machine_menu.X_Current = X_TMC_CURRENT_EN;
+ machine_menu.Y_Current = Y_TMC_CURRENT_EN;
+ machine_menu.Z_Current = Z_TMC_CURRENT_EN;
+ machine_menu.E0_Current = E0_TMC_CURRENT_EN;
+ machine_menu.E1_Current = E1_TMC_CURRENT_EN;
+
+ machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_EN;
+ machine_menu.X_StepMode = X_TMC_MODE_EN;
+ machine_menu.Y_StepMode = Y_TMC_MODE_EN;
+ machine_menu.Z_StepMode = Z_TMC_MODE_EN;
+ machine_menu.E0_StepMode = E0_TMC_MODE_EN;
+ machine_menu.E1_StepMode = E1_TMC_MODE_EN;
+
+ machine_menu.MotorDirConfTitle = MOTORDIR_CONF_TITLE_EN;
+ machine_menu.X_MotorDir = X_MOTORDIR_EN;
+ machine_menu.Y_MotorDir = Y_MOTORDIR_EN;
+ machine_menu.Z_MotorDir = Z_MOTORDIR_EN;
+ machine_menu.E0_MotorDir = E0_MOTORDIR_EN;
+ machine_menu.E1_MotorDir = E1_MOTORDIR_EN;
+ machine_menu.Invert_0 = INVERT_P_EN;
+ machine_menu.Invert_1 = INVERT_N_EN;
+
+ machine_menu.HomeFeedRateConfTitle = HOMEFEEDRATE_CONF_TITLE_EN;
+ machine_menu.XY_HomeFeedRate = X_HOMESPEED_EN;
+ machine_menu.Z_HomeFeedRate = Z_HOMESPEED_EN;
+
+ machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_EN;
+ machine_menu.PwrOffDection = PWROFF_DECTION_EN;
+ machine_menu.PwrOffAfterPrint = PWROFF_AFTER_PRINT_EN;
+ machine_menu.HaveUps = HAVE_UPS_EN;
+ machine_menu.Z2andZ2Endstop = Z2_AND_Z2ENDSTOP_CONF_EN;
+ machine_menu.EnablePinsInvert = ENABLE_PINS_CONF_EN;
+
+ machine_menu.Z2ConfTitle = Z2_AND_Z2ENDSTOP_CONF_TITLE_EN;
+ machine_menu.Z2Enable = Z2_ENABLE_EN;
+ machine_menu.Z2EndstopEnable = Z2_ENDSTOP_EN;
+ machine_menu.Z2Port = Z2_PORT_EN;
+
+ machine_menu.EnablePinsInvertTitle = ENABLE_PINS_CONF_TITLE_EN;
+ machine_menu.XInvert = X_ENABLE_PINS_INVERT_EN;
+ machine_menu.YInvert = Y_ENABLE_PINS_INVERT_EN;
+ machine_menu.ZInvert = Z_ENABLE_PINS_INVERT_EN;
+ machine_menu.EInvert = E_ENABLE_PINS_INVERT_EN;
+
+ machine_menu.key_back = KEY_BACK_EN;
+ machine_menu.key_reset = KEY_REST_EN;
+ machine_menu.key_confirm = KEY_CONFIRM_EN;
+ //
+ machine_menu.high_level = MOTOR_EN_HIGH_LEVEL_EN;
+ machine_menu.low_level = MOTOR_EN_LOW_LEVEL_EN;
+
+ machine_menu.PausePosText = PAUSE_POSITION_EN;
+ machine_menu.xPos = PAUSE_POSITION_X_EN;
+ machine_menu.yPos = PAUSE_POSITION_Y_EN;
+ machine_menu.zPos = PAUSE_POSITION_Z_EN;
+ machine_menu.WifiConfTitle = WIFI_SETTINGS_TITLE_EN;
+ machine_menu.wifiMode = WIFI_SETTINGS_MODE_EN;
+ machine_menu.wifiName = WIFI_SETTINGS_NAME_EN;
+ machine_menu.wifiPassWord = WIFI_SETTINGS_PASSWORD_EN;
+ machine_menu.wifiCloud = WIFI_SETTINGS_CLOUD_EN;
+ machine_menu.wifiConfig = WIFI_SETTINGS_CONFIG_EN;
+ machine_menu.wifiEdit = WIFI_SETTINGS_EDIT_EN;
+ machine_menu.wifiConfigTips = WIFI_CONFIG_TIPS_EN;
+
+ machine_menu.OffsetConfTitle = OFFSET_TITLE_EN;
+ machine_menu.Xoffset = OFFSET_X_EN;
+ machine_menu.Yoffset = OFFSET_Y_EN;
+ machine_menu.Zoffset = OFFSET_Z_EN;
+
+ machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_EN;
+ machine_menu.TouchmiInit = TM_INIT_EN;
+ machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_EN;
+ machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_EN;
+ machine_menu.TouchmiSave = TM_SAVE_EN;
+ machine_menu.TouchmiTest = TM_TEST_EN;
+
+ machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_EN;
+ machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_EN;
+ machine_menu.BLTouchInit = BLTOUCH_INIT_EN;
+ machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_EN;
+ machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_EN;
+ machine_menu.BLTouchSave = BLTOUCH_SAVE_EN;
+ machine_menu.BLTouchTest = BLTOUCH_TEST_EN;
+
+ machine_menu.HomingSensitivityConfTitle = HOMING_SENSITIVITY_CONF_TITLE_EN;
+ machine_menu.X_Sensitivity = X_SENSITIVITY_EN;
+ machine_menu.Y_Sensitivity = Y_SENSITIVITY_EN;
+ machine_menu.Z_Sensitivity = Z_SENSITIVITY_EN;
+ machine_menu.Z2_Sensitivity = Z2_SENSITIVITY_EN;
+
+ machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_EN;
+ machine_menu.EncoderConfText = ENCODER_CONF_TEXT_EN;
+ }
+}
+
+void disp_language_init() {
+ preheat_menu.value_state = TEXT_VALUE;
+ preheat_menu.step_1c = TEXT_1C;
+ preheat_menu.step_5c = TEXT_5C;
+ preheat_menu.step_10c = TEXT_10C;
+
+ move_menu.x_add = AXIS_X_ADD_TEXT;
+ move_menu.x_dec = AXIS_X_DEC_TEXT;
+ move_menu.y_add = AXIS_Y_ADD_TEXT;
+ move_menu.y_dec = AXIS_Y_DEC_TEXT;
+ move_menu.z_add = AXIS_Z_ADD_TEXT;
+ move_menu.z_dec = AXIS_Z_DEC_TEXT;
+
+ move_menu.step_001mm = TEXT_001MM;
+ move_menu.step_005mm = TEXT_005MM;
+ move_menu.step_01mm = TEXT_01MM;
+ move_menu.step_1mm = TEXT_1MM;
+ move_menu.step_10mm = TEXT_10MM;
+
+ home_menu.home_x = HOME_X_TEXT;
+ home_menu.home_y = HOME_Y_TEXT;
+ home_menu.home_z = HOME_Z_TEXT;
+ home_menu.home_all = HOME_ALL_TEXT;
+
+ extrude_menu.temp_value = TEXT_VALUE_T;
+ extrude_menu.count_value_mm = TEXT_VALUE_mm;
+ extrude_menu.count_value_cm = TEXT_VALUE_cm;
+ extrude_menu.count_value_m = TEXT_VALUE_m;
+ extrude_menu.step_1mm = EXTRUDE_1MM_TEXT;
+ extrude_menu.step_5mm = EXTRUDE_5MM_TEXT;
+ extrude_menu.step_10mm = EXTRUDE_10MM_TEXT;
+
+ fan_menu.full = FAN_OPEN_TEXT;
+ fan_menu.half = FAN_HALF_TEXT;
+ fan_menu.off = FAN_CLOSE_TEXT;
+
+ speed_menu.step_1percent = STEP_1PERCENT;
+ speed_menu.step_5percent = STEP_5PERCENT;
+ speed_menu.step_10percent = STEP_10PERCENT;
+
+ language_menu.chinese_s = LANGUAGE_S_CN;
+ language_menu.chinese_t = LANGUAGE_T_CN;
+ language_menu.english = LANGUAGE_EN;
+ language_menu.russian = LANGUAGE_RU;
+ language_menu.spanish = LANGUAGE_SP;
+ language_menu.german = LANGUAGE_GE;
+ language_menu.japan = LANGUAGE_JP;
+ language_menu.korean = LANGUAGE_KR;
+ language_menu.portuguese = LANGUAGE_PR;
+ language_menu.italy = LANGUAGE_IT;
+ language_menu.brazil = LANGUAGE_BR;
+ language_menu.french = LANGUAGE_FR;
+
+ about_menu.type_name = ABOUT_TYPE_TEXT;
+ about_menu.firmware_v = ABOUT_VERSION_TEXT;
+
+ wifi_menu.ip = WIFI_IP_TEXT;
+ wifi_menu.wifi = WIFI_NAME_TEXT;
+ wifi_menu.key = WIFI_KEY_TEXT;
+ wifi_menu.state_ap = WIFI_STATE_AP_TEXT;
+ wifi_menu.state_sta = WIFI_STATE_STA_TEXT;
+ wifi_menu.connected = WIFI_CONNECTED_TEXT;
+ wifi_menu.disconnected = WIFI_DISCONNECTED_TEXT;
+ wifi_menu.exception = WIFI_EXCEPTION_TEXT;
+
+ printing_menu.temp1 = TEXT_VALUE;
+ printing_menu.temp2 = TEXT_VALUE;
+ printing_menu.bed_temp = TEXT_VALUE;
+
+ filament_menu.stat_temp = TEXT_VALUE;
+
+ machine_menu.key_0 = KEYBOARD_KEY0_EN;
+ machine_menu.key_1 = KEYBOARD_KEY1_EN;
+ machine_menu.key_2 = KEYBOARD_KEY2_EN;
+ machine_menu.key_3 = KEYBOARD_KEY3_EN;
+ machine_menu.key_4 = KEYBOARD_KEY4_EN;
+ machine_menu.key_5 = KEYBOARD_KEY5_EN;
+ machine_menu.key_6 = KEYBOARD_KEY6_EN;
+ machine_menu.key_7 = KEYBOARD_KEY7_EN;
+ machine_menu.key_8 = KEYBOARD_KEY8_EN;
+ machine_menu.key_9 = KEYBOARD_KEY9_EN;
+ machine_menu.key_point = KEYBOARD_KEY_POINT_EN;
+ machine_menu.negative = KEYBOARD_KEY_NEGATIVE_EN;
+ // wifi-list
+ #if ENABLED(MKS_WIFI_MODULE)
+ list_menu.title = TEXT_WIFI_MENU_TITLE_EN;
+ list_menu.file_pages = FILE_PAGES_EN;
+
+ // tips
+ tips_menu.joining = TEXT_WIFI_JOINING_EN;
+ tips_menu.failedJoin = TEXT_WIFI_FAILED_JOIN_EN;
+ tips_menu.wifiConected = TEXT_WIFI_WIFI_CONECTED_EN;
+ #endif
+ machine_setting_disp();
+
+ operation_menu.babystep = TEXT_BABY_STEP_EN;
+
+ switch (gCfgItems.language) {
+ case LANG_SIMPLE_CHINESE:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_CN;
+ common_menu.text_back = BACK_TEXT_CN;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_CN;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_CN;
+ common_menu.print_special_title = PRINTING_GBK;
+ common_menu.pause_special_title = PRINTING_PAUSE_GBK;
+ common_menu.operate_special_title = PRINTING_OPERATION_GBK;
+ //
+ main_menu.title = TITLE_READYPRINT_CN;
+ main_menu.preheat = PREHEAT_TEXT_CN;
+ main_menu.move = MOVE_TEXT_CN;
+ main_menu.home = HOME_TEXT_CN;
+ main_menu.print = PRINT_TEXT_CN;
+ main_menu.extrude = EXTRUDE_TEXT_CN;
+ main_menu.leveling = LEVELING_TEXT_CN;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_CN;
+ main_menu.fan = FAN_TEXT_CN;
+ main_menu.set = SET_TEXT_CN;
+ main_menu.more = MORE_TEXT_CN;
+ main_menu.tool = TOOL_TEXT_CN;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_CN;
+ tool_menu.preheat = TOOL_PREHEAT_CN;
+ tool_menu.extrude = TOOL_EXTRUDE_CN;
+ tool_menu.move = TOOL_MOVE_CN;
+ tool_menu.home = TOOL_HOME_CN;
+ tool_menu.leveling = TOOL_LEVELING_CN;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_CN;
+ tool_menu.filament = TOOL_FILAMENT_CN;
+ tool_menu.more = TOOL_MORE_CN;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_CN;
+ preheat_menu.title = TITLE_PREHEAT_CN;
+ preheat_menu.add = ADD_TEXT_CN;
+ preheat_menu.dec = DEC_TEXT_CN;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_CN;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_CN;
+ preheat_menu.hotbed = HEATBED_TEXT_CN;
+ preheat_menu.off = CLOSE_TEXT_CN;
+
+ preheat_menu.value_state = TEXT_VALUE_CN;
+ preheat_menu.step_1c = TEXT_1C_CN;
+ preheat_menu.step_5c = TEXT_5C_CN;
+ preheat_menu.step_10c = TEXT_10C_CN;
+ //
+ move_menu.title = MOVE_TEXT_CN;
+ //
+ home_menu.title = TITLE_HOME_CN;
+ home_menu.stopmove = HOME_STOPMOVE_CN;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_CN;
+ file_menu.page_up = PAGE_UP_TEXT_CN;
+ file_menu.page_down = PAGE_DOWN_TEXT_CN;
+ file_menu.file_loading = FILE_LOADING_CN;
+ file_menu.no_file = NO_FILE_CN;
+ file_menu.no_file_and_check = NO_FILE_CN;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_CN;
+ extrude_menu.in = EXTRUDER_IN_TEXT_CN;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_CN;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_CN;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_CN;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_CN;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_CN;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_CN;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_CN;
+ extrude_menu.temp_value = EXTRUDE_TEXT_VALUE_T_CN;
+ //
+ leveling_menu.title = TITLE_LEVELING_CN;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_CN;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_CN;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_CN;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_CN;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_CN;
+ //
+ set_menu.title = TITLE_SET_CN;
+ set_menu.filesys = FILESYS_TEXT_CN;
+ set_menu.wifi = WIFI_TEXT_CN;
+ set_menu.about = ABOUT_TEXT_CN;
+ set_menu.fan = FAN_TEXT_CN;
+ set_menu.filament = FILAMENT_TEXT_CN;
+ set_menu.breakpoint = BREAK_POINT_TEXT_CN;
+ set_menu.motoroff = MOTOR_OFF_TEXT_CN;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_CN;
+ set_menu.language = LANGUAGE_TEXT_CN;
+ set_menu.shutdown = SHUTDOWN_TEXT_CN;
+ set_menu.machine_para = MACHINE_PARA_CN;
+ set_menu.eepromSet = EEPROM_SETTINGS_CN;
+ //
+ filesys_menu.title = TITLE_FILESYS_CN;
+ filesys_menu.sd_sys = SD_CARD_TEXT_CN;
+ filesys_menu.usb_sys = U_DISK_TEXT_CN;
+ //
+ more_menu.title = TITLE_MORE_CN;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_CN;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_CN;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_CN;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_CN;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_CN;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_CN;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_CN;
+ #endif
+ // WIFI
+ wifi_menu.title = WIFI_TEXT;
+ wifi_menu.cloud = CLOUD_TEXT_CN;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_CN;
+ // CLOUD
+ cloud_menu.title = TITLE_CLOUD_TEXT_CN;
+ cloud_menu.bind = CLOUD_BINDED_CN;
+ cloud_menu.binded = CLOUD_BINDED_CN;
+ cloud_menu.unbind = CLOUD_UNBIND_CN;
+ cloud_menu.unbinding = CLOUD_UNBINDED_CN;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_CN;
+ cloud_menu.unbinded = CLOUD_UNBINDED_CN;
+ cloud_menu.disable = CLOUD_DISABLE_CN;
+ //
+ about_menu.title = ABOUT_TEXT_CN;
+ about_menu.type = ABOUT_TYPE_TEXT_CN;
+ about_menu.version = ABOUT_VERSION_TEXT_CN;
+ about_menu.wifi = ABOUT_WIFI_TEXT_CN;
+
+ //
+ fan_menu.title = FAN_TEXT_CN;
+ fan_menu.add = FAN_ADD_TEXT_CN;
+ fan_menu.dec = FAN_DEC_TEXT_CN;
+ fan_menu.state = FAN_TIPS1_TEXT_CN;
+ //
+ filament_menu.title = TITLE_FILAMENT_CN;
+ filament_menu.in = FILAMENT_IN_TEXT_CN;
+ filament_menu.out = FILAMENT_OUT_TEXT_CN;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_CN;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_CN;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_CN;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_CN;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_CN;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_CN;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_CN;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_CN;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_CN;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_CN;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_CN;
+
+
+ //
+ language_menu.title = TITLE_LANGUAGE_CN;
+ language_menu.next = PAGE_DOWN_TEXT_CN;
+ language_menu.up = PAGE_UP_TEXT_CN;
+
+ //
+ printing_menu.title = TITLE_PRINTING_CN;
+ printing_menu.option = PRINTING_OPERATION_CN;
+ printing_menu.stop = PRINTING_STOP_CN;
+ printing_menu.pause = PRINTING_PAUSE_CN;
+ printing_menu.resume = PRINTING_RESUME_CN;
+
+ //
+ operation_menu.title = TITLE_OPERATION_CN;
+ operation_menu.pause = PRINTING_PAUSE_CN;
+ operation_menu.stop = PRINTING_STOP_CN;
+ operation_menu.temp = PRINTING_TEMP_CN;
+ operation_menu.fan = FAN_TEXT_CN;
+ operation_menu.filament = FILAMENT_TEXT_CN;
+ operation_menu.extr = PRINTING_EXTRUDER_CN;
+ operation_menu.speed = PRINTING_CHANGESPEED_CN;
+ operation_menu.more = PRINTING_MORE_CN;
+ operation_menu.move = PRINTING_MOVE_CN;
+ operation_menu.auto_off = AUTO_SHUTDOWN_CN;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_CN;
+ //
+ pause_menu.title = TITLE_PAUSE_CN;
+ pause_menu.resume = PRINTING_RESUME_CN;
+ pause_menu.stop = PRINTING_STOP_CN;
+ pause_menu.extrude = PRINTING_EXTRUDER_CN;
+ pause_menu.move = PRINTING_MOVE_CN;
+ pause_menu.filament = FILAMENT_TEXT_CN;
+ pause_menu.more = PRINTING_MORE_CN;
+
+ //
+ speed_menu.title = PRINTING_CHANGESPEED_CN;
+ speed_menu.add = ADD_TEXT_CN;
+ speed_menu.dec = DEC_TEXT_CN;
+ speed_menu.move = MOVE_SPEED_CN;
+ speed_menu.extrude = EXTRUDER_SPEED_CN;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_CN;
+ speed_menu.move_speed = MOVE_SPEED_STATE_CN;
+ //
+ printing_more_menu.title = TITLE_MORE_CN;
+ printing_more_menu.fan = FAN_TEXT_CN;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_CN;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_CN;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_CN;
+ printing_more_menu.temp = PRINTING_TEMP_CN;
+
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_CN;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_CN;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_CN;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_CN;
+ print_file_dialog_menu.retry = DIALOG_RETRY_CN;
+ print_file_dialog_menu.stop = DIALOG_STOP_CN;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_CN;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_CN;
+
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_CN;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_CN;
+
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_CN;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_CN;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_CN;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_CN;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_CN;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_CN;
+ pause_msg_menu.changing = MESSAGE_CHANGING_CN;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_CN;
+ pause_msg_menu.waiting = MESSAGE_WAITING_CN;
+ pause_msg_menu.insert = MESSAGE_INSERT_CN;
+ pause_msg_menu.load = MESSAGE_LOAD_CN;
+ pause_msg_menu.purge = MESSAGE_PURGE_CN;
+ pause_msg_menu.resume = MESSAGE_RESUME_CN;
+ pause_msg_menu.heat = MESSAGE_HEAT_CN;
+ pause_msg_menu.heating = MESSAGE_HEATING_CN;
+ pause_msg_menu.option = MESSAGE_OPTION_CN;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_CN;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_CN;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_CN;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_CN;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_CN;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_CN;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_CN;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_CN;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_CN;
+ break;
+
+ #if 1
+ #if 1
+
+ case LANG_COMPLEX_CHINESE:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_T_CN;
+ common_menu.text_back = BACK_TEXT_T_CN;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_T_CN;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_T_CN;
+ common_menu.print_special_title = PRINTING_GBK;
+ common_menu.pause_special_title = PRINTING_PAUSE_GBK;
+ common_menu.operate_special_title = PRINTING_OPERATION_GBK;
+ //
+ main_menu.title = TITLE_READYPRINT_T_CN;
+ main_menu.preheat = PREHEAT_TEXT_T_CN;
+ main_menu.move = MOVE_TEXT_T_CN;
+ main_menu.home = HOME_TEXT_T_CN;
+ main_menu.print = PRINT_TEXT_T_CN;
+ main_menu.extrude = EXTRUDE_TEXT_T_CN;
+ main_menu.leveling = LEVELING_TEXT_T_CN;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_T_CN;
+ main_menu.fan = FAN_TEXT_T_CN;
+ main_menu.set = SET_TEXT_T_CN;
+ main_menu.more = MORE_TEXT_T_CN;
+ main_menu.tool = TOOL_TEXT_T_CN;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_T_CN;
+ tool_menu.preheat = TOOL_PREHEAT_T_CN;
+ tool_menu.extrude = TOOL_EXTRUDE_T_CN;
+ tool_menu.move = TOOL_MOVE_T_CN;
+ tool_menu.home = TOOL_HOME_T_CN;
+ tool_menu.leveling = TOOL_LEVELING_T_CN;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_T_CN;
+ tool_menu.filament = TOOL_FILAMENT_T_CN;
+ tool_menu.more = TOOL_MORE_T_CN;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_T_CN;
+ preheat_menu.title = TITLE_PREHEAT_T_CN;
+ preheat_menu.add = ADD_TEXT_T_CN;
+ preheat_menu.dec = DEC_TEXT_T_CN;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_T_CN;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_T_CN;
+ preheat_menu.hotbed = HEATBED_TEXT_T_CN;
+ preheat_menu.off = CLOSE_TEXT_T_CN;
+ preheat_menu.value_state = TEXT_VALUE_T_CN;
+ preheat_menu.step_1c = TEXT_1C_T_CN;
+ preheat_menu.step_5c = TEXT_5C_T_CN;
+ preheat_menu.step_10c = TEXT_10C_T_CN;
+ //
+ move_menu.title = MOVE_TEXT_T_CN;
+ //
+ home_menu.title = TITLE_HOME_T_CN;
+ home_menu.stopmove = HOME_STOPMOVE_T_CN;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_T_CN;
+ file_menu.page_up = PAGE_UP_TEXT_T_CN;
+ file_menu.page_down = PAGE_DOWN_TEXT_T_CN;
+ file_menu.file_loading = FILE_LOADING_T_CN;
+ file_menu.no_file = NO_FILE_T_CN;
+ file_menu.no_file_and_check = NO_FILE_T_CN;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_T_CN;
+ extrude_menu.in = EXTRUDER_IN_TEXT_T_CN;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_T_CN;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_T_CN;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_T_CN;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_T_CN;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_T_CN;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_T_CN;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_T_CN;
+ extrude_menu.temp_value = EXTRUDE_TEXT_VALUE_T_T_CN;
+ //
+ leveling_menu.title = TITLE_LEVELING_CN;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_T_CN;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_T_CN;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_T_CN;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_T_CN;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_T_CN;
+ //
+ set_menu.title = TITLE_SET_T_CN;
+ set_menu.filesys = FILESYS_TEXT_T_CN;
+ set_menu.wifi = WIFI_TEXT_T_CN;
+ set_menu.about = ABOUT_TEXT_T_CN;
+ set_menu.fan = FAN_TEXT_T_CN;
+ set_menu.filament = FILAMENT_TEXT_T_CN;
+ set_menu.breakpoint = BREAK_POINT_TEXT_T_CN;
+ set_menu.motoroff = MOTOR_OFF_TEXT_T_CN;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_T_CN;
+ set_menu.language = LANGUAGE_TEXT_T_CN;
+ set_menu.shutdown = SHUTDOWN_TEXT_T_CN;
+ set_menu.machine_para = MACHINE_PARA_T_CN;
+ set_menu.eepromSet = EEPROM_SETTINGS_T_CN;
+ filesys_menu.title = TITLE_FILESYS_T_CN;
+ filesys_menu.sd_sys = SD_CARD_TEXT_T_CN;
+ filesys_menu.usb_sys = U_DISK_TEXT_T_CN;
+ //
+ more_menu.title = TITLE_MORE_T_CN;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_T_CN;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_T_CN;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_T_CN;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_T_CN;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_T_CN;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_T_CN;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_T_CN;
+ #endif
+ // WIFI
+ wifi_menu.title = WIFI_TEXT;
+ wifi_menu.cloud = CLOUD_TEXT_T_CN;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_T_CN;
+ // CLOUD
+ cloud_menu.title = TITLE_CLOUD_TEXT_T_CN;
+ cloud_menu.bind = CLOUD_BINDED_T_CN;
+ cloud_menu.binded = CLOUD_BINDED_T_CN;
+ cloud_menu.unbind = CLOUD_UNBIND_T_CN;
+ cloud_menu.unbinding = CLOUD_UNBINDED_T_CN;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_T_CN;
+ cloud_menu.unbinded = CLOUD_UNBINDED_T_CN;
+ cloud_menu.disable = CLOUD_DISABLE_T_CN;
+ //
+ about_menu.title = ABOUT_TEXT_T_CN;
+ about_menu.type = ABOUT_TYPE_TEXT_T_CN;
+ about_menu.version = ABOUT_VERSION_TEXT_T_CN;
+ about_menu.wifi = ABOUT_WIFI_TEXT_T_CN;
+
+ //
+ fan_menu.title = FAN_TEXT_T_CN;
+ fan_menu.add = FAN_ADD_TEXT_T_CN;
+ fan_menu.dec = FAN_DEC_TEXT_T_CN;
+ fan_menu.state = FAN_TIPS1_TEXT_T_CN;
+ //
+ filament_menu.title = TITLE_FILAMENT_T_CN;
+ filament_menu.in = FILAMENT_IN_TEXT_T_CN;
+ filament_menu.out = FILAMENT_OUT_TEXT_T_CN;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_T_CN;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_T_CN;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_T_CN;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_T_CN;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_T_CN;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_T_CN;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_T_CN;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_T_CN;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_T_CN;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_T_CN;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_T_CN;
+
+ //
+ language_menu.title = TITLE_LANGUAGE_T_CN;
+ language_menu.next = PAGE_DOWN_TEXT_T_CN;
+ language_menu.up = PAGE_UP_TEXT_T_CN;
+
+ //
+ printing_menu.title = TITLE_PRINTING_T_CN;
+ printing_menu.option = PRINTING_OPERATION_T_CN;
+ printing_menu.stop = PRINTING_STOP_T_CN;
+ printing_menu.pause = PRINTING_PAUSE_T_CN;
+ printing_menu.resume = PRINTING_RESUME_T_CN;
+
+ //
+ operation_menu.title = TITLE_OPERATION_T_CN;
+ operation_menu.pause = PRINTING_PAUSE_T_CN;
+ operation_menu.stop = PRINTING_STOP_T_CN;
+ operation_menu.temp = PRINTING_TEMP_T_CN;
+ operation_menu.fan = FAN_TEXT_T_CN;
+ operation_menu.extr = PRINTING_EXTRUDER_T_CN;
+ operation_menu.speed = PRINTING_CHANGESPEED_T_CN;
+ operation_menu.filament = FILAMENT_TEXT_T_CN;
+ operation_menu.more = PRINTING_MORE_T_CN;
+ operation_menu.move = PRINTING_MOVE_T_CN;
+ operation_menu.auto_off = AUTO_SHUTDOWN_T_CN;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_T_CN;
+ //
+ pause_menu.title = TITLE_PAUSE_T_CN;
+ pause_menu.resume = PRINTING_RESUME_T_CN;
+ pause_menu.stop = PRINTING_STOP_T_CN;
+ pause_menu.extrude = PRINTING_EXTRUDER_T_CN;
+ pause_menu.move = PRINTING_MOVE_T_CN;
+ pause_menu.filament = FILAMENT_TEXT_T_CN;
+ pause_menu.more = PRINTING_MORE_T_CN;
+
+ //
+ speed_menu.title = PRINTING_CHANGESPEED_T_CN;
+ speed_menu.add = ADD_TEXT_T_CN;
+ speed_menu.dec = DEC_TEXT_T_CN;
+ speed_menu.move = MOVE_SPEED_T_CN;
+ speed_menu.extrude = EXTRUDER_SPEED_T_CN;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_T_CN;
+ speed_menu.move_speed = MOVE_SPEED_STATE_T_CN;
+ //
+ printing_more_menu.title = TITLE_MORE_T_CN;
+ printing_more_menu.fan = FAN_TEXT_T_CN;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_T_CN;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_T_CN;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_T_CN;
+ printing_more_menu.temp = PRINTING_TEMP_T_CN;
+
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_T_CN;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_T_CN;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_T_CN;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_T_CN;
+ print_file_dialog_menu.retry = DIALOG_RETRY_T_CN;
+ print_file_dialog_menu.stop = DIALOG_STOP_T_CN;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_T_CN;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_T_CN;
+
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_T_CN;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_T_CN;
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_T_CN;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_T_CN;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_T_CN;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_T_CN;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_T_CN;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_T_CN;
+ pause_msg_menu.changing = MESSAGE_CHANGING_T_CN;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_T_CN;
+ pause_msg_menu.waiting = MESSAGE_WAITING_T_CN;
+ pause_msg_menu.insert = MESSAGE_INSERT_T_CN;
+ pause_msg_menu.load = MESSAGE_LOAD_T_CN;
+ pause_msg_menu.purge = MESSAGE_PURGE_T_CN;
+ pause_msg_menu.resume = MESSAGE_RESUME_T_CN;
+ pause_msg_menu.heat = MESSAGE_HEAT_T_CN;
+ pause_msg_menu.heating = MESSAGE_HEATING_T_CN;
+ pause_msg_menu.option = MESSAGE_OPTION_T_CN;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_T_CN;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_T_CN;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_T_CN;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_T_CN;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_T_CN;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_T_CN;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_T_CN;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_T_CN;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_T_CN;
+ break;
+ case LANG_ENGLISH:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_EN;
+ common_menu.text_back = BACK_TEXT_EN;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_EN;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_EN;
+ common_menu.print_special_title = PRINTING_OTHER_LANGUGE;
+ common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE;
+ common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE;
+ //
+ main_menu.title = TITLE_READYPRINT_EN;
+ main_menu.preheat = PREHEAT_TEXT_EN;
+ main_menu.move = MOVE_TEXT_EN;
+ main_menu.home = HOME_TEXT_EN;
+ main_menu.print = PRINT_TEXT_EN;
+ main_menu.extrude = EXTRUDE_TEXT_EN;
+ main_menu.leveling = LEVELING_TEXT_EN;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_EN;
+ main_menu.fan = FAN_TEXT_EN;
+ main_menu.set = SET_TEXT_EN;
+ main_menu.more = MORE_TEXT_EN;
+ main_menu.tool = TOOL_TEXT_EN;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_EN;
+ tool_menu.preheat = TOOL_PREHEAT_EN;
+ tool_menu.extrude = TOOL_EXTRUDE_EN;
+ tool_menu.move = TOOL_MOVE_EN;
+ tool_menu.home = TOOL_HOME_EN;
+ tool_menu.leveling = TOOL_LEVELING_EN;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_EN;
+ tool_menu.filament = TOOL_FILAMENT_EN;
+ tool_menu.more = TOOL_MORE_EN;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_EN;
+ preheat_menu.title = TITLE_PREHEAT_EN;
+ preheat_menu.add = ADD_TEXT_EN;
+ preheat_menu.dec = DEC_TEXT_EN;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_EN;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_EN;
+ preheat_menu.hotbed = HEATBED_TEXT_EN;
+ preheat_menu.off = CLOSE_TEXT_EN;
+ //
+ move_menu.title = TITLE_MOVE_EN;
+ //
+ home_menu.title = TITLE_HOME_EN;
+ home_menu.stopmove = HOME_STOPMOVE_EN;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_EN;
+ file_menu.page_up = PAGE_UP_TEXT_EN;
+ file_menu.page_down = PAGE_DOWN_TEXT_EN;
+ file_menu.file_loading = FILE_LOADING_EN;
+ file_menu.no_file = NO_FILE_EN;
+ file_menu.no_file_and_check = NO_FILE_EN;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_EN;
+ extrude_menu.in = EXTRUDER_IN_TEXT_EN;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_EN;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_EN;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_EN;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_EN;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_EN;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_EN;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_EN;
+ //
+ leveling_menu.title = TITLE_LEVELING_EN;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_EN;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_EN;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_EN;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_EN;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_EN;
+ //
+ set_menu.title = TITLE_SET_EN;
+ set_menu.filesys = FILESYS_TEXT_EN;
+ set_menu.wifi = WIFI_TEXT_EN;
+ set_menu.about = ABOUT_TEXT_EN;
+ set_menu.fan = FAN_TEXT_EN;
+ set_menu.filament = FILAMENT_TEXT_EN;
+ set_menu.breakpoint = BREAK_POINT_TEXT_EN;
+ set_menu.motoroff = MOTOR_OFF_TEXT_EN;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_EN;
+ set_menu.language = LANGUAGE_TEXT_EN;
+ set_menu.shutdown = SHUTDOWN_TEXT_EN;
+ set_menu.machine_para = MACHINE_PARA_EN;
+ set_menu.eepromSet = EEPROM_SETTINGS_EN;
+ more_menu.title = TITLE_MORE_EN;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_EN;
+ #endif
+
+ //
+ filesys_menu.title = TITLE_FILESYS_EN;
+ filesys_menu.sd_sys = SD_CARD_TEXT_EN;
+ filesys_menu.usb_sys = U_DISK_TEXT_EN;
+ // WIFI
+ wifi_menu.title = WIFI_TEXT;
+ wifi_menu.cloud = CLOUD_TEXT_EN;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_EN;
+
+ cloud_menu.title = TITLE_CLOUD_TEXT_EN;
+ cloud_menu.bind = CLOUD_BINDED_EN;
+ cloud_menu.binded = CLOUD_BINDED_EN;
+ cloud_menu.unbind = CLOUD_UNBIND_EN;
+ cloud_menu.unbinding = CLOUD_UNBINDED_EN;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_EN;
+ cloud_menu.unbinded = CLOUD_UNBINDED_EN;
+ cloud_menu.disable = CLOUD_DISABLE_EN;
+ //
+ about_menu.title = TITLE_ABOUT_EN;
+ about_menu.type = ABOUT_TYPE_TEXT_EN;
+ about_menu.version = ABOUT_VERSION_TEXT_EN;
+ about_menu.wifi = ABOUT_WIFI_TEXT_EN;
+ //
+ fan_menu.title = TITLE_FAN_EN;
+ fan_menu.add = FAN_ADD_TEXT_EN;
+ fan_menu.dec = FAN_DEC_TEXT_EN;
+ fan_menu.state = FAN_TIPS1_TEXT_EN;
+ //
+ filament_menu.title = TITLE_FILAMENT_EN;
+ filament_menu.in = FILAMENT_IN_TEXT_EN;
+ filament_menu.out = FILAMENT_OUT_TEXT_EN;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_EN;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_EN;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_EN;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_EN;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_EN;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_EN;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_EN;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_EN;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_EN;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_EN;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_EN;
+
+ //
+ language_menu.title = TITLE_LANGUAGE_EN;
+ language_menu.next = PAGE_DOWN_TEXT_EN;
+ language_menu.up = PAGE_UP_TEXT_EN;
+ //
+ printing_menu.title = TITLE_PRINTING_EN;
+ printing_menu.option = PRINTING_OPERATION_EN;
+ printing_menu.stop = PRINTING_STOP_EN;
+ printing_menu.pause = PRINTING_PAUSE_EN;
+ printing_menu.resume = PRINTING_RESUME_EN;
+
+ //
+ operation_menu.title = TITLE_OPERATION_EN;
+ operation_menu.pause = PRINTING_PAUSE_EN;
+ operation_menu.stop = PRINTING_STOP_EN;
+ operation_menu.temp = PRINTING_TEMP_EN;
+ operation_menu.fan = FAN_TEXT_EN;
+ operation_menu.extr = PRINTING_EXTRUDER_EN;
+ operation_menu.speed = PRINTING_CHANGESPEED_EN;
+ operation_menu.filament = FILAMENT_TEXT_EN;
+ operation_menu.more = PRINTING_MORE_EN;
+ operation_menu.move = PRINTING_MOVE_EN;
+ operation_menu.auto_off = AUTO_SHUTDOWN_EN;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_EN;
+ //
+ pause_menu.title = TITLE_PAUSE_EN;
+ pause_menu.resume = PRINTING_RESUME_EN;
+ pause_menu.stop = PRINTING_STOP_EN;
+ pause_menu.extrude = PRINTING_EXTRUDER_EN;
+ pause_menu.move = PRINTING_MOVE_EN;
+ pause_menu.filament = FILAMENT_TEXT_EN;
+ pause_menu.more = PRINTING_MORE_EN;
+
+ //
+ speed_menu.title = TITLE_CHANGESPEED_EN;
+ speed_menu.add = ADD_TEXT_EN;
+ speed_menu.dec = DEC_TEXT_EN;
+ speed_menu.move = MOVE_SPEED_EN;
+ speed_menu.extrude = EXTRUDER_SPEED_EN;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_EN;
+ speed_menu.move_speed = MOVE_SPEED_STATE_EN;
+ //
+ printing_more_menu.title = TITLE_MORE_EN;
+ printing_more_menu.fan = FAN_TEXT_EN;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_EN;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_EN;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_EN;
+ printing_more_menu.temp = PRINTING_TEMP_EN;
+
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_EN;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_EN;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_EN;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_EN;
+ print_file_dialog_menu.retry = DIALOG_RETRY_EN;
+ print_file_dialog_menu.stop = DIALOG_STOP_EN;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_EN;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_EN;
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_EN;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_EN;
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_EN;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_EN;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_EN;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_EN;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_EN;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_EN;
+ pause_msg_menu.changing = MESSAGE_CHANGING_EN;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_EN;
+ pause_msg_menu.waiting = MESSAGE_WAITING_EN;
+ pause_msg_menu.insert = MESSAGE_INSERT_EN;
+ pause_msg_menu.load = MESSAGE_LOAD_EN;
+ pause_msg_menu.purge = MESSAGE_PURGE_EN;
+ pause_msg_menu.resume = MESSAGE_RESUME_EN;
+ pause_msg_menu.heat = MESSAGE_HEAT_EN;
+ pause_msg_menu.heating = MESSAGE_HEATING_EN;
+ pause_msg_menu.option = MESSAGE_OPTION_EN;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_EN;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_EN;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_EN;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_EN;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_EN;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_EN;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_EN;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_EN;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_EN;
+ break;
+ case LANG_RUSSIAN:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_RU;
+ common_menu.text_back = BACK_TEXT_RU;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_RU;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_RU;
+ common_menu.print_special_title = PRINTING_OTHER_LANGUGE;
+ common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE;
+ common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE;
+ //
+ main_menu.title = TITLE_READYPRINT_RU;
+ main_menu.preheat = PREHEAT_TEXT_RU;
+ main_menu.move = MOVE_TEXT_RU;
+ main_menu.home = HOME_TEXT_RU;
+ main_menu.print = PRINT_TEXT_RU;
+ main_menu.extrude = EXTRUDE_TEXT_RU;
+ main_menu.leveling = LEVELING_TEXT_RU;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_RU;
+ main_menu.fan = FAN_TEXT_RU;
+ main_menu.set = SET_TEXT_RU;
+ main_menu.more = MORE_TEXT_RU;
+ main_menu.tool = TOOL_TEXT_RU;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_RU;
+ tool_menu.preheat = TOOL_PREHEAT_RU;
+ tool_menu.extrude = TOOL_EXTRUDE_RU;
+ tool_menu.move = TOOL_MOVE_RU;
+ tool_menu.home = TOOL_HOME_RU;
+ tool_menu.leveling = TOOL_LEVELING_RU;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_RU;
+ tool_menu.filament = TOOL_FILAMENT_RU;
+ tool_menu.more = TOOL_MORE_RU;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_RU;
+ preheat_menu.title = TITLE_PREHEAT_RU;
+ preheat_menu.add = ADD_TEXT_RU;
+ preheat_menu.dec = DEC_TEXT_RU;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_RU;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_RU;
+ preheat_menu.hotbed = HEATBED_TEXT_RU;
+ preheat_menu.off = CLOSE_TEXT_RU;
+ //
+ move_menu.title = MOVE_TEXT_RU;
+ //
+ home_menu.title = TITLE_HOME_RU;
+ home_menu.stopmove = HOME_STOPMOVE_RU;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_RU;
+ file_menu.page_up = PAGE_UP_TEXT_RU;
+ file_menu.page_down = PAGE_DOWN_TEXT_RU;
+ file_menu.file_loading = FILE_LOADING_RU;
+ file_menu.no_file = NO_FILE_RU;
+ file_menu.no_file_and_check = NO_FILE_RU;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_RU;
+ extrude_menu.in = EXTRUDER_IN_TEXT_RU;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_RU;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_RU;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_RU;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_RU;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_RU;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_RU;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_RU;
+ //
+ leveling_menu.title = TITLE_LEVELING_RU;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_RU;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_RU;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_RU;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_RU;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_RU;
+ //
+ set_menu.title = TITLE_SET_RU;
+ set_menu.filesys = FILESYS_TEXT_RU;
+ set_menu.wifi = WIFI_TEXT_RU;
+ set_menu.about = ABOUT_TEXT_RU;
+ set_menu.fan = FAN_TEXT_RU;
+ set_menu.filament = FILAMENT_TEXT_RU;
+ set_menu.breakpoint = BREAK_POINT_TEXT_RU;
+ set_menu.motoroff = MOTOR_OFF_TEXT_RU;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_RU;
+ set_menu.language = LANGUAGE_TEXT_RU;
+ set_menu.shutdown = SHUTDOWN_TEXT_RU;
+ set_menu.machine_para = MACHINE_PARA_RU;
+ set_menu.eepromSet = EEPROM_SETTINGS_RU;
+ more_menu.title = TITLE_MORE_RU;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_RU;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_RU;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_RU;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_RU;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_RU;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_RU;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_RU;
+ #endif
+ //
+ filesys_menu.title = TITLE_FILESYS_RU;
+ filesys_menu.sd_sys = SD_CARD_TEXT_RU;
+ filesys_menu.usb_sys = U_DISK_TEXT_RU;
+ // WIFI
+ wifi_menu.title = WIFI_TEXT;
+ wifi_menu.cloud = CLOUD_TEXT_RU;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_RU;
+
+ machine_menu.next = NEXT_RU;
+ machine_menu.previous = PREVIOUS_RU;
+ machine_menu.enable = ENABLE_RU;
+ machine_menu.disable = DISABLE_RU;
+ machine_menu.key_confirm = KEY_CONFIRM_RU;
+
+ MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_RU;
+ MachinePara_menu.title = MACHINE_PARA_TITLE_RU;
+ machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_RU;
+ MachinePara_menu.MotorSetting = MOTOR_CONFIG_RU;
+ MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_RU;
+ MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_RU;
+ machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_RU;
+ machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_RU;
+ machine_menu.AccelerationConf = ACCELERATION_CONF_RU;
+ machine_menu.JerkConf = JERKCONF_RU;
+ machine_menu.StepsConf = STEPSCONF_RU;
+ machine_menu.TMCcurrentConf = TMC_CURRENT_RU;
+ machine_menu.TMCStepModeConf = TMC_STEP_MODE_RU;
+ machine_menu.PausePosition = PAUSE_POSITION_RU;
+ machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_RU;
+ machine_menu.EncoderSettings = ENCODER_SETTINGS_RU;
+ machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_RU;
+
+ machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_RU;
+ machine_menu.LevelingParaConf = LEVELING_PARA_CONF_RU;
+ machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_RU;
+ machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_RU;
+ machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_RU;
+
+ machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_RU;
+ machine_menu.PrintAcceleration = PRINT_ACCELERATION_RU;
+ machine_menu.RetractAcceleration = RETRACT_ACCELERATION_RU;
+ machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_RU;
+ machine_menu.X_Acceleration = X_ACCELERATION_RU;
+ machine_menu.Y_Acceleration = Y_ACCELERATION_RU;
+ machine_menu.Z_Acceleration = Z_ACCELERATION_RU;
+ machine_menu.E0_Acceleration = E0_ACCELERATION_RU;
+ machine_menu.E1_Acceleration = E1_ACCELERATION_RU;
+
+ machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_RU;
+ machine_menu.XMaxFeedRate = X_MAXFEEDRATE_RU;
+ machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_RU;
+ machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_RU;
+ machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_RU;
+ machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_RU;
+
+ machine_menu.JerkConfTitle = JERK_CONF_TITLE_RU;
+ machine_menu.X_Jerk = X_JERK_RU;
+ machine_menu.Y_Jerk = Y_JERK_RU;
+ machine_menu.Z_Jerk = Z_JERK_RU;
+ machine_menu.E_Jerk = E_JERK_RU;
+
+ machine_menu.StepsConfTitle = STEPS_CONF_TITLE_RU;
+ machine_menu.X_Steps = X_STEPS_RU;
+ machine_menu.Y_Steps = Y_STEPS_RU;
+ machine_menu.Z_Steps = Z_STEPS_RU;
+ machine_menu.E0_Steps = E0_STEPS_RU;
+ machine_menu.E1_Steps = E1_STEPS_RU;
+
+ machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_RU;
+ machine_menu.X_Current = X_TMC_CURRENT_RU;
+ machine_menu.Y_Current = Y_TMC_CURRENT_RU;
+ machine_menu.Z_Current = Z_TMC_CURRENT_RU;
+ machine_menu.E0_Current = E0_TMC_CURRENT_RU;
+ machine_menu.E1_Current = E1_TMC_CURRENT_RU;
+
+ machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_RU;
+ machine_menu.X_StepMode = X_TMC_MODE_RU;
+ machine_menu.Y_StepMode = Y_TMC_MODE_RU;
+ machine_menu.Z_StepMode = Z_TMC_MODE_RU;
+ machine_menu.E0_StepMode = E0_TMC_MODE_RU;
+ machine_menu.E1_StepMode = E1_TMC_MODE_RU;
+
+ machine_menu.PausePosText = PAUSE_POSITION_RU;
+ machine_menu.xPos = PAUSE_POSITION_X_RU;
+ machine_menu.yPos = PAUSE_POSITION_Y_RU;
+ machine_menu.zPos = PAUSE_POSITION_Z_RU;
+
+ machine_menu.OffsetConfTitle = OFFSET_TITLE_RU;
+ machine_menu.Xoffset = OFFSET_X_RU;
+ machine_menu.Yoffset = OFFSET_Y_RU;
+ machine_menu.Zoffset = OFFSET_Z_RU;
+
+ machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_RU;
+ machine_menu.TouchmiInit = TM_INIT_RU;
+ machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_RU;
+ machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_RU;
+ machine_menu.TouchmiSave = TM_SAVE_RU;
+ machine_menu.TouchmiTest = TM_TEST_RU;
+
+ machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_RU;
+ machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_RU;
+ machine_menu.BLTouchInit = BLTOUCH_INIT_RU;
+ machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_RU;
+ machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_RU;
+ machine_menu.BLTouchSave = BLTOUCH_SAVE_RU;
+ machine_menu.BLTouchTest = BLTOUCH_TEST_RU;
+
+ machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_RU;
+ machine_menu.InLength = FILAMENT_IN_LENGTH_RU;
+ machine_menu.InSpeed = FILAMENT_IN_SPEED_RU;
+ machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_RU;
+ machine_menu.OutLength = FILAMENT_OUT_LENGTH_RU;
+ machine_menu.OutSpeed = FILAMENT_OUT_SPEED_RU;
+
+ machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_RU;
+ machine_menu.EncoderConfText = ENCODER_CONF_TEXT_RU;
+
+
+ cloud_menu.title = TITLE_CLOUD_TEXT_RU;
+ cloud_menu.bind = CLOUD_BINDED_RU;
+ cloud_menu.binded = CLOUD_BINDED_RU;
+ cloud_menu.unbind = CLOUD_UNBIND_RU;
+ cloud_menu.unbinding = CLOUD_UNBINDED_RU;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_RU;
+ cloud_menu.unbinded = CLOUD_UNBINDED_RU;
+ cloud_menu.disable = CLOUD_DISABLE_RU;
+ //
+ about_menu.title = ABOUT_TEXT_RU;
+ about_menu.type = ABOUT_TYPE_TEXT_RU;
+ about_menu.version = ABOUT_VERSION_TEXT_RU;
+ about_menu.wifi = ABOUT_WIFI_TEXT_RU;
+ //
+ fan_menu.title = FAN_TEXT_RU;
+ fan_menu.add = FAN_ADD_TEXT_RU;
+ fan_menu.dec = FAN_DEC_TEXT_RU;
+ fan_menu.state = FAN_TIPS1_TEXT_RU;
+ //
+ filament_menu.title = TITLE_FILAMENT_RU;
+ filament_menu.in = FILAMENT_IN_TEXT_RU;
+ filament_menu.out = FILAMENT_OUT_TEXT_RU;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_RU;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_RU;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_RU;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_RU;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_RU;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_RU;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_RU;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_RU;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_RU;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_RU;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_RU;
+
+ //
+ language_menu.title = LANGUAGE_TEXT_RU;
+ language_menu.next = PAGE_DOWN_TEXT_RU;
+ language_menu.up = PAGE_UP_TEXT_RU;
+ //
+ printing_menu.title = TITLE_PRINTING_RU;
+ printing_menu.option = PRINTING_OPERATION_RU;
+ printing_menu.stop = PRINTING_STOP_RU;
+ printing_menu.pause = PRINTING_PAUSE_RU;
+ printing_menu.resume = PRINTING_RESUME_RU;
+
+ //
+ operation_menu.title = TITLE_OPERATION_RU;
+ operation_menu.pause = PRINTING_PAUSE_RU;
+ operation_menu.stop = PRINTING_STOP_RU;
+ operation_menu.temp = PRINTING_TEMP_RU;
+ operation_menu.fan = FAN_TEXT_RU;
+ operation_menu.extr = PRINTING_EXTRUDER_RU;
+ operation_menu.speed = PRINTING_CHANGESPEED_RU;
+ operation_menu.filament = FILAMENT_TEXT_RU;
+ operation_menu.more = PRINTING_MORE_RU;
+ operation_menu.move = PRINTING_MOVE_RU;
+ operation_menu.auto_off = AUTO_SHUTDOWN_RU;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_RU;
+ //
+ pause_menu.title = TITLE_PAUSE_RU;
+ pause_menu.resume = PRINTING_RESUME_RU;
+ pause_menu.stop = PRINTING_STOP_RU;
+ pause_menu.extrude = PRINTING_EXTRUDER_RU;
+ pause_menu.move = PRINTING_MOVE_RU;
+ pause_menu.filament = FILAMENT_TEXT_RU;
+ pause_menu.more = PRINTING_MORE_RU;
+
+ //
+ speed_menu.title = PRINTING_CHANGESPEED_RU;
+ speed_menu.add = ADD_TEXT_RU;
+ speed_menu.dec = DEC_TEXT_RU;
+ speed_menu.move = MOVE_SPEED_RU;
+ speed_menu.extrude = EXTRUDER_SPEED_RU;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_RU;
+ speed_menu.move_speed = MOVE_SPEED_STATE_RU;
+ //
+ printing_more_menu.title = TITLE_MORE_RU;
+ printing_more_menu.fan = FAN_TEXT_RU;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_RU;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_RU;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_RU;
+ printing_more_menu.temp = PRINTING_TEMP_RU;
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_RU;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_RU;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_RU;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_RU;
+ print_file_dialog_menu.retry = DIALOG_RETRY_RU;
+ print_file_dialog_menu.stop = DIALOG_STOP_RU;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_RU;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_RU;
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_RU;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_RU;
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_RU;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_RU;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_RU;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_RU;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_RU;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_RU;
+ pause_msg_menu.changing = MESSAGE_CHANGING_RU;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_RU;
+ pause_msg_menu.waiting = MESSAGE_WAITING_RU;
+ pause_msg_menu.insert = MESSAGE_INSERT_RU;
+ pause_msg_menu.load = MESSAGE_LOAD_RU;
+ pause_msg_menu.purge = MESSAGE_PURGE_RU;
+ pause_msg_menu.resume = MESSAGE_RESUME_RU;
+ pause_msg_menu.heat = MESSAGE_HEAT_RU;
+ pause_msg_menu.heating = MESSAGE_HEATING_RU;
+ pause_msg_menu.option = MESSAGE_OPTION_RU;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_RU;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_RU;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_RU;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_RU;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_RU;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_RU;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_RU;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_RU;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_RU;
+ break;
+ case LANG_SPANISH:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_SP;
+ common_menu.text_back = BACK_TEXT_SP;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_SP;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_SP;
+ common_menu.print_special_title = PRINTING_SP;
+ common_menu.pause_special_title = PRINTING_PAUSAR_SP;
+ common_menu.operate_special_title = PRINTING_AJUSTES_SP;
+ //
+ main_menu.title = TITLE_READYPRINT_SP;
+ main_menu.preheat = PREHEAT_TEXT_SP;
+ main_menu.move = MOVE_TEXT_SP;
+ main_menu.home = HOME_TEXT_SP;
+ main_menu.print = PRINT_TEXT_SP;
+ main_menu.extrude = EXTRUDE_TEXT_SP;
+ main_menu.leveling = LEVELING_TEXT_SP;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_SP;
+ main_menu.fan = FAN_TEXT_SP;
+ main_menu.set = SET_TEXT_SP;
+ main_menu.more = MORE_TEXT_SP;
+ main_menu.tool = TOOL_TEXT_SP;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_SP;
+ tool_menu.preheat = TOOL_PREHEAT_SP;
+ tool_menu.extrude = TOOL_EXTRUDE_SP;
+ tool_menu.move = TOOL_MOVE_SP;
+ tool_menu.home = TOOL_HOME_SP;
+ tool_menu.leveling = TOOL_LEVELING_SP;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_SP;
+ tool_menu.filament = TOOL_FILAMENT_SP;
+ tool_menu.more = TOOL_MORE_SP;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_SP;
+ preheat_menu.title = TITLE_PREHEAT_SP;
+ preheat_menu.add = ADD_TEXT_SP;
+ preheat_menu.dec = DEC_TEXT_SP;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_SP;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_SP;
+ preheat_menu.hotbed = HEATBED_TEXT_SP;
+ preheat_menu.off = CLOSE_TEXT_SP;
+ //
+ move_menu.title = MOVE_TEXT_SP;
+ //
+ home_menu.title = TITLE_HOME_SP;
+ home_menu.home_x = HOME_X_TEXT_SP;
+ home_menu.home_y = HOME_Y_TEXT_SP;
+ home_menu.home_z = HOME_Z_TEXT_SP;
+ home_menu.home_all = HOME_ALL_TEXT_SP;
+ home_menu.stopmove = HOME_STOPMOVE_SP;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_SP;
+ file_menu.page_up = PAGE_UP_TEXT_SP;
+ file_menu.page_down = PAGE_DOWN_TEXT_SP;
+ file_menu.file_loading = FILE_LOADING_SP;
+ file_menu.no_file = NO_FILE_SP;
+ file_menu.no_file_and_check = NO_FILE_SP;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_SP;
+ extrude_menu.in = EXTRUDER_IN_TEXT_SP;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_SP;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_SP;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_SP;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_SP;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_SP;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_SP;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_SP;
+ //
+ leveling_menu.title = TITLE_LEVELING_SP;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_SP;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_SP;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_SP;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_SP;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_SP;
+ //
+ set_menu.title = TITLE_SET_SP;
+ set_menu.filesys = FILESYS_TEXT_SP;
+ set_menu.wifi = WIFI_TEXT_SP;
+ set_menu.about = ABOUT_TEXT_SP;
+ set_menu.fan = FAN_TEXT_SP;
+ set_menu.filament = FILAMENT_TEXT_SP;
+ set_menu.breakpoint = BREAK_POINT_TEXT_SP;
+ set_menu.motoroff = MOTOR_OFF_TEXT_SP;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_SP;
+ set_menu.language = LANGUAGE_TEXT_SP;
+ set_menu.shutdown = SHUTDOWN_TEXT_SP;
+ set_menu.machine_para = MACHINE_PARA_SP;
+ set_menu.eepromSet = EEPROM_SETTINGS_SP;
+ more_menu.title = TITLE_MORE_SP;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_SP;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_SP;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_SP;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_SP;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_SP;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_SP;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_SP;
+ #endif
+ //
+ filesys_menu.title = TITLE_FILESYS_SP;
+ filesys_menu.sd_sys = SD_CARD_TEXT_SP;
+ filesys_menu.usb_sys = U_DISK_TEXT_SP;
+
+ // WIFI
+ wifi_menu.title = WIFI_TEXT;
+ wifi_menu.cloud = CLOUD_TEXT_SP;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_SP;
+
+ cloud_menu.title = TITLE_CLOUD_TEXT_SP;
+ cloud_menu.bind = CLOUD_BINDED_SP;
+ cloud_menu.binded = CLOUD_BINDED_SP;
+ cloud_menu.unbind = CLOUD_UNBIND_SP;
+ cloud_menu.unbinding = CLOUD_UNBINDED_SP;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_SP;
+ cloud_menu.unbinded = CLOUD_UNBINDED_SP;
+ cloud_menu.disable = CLOUD_DISABLE_SP;
+ //
+ about_menu.title = ABOUT_TEXT_SP;
+ about_menu.type = ABOUT_TYPE_TEXT_SP;
+ about_menu.version = ABOUT_VERSION_TEXT_SP;
+ about_menu.wifi = ABOUT_WIFI_TEXT_SP;
+ //
+ fan_menu.title = FAN_TEXT_SP;
+ fan_menu.add = FAN_ADD_TEXT_SP;
+ fan_menu.dec = FAN_DEC_TEXT_SP;
+ fan_menu.state = FAN_TIPS1_TEXT_SP;
+ //
+ filament_menu.title = TITLE_FILAMENT_SP;
+ filament_menu.in = FILAMENT_IN_TEXT_SP;
+ filament_menu.out = FILAMENT_OUT_TEXT_SP;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_SP;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_SP;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_SP;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_SP;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_SP;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_SP;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_SP;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_SP;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_SP;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_SP;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_SP;
+
+ //
+ language_menu.title = LANGUAGE_TEXT_SP;
+ language_menu.next = PAGE_DOWN_TEXT_SP;
+ language_menu.up = PAGE_UP_TEXT_SP;
+ //
+ printing_menu.title = TITLE_PRINTING_SP;
+ printing_menu.option = PRINTING_OPERATION_SP;
+ printing_menu.stop = PRINTING_STOP_SP;
+ printing_menu.pause = PRINTING_PAUSE_SP;
+ printing_menu.resume = PRINTING_RESUME_SP;
+
+ //
+ operation_menu.title = TITLE_OPERATION_SP;
+ operation_menu.pause = PRINTING_PAUSE_SP;
+ operation_menu.stop = PRINTING_STOP_SP;
+ operation_menu.temp = PRINTING_TEMP_SP;
+ operation_menu.fan = FAN_TEXT_SP;
+ operation_menu.extr = PRINTING_EXTRUDER_SP;
+ operation_menu.speed = PRINTING_CHANGESPEED_SP;
+ operation_menu.filament = FILAMENT_TEXT_SP;
+ operation_menu.more = PRINTING_MORE_SP;
+ operation_menu.move = PRINTING_MOVE_SP;
+ operation_menu.auto_off = AUTO_SHUTDOWN_SP;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_SP;
+ //
+ pause_menu.title = TITLE_PAUSE_RU;
+ pause_menu.resume = PRINTING_RESUME_SP;
+ pause_menu.stop = PRINTING_STOP_SP;
+ pause_menu.extrude = PRINTING_EXTRUDER_SP;
+ pause_menu.move = PRINTING_MOVE_SP;
+ pause_menu.filament = FILAMENT_TEXT_SP;
+ pause_menu.more = PRINTING_MORE_SP;
+
+ //
+ speed_menu.title = PRINTING_CHANGESPEED_SP;
+ speed_menu.add = ADD_TEXT_SP;
+ speed_menu.dec = DEC_TEXT_SP;
+ speed_menu.move = MOVE_SPEED_SP;
+ speed_menu.extrude = EXTRUDER_SPEED_SP;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_SP;
+ speed_menu.move_speed = MOVE_SPEED_STATE_SP;
+ //
+ printing_more_menu.title = TITLE_MORE_SP;
+ printing_more_menu.fan = FAN_TEXT_SP;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_SP;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_SP;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_SP;
+ printing_more_menu.temp = PRINTING_TEMP_SP;
+
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_SP;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_SP;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_SP;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_SP;
+ print_file_dialog_menu.retry = DIALOG_RETRY_SP;
+ print_file_dialog_menu.stop = DIALOG_STOP_SP;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_SP;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_SP;
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_SP;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_SP;
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_SP;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_SP;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_SP;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_SP;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_SP;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_SP;
+ pause_msg_menu.changing = MESSAGE_CHANGING_SP;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_SP;
+ pause_msg_menu.waiting = MESSAGE_WAITING_SP;
+ pause_msg_menu.insert = MESSAGE_INSERT_SP;
+ pause_msg_menu.load = MESSAGE_LOAD_SP;
+ pause_msg_menu.purge = MESSAGE_PURGE_SP;
+ pause_msg_menu.resume = MESSAGE_RESUME_SP;
+ pause_msg_menu.heat = MESSAGE_HEAT_SP;
+ pause_msg_menu.heating = MESSAGE_HEATING_SP;
+ pause_msg_menu.option = MESSAGE_OPTION_SP;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_SP;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_SP;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_SP;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_SP;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_SP;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_SP;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_SP;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_SP;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_SP;
+ break;
+
+ #endif // if 1
+
+ case LANG_FRENCH:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_FR;
+ common_menu.text_back = BACK_TEXT_FR;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_FR;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_FR;
+ common_menu.print_special_title = PRINTING_OTHER_LANGUGE;
+ common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE;
+ common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE;
+
+ //
+ main_menu.title = TITLE_READYPRINT_FR;
+ main_menu.preheat = PREHEAT_TEXT_FR;
+ main_menu.move = MOVE_TEXT_FR;
+ main_menu.home = HOME_TEXT_FR;
+ main_menu.print = PRINT_TEXT_FR;
+ main_menu.extrude = EXTRUDE_TEXT_FR;
+ main_menu.leveling = LEVELING_TEXT_FR;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_FR;
+ main_menu.fan = FAN_TEXT_FR;
+ main_menu.set = SET_TEXT_FR;
+ main_menu.more = MORE_TEXT_FR;
+ main_menu.tool = TOOL_TEXT_FR;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_FR;
+ tool_menu.preheat = TOOL_PREHEAT_FR;
+ tool_menu.extrude = TOOL_EXTRUDE_FR;
+ tool_menu.move = TOOL_MOVE_FR;
+ tool_menu.home = TOOL_HOME_FR;
+ tool_menu.leveling = TOOL_LEVELING_FR;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_FR;
+ tool_menu.filament = TOOL_FILAMENT_FR;
+ tool_menu.more = TOOL_MORE_FR;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_FR;
+ preheat_menu.title = TITLE_PREHEAT_FR;
+ preheat_menu.add = ADD_TEXT_FR;
+ preheat_menu.dec = DEC_TEXT_FR;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_FR;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_FR;
+ preheat_menu.hotbed = HEATBED_TEXT_FR;
+ preheat_menu.off = CLOSE_TEXT_FR;
+ //
+ move_menu.title = MOVE_TEXT_FR;
+ //
+ home_menu.title = TITLE_HOME_FR;
+ home_menu.stopmove = HOME_STOPMOVE_FR;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_FR;
+ file_menu.page_up = PAGE_UP_TEXT_FR;
+ file_menu.page_down = PAGE_DOWN_TEXT_FR;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_FR;
+ extrude_menu.in = EXTRUDER_IN_TEXT_FR;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_FR;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_FR;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_FR;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_FR;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_FR;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_FR;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_FR;
+ //
+ leveling_menu.title = TITLE_LEVELING_FR;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_FR;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_FR;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_FR;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_FR;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_FR;
+ //
+ set_menu.title = TITLE_SET_FR;
+ set_menu.filesys = FILESYS_TEXT_FR;
+ set_menu.wifi = WIFI_TEXT_FR;
+ set_menu.about = ABOUT_TEXT_FR;
+ set_menu.fan = FAN_TEXT_FR;
+ set_menu.filament = FILAMENT_TEXT_FR;
+ set_menu.breakpoint = BREAK_POINT_TEXT_FR;
+ set_menu.motoroff = MOTOR_OFF_TEXT_FR;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_FR;
+ set_menu.language = LANGUAGE_TEXT_FR;
+ set_menu.shutdown = SHUTDOWN_TEXT_FR;
+ set_menu.machine_para = MACHINE_PARA_FR;
+ set_menu.eepromSet = EEPROM_SETTINGS_FR;
+ more_menu.title = TITLE_MORE_FR;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_FR;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_FR;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_FR;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_FR;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_FR;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_FR;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_FR;
+ #endif
+ //
+ filesys_menu.title = TITLE_FILESYS_FR;
+ filesys_menu.sd_sys = SD_CARD_TEXT_FR;
+ filesys_menu.usb_sys = U_DISK_TEXT_FR;
+ file_menu.file_loading = FILE_LOADING_FR;
+ file_menu.no_file = NO_FILE_FR;
+ file_menu.no_file_and_check = NO_FILE_FR;
+ // WIFI
+ wifi_menu.title = WIFI_NAME_TEXT_FR;
+ wifi_menu.cloud = CLOUD_TEXT_FR;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_FR;
+
+ cloud_menu.title = TITLE_CLOUD_TEXT_FR;
+ cloud_menu.bind = CLOUD_BINDED_FR;
+ cloud_menu.binded = CLOUD_BINDED_FR;
+ cloud_menu.unbind = CLOUD_UNBIND_FR;
+ cloud_menu.unbinding = CLOUD_UNBINDED_FR;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_FR;
+ cloud_menu.unbinded = CLOUD_UNBINDED_FR;
+ cloud_menu.disable = CLOUD_DISABLE_FR;
+ //
+ about_menu.title = ABOUT_TEXT_FR;
+ about_menu.type = ABOUT_TYPE_TEXT_FR;
+ about_menu.version = ABOUT_VERSION_TEXT_FR;
+ about_menu.wifi = ABOUT_WIFI_TEXT_FR;
+ //
+ fan_menu.title = FAN_TEXT_FR;
+ fan_menu.add = FAN_ADD_TEXT_FR;
+ fan_menu.dec = FAN_DEC_TEXT_FR;
+ fan_menu.state = FAN_TIPS1_TEXT_FR;
+ //
+ filament_menu.title = TITLE_FILAMENT_FR;
+ filament_menu.in = FILAMENT_IN_TEXT_FR;
+ filament_menu.out = FILAMENT_OUT_TEXT_FR;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_FR;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_FR;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_FR;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_FR;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_FR;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_FR;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_FR;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_FR;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_FR;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_FR;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_FR;
+
+ //
+ language_menu.title = LANGUAGE_TEXT_FR;
+
+ //
+ printing_menu.title = TITLE_PRINTING_FR;
+ printing_menu.option = PRINTING_OPERATION_FR;
+ printing_menu.stop = PRINTING_STOP_FR;
+ printing_menu.pause = PRINTING_PAUSE_FR;
+ printing_menu.resume = PRINTING_RESUME_FR;
+
+ //
+ operation_menu.title = TITLE_OPERATION_FR;
+ operation_menu.pause = PRINTING_PAUSE_FR;
+ operation_menu.stop = PRINTING_STOP_FR;
+ operation_menu.temp = PRINTING_TEMP_FR;
+ operation_menu.fan = FAN_TEXT_FR;
+ operation_menu.extr = PRINTING_EXTRUDER_FR;
+ operation_menu.speed = PRINTING_CHANGESPEED_FR;
+ operation_menu.filament = FILAMENT_TEXT_FR;
+ operation_menu.more = PRINTING_MORE_FR;
+ operation_menu.move = PRINTING_MOVE_FR;
+ operation_menu.auto_off = AUTO_SHUTDOWN_FR;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_FR;
+ //
+ pause_menu.title = TITLE_PAUSE_FR;
+ pause_menu.resume = PRINTING_RESUME_FR;
+ pause_menu.stop = PRINTING_STOP_FR;
+ pause_menu.extrude = PRINTING_EXTRUDER_FR;
+ pause_menu.move = PRINTING_MOVE_FR;
+ pause_menu.filament = FILAMENT_TEXT_FR;
+ pause_menu.more = PRINTING_MORE_FR;
+
+ //
+ speed_menu.title = PRINTING_CHANGESPEED_FR;
+ speed_menu.add = ADD_TEXT_FR;
+ speed_menu.dec = DEC_TEXT_FR;
+ speed_menu.move = MOVE_SPEED_FR;
+ speed_menu.extrude = EXTRUDER_SPEED_FR;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_FR;
+ speed_menu.move_speed = MOVE_SPEED_STATE_FR;
+ //
+ printing_more_menu.fan = FAN_TEXT_FR;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_FR;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_FR;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_FR;
+ printing_more_menu.temp = PRINTING_TEMP_FR;
+
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_FR;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_FR;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_FR;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_FR;
+ print_file_dialog_menu.retry = DIALOG_RETRY_FR;
+ print_file_dialog_menu.stop = DIALOG_STOP_FR;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_FR;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_FR;
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_FR;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_FR;
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_FR;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_FR;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_FR;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_FR;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_FR;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_FR;
+ pause_msg_menu.changing = MESSAGE_CHANGING_FR;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_FR;
+ pause_msg_menu.waiting = MESSAGE_WAITING_FR;
+ pause_msg_menu.insert = MESSAGE_INSERT_FR;
+ pause_msg_menu.load = MESSAGE_LOAD_FR;
+ pause_msg_menu.purge = MESSAGE_PURGE_FR;
+ pause_msg_menu.resume = MESSAGE_RESUME_FR;
+ pause_msg_menu.heat = MESSAGE_HEAT_FR;
+ pause_msg_menu.heating = MESSAGE_HEATING_FR;
+ pause_msg_menu.option = MESSAGE_OPTION_FR;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_FR;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_FR;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_FR;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_FR;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_FR;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_FR;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_FR;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_FR;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_FR;
+ break;
+
+ case LANG_ITALY:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_IT;
+ common_menu.text_back = BACK_TEXT_IT;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_IT;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_IT;
+ common_menu.print_special_title = PRINTING_OTHER_LANGUGE;
+ common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE;
+ common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE;
+
+ //
+ main_menu.title = TITLE_READYPRINT_IT;
+ main_menu.preheat = PREHEAT_TEXT_IT;
+ main_menu.move = MOVE_TEXT_IT;
+ main_menu.home = HOME_TEXT_IT;
+ main_menu.print = PRINT_TEXT_IT;
+ main_menu.extrude = EXTRUDE_TEXT_IT;
+ main_menu.leveling = LEVELING_TEXT_IT;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_IT;
+ main_menu.fan = FAN_TEXT_IT;
+ main_menu.set = SET_TEXT_IT;
+ main_menu.more = MORE_TEXT_IT;
+ main_menu.tool = TOOL_TEXT_IT;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_IT;
+ tool_menu.preheat = TOOL_PREHEAT_IT;
+ tool_menu.extrude = TOOL_EXTRUDE_IT;
+ tool_menu.move = TOOL_MOVE_IT;
+ tool_menu.home = TOOL_HOME_IT;
+ tool_menu.leveling = TOOL_LEVELING_IT;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_IT;
+ tool_menu.filament = TOOL_FILAMENT_IT;
+ tool_menu.more = TOOL_MORE_IT;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_IT;
+ preheat_menu.title = TITLE_PREHEAT_IT;
+ preheat_menu.add = ADD_TEXT_IT;
+ preheat_menu.dec = DEC_TEXT_IT;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_IT;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_IT;
+ preheat_menu.hotbed = HEATBED_TEXT_IT;
+ preheat_menu.off = CLOSE_TEXT_IT;
+ //
+ move_menu.title = MOVE_TEXT_IT;
+ //
+ home_menu.title = TITLE_HOME_IT;
+ home_menu.stopmove = HOME_STOPMOVE_IT;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_IT;
+ file_menu.page_up = PAGE_UP_TEXT_IT;
+ file_menu.page_down = PAGE_DOWN_TEXT_IT;
+ file_menu.file_loading = FILE_LOADING_IT;
+ file_menu.no_file = NO_FILE_IT;
+ file_menu.no_file_and_check = NO_FILE_IT;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_IT;
+ extrude_menu.in = EXTRUDER_IN_TEXT_IT;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_IT;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_IT;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_IT;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_IT;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_IT;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_IT;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_IT;
+ //
+ leveling_menu.title = TITLE_LEVELING_IT;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_IT;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_IT;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_IT;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_IT;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_IT;
+ //
+ set_menu.title = TITLE_SET_IT;
+ set_menu.filesys = FILESYS_TEXT_IT;
+ set_menu.wifi = WIFI_TEXT_IT;
+ set_menu.about = ABOUT_TEXT_IT;
+ set_menu.fan = FAN_TEXT_IT;
+ set_menu.filament = FILAMENT_TEXT_IT;
+ set_menu.breakpoint = BREAK_POINT_TEXT_IT;
+ set_menu.motoroff = MOTOR_OFF_TEXT_IT;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_IT;
+ set_menu.language = LANGUAGE_TEXT_IT;
+ set_menu.shutdown = SHUTDOWN_TEXT_IT;
+ set_menu.machine_para = MACHINE_PARA_IT;
+ set_menu.eepromSet = EEPROM_SETTINGS_IT;
+ more_menu.title = TITLE_MORE_IT;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_IT;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_IT;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_IT;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_IT;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_IT;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_IT;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_IT;
+ #endif
+ //
+ filesys_menu.title = TITLE_FILESYS_IT;
+ filesys_menu.sd_sys = SD_CARD_TEXT_IT;
+ filesys_menu.usb_sys = U_DISK_TEXT_IT;
+
+ // WIFI
+ wifi_menu.title = WIFI_NAME_TEXT_IT;
+ wifi_menu.cloud = CLOSE_TEXT_IT;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_IT;
+
+ cloud_menu.title = TITLE_CLOUD_TEXT_IT;
+ cloud_menu.bind = CLOUD_BINDED_IT;
+ cloud_menu.binded = CLOUD_BINDED_IT;
+ cloud_menu.unbind = CLOUD_UNBIND_IT;
+ cloud_menu.unbinding = CLOUD_UNBINDED_IT;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_IT;
+ cloud_menu.unbinded = CLOUD_UNBINDED_IT;
+ cloud_menu.disable = CLOUD_DISABLE_IT;
+ //
+ about_menu.title = ABOUT_TEXT_IT;
+ about_menu.type = ABOUT_TYPE_TEXT_IT;
+ about_menu.version = ABOUT_VERSION_TEXT_IT;
+ about_menu.wifi = ABOUT_WIFI_TEXT_IT;
+ //
+ fan_menu.title = FAN_TEXT_IT;
+ fan_menu.add = FAN_ADD_TEXT_IT;
+ fan_menu.dec = FAN_DEC_TEXT_IT;
+ fan_menu.state = FAN_TIPS1_TEXT_IT;
+ //
+ filament_menu.title = TITLE_FILAMENT_IT;
+ filament_menu.in = FILAMENT_IN_TEXT_IT;
+ filament_menu.out = FILAMENT_OUT_TEXT_IT;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_IT;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_IT;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_IT;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_IT;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_IT;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_IT;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_IT;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_IT;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_IT;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_IT;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_IT;
+
+ //
+ language_menu.title = LANGUAGE_TEXT_IT;
+
+ //
+ printing_menu.title = TITLE_PRINTING_IT;
+ printing_menu.option = PRINTING_OPERATION_IT;
+ printing_menu.stop = PRINTING_STOP_IT;
+ printing_menu.pause = PRINTING_PAUSE_IT;
+ printing_menu.resume = PRINTING_RESUME_IT;
+
+ //
+ operation_menu.title = TITLE_OPERATION_IT;
+ operation_menu.pause = PRINTING_PAUSE_IT;
+ operation_menu.stop = PRINTING_STOP_IT;
+ operation_menu.temp = PRINTING_TEMP_IT;
+ operation_menu.fan = FAN_TEXT_IT;
+ operation_menu.extr = PRINTING_EXTRUDER_IT;
+ operation_menu.speed = PRINTING_CHANGESPEED_IT;
+ operation_menu.filament = FILAMENT_TEXT_IT;
+ operation_menu.more = PRINTING_MORE_IT;
+ operation_menu.move = PRINTING_MOVE_IT;
+ operation_menu.auto_off = AUTO_SHUTDOWN_IT;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_IT;
+ //
+ pause_menu.title = TITLE_PAUSE_IT;
+ pause_menu.resume = PRINTING_RESUME_IT;
+ pause_menu.stop = PRINTING_STOP_IT;
+ pause_menu.extrude = PRINTING_EXTRUDER_IT;
+ pause_menu.move = PRINTING_MOVE_IT;
+ pause_menu.filament = FILAMENT_TEXT_IT;
+ pause_menu.more = PRINTING_MORE_IT;
+
+ //
+ speed_menu.title = PRINTING_CHANGESPEED_IT;
+ speed_menu.add = ADD_TEXT_IT;
+ speed_menu.dec = DEC_TEXT_IT;
+ speed_menu.move = MOVE_SPEED_IT;
+ speed_menu.extrude = EXTRUDER_SPEED_IT;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_IT;
+ speed_menu.move_speed = MOVE_SPEED_STATE_IT;
+ //
+ printing_more_menu.fan = FAN_TEXT_IT;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_IT;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_IT;
+ printing_more_menu.temp = PRINTING_TEMP_IT;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_IT;
+
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_IT;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_IT;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_IT;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_IT;
+ print_file_dialog_menu.retry = DIALOG_RETRY_IT;
+ print_file_dialog_menu.stop = DIALOG_STOP_IT;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_IT;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_IT;
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_IT;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_IT;
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_IT;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_IT;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_IT;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_IT;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_IT;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_IT;
+ pause_msg_menu.changing = MESSAGE_CHANGING_IT;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_IT;
+ pause_msg_menu.waiting = MESSAGE_WAITING_IT;
+ pause_msg_menu.insert = MESSAGE_INSERT_IT;
+ pause_msg_menu.load = MESSAGE_LOAD_IT;
+ pause_msg_menu.purge = MESSAGE_PURGE_IT;
+ pause_msg_menu.resume = MESSAGE_RESUME_IT;
+ pause_msg_menu.heat = MESSAGE_HEAT_IT;
+ pause_msg_menu.heating = MESSAGE_HEATING_IT;
+ pause_msg_menu.option = MESSAGE_OPTION_IT;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_IT;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_IT;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_IT;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_IT;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_IT;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_IT;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_IT;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_IT;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_IT;
+ break;
+
+ #endif // if 1
+
+ default:
+ common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_EN;
+ common_menu.text_back = BACK_TEXT_EN;
+ common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_EN;
+ common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_EN;
+ common_menu.print_special_title = PRINTING_OTHER_LANGUGE;
+ common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE;
+ common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE;
+ //
+ main_menu.title = TITLE_READYPRINT_EN;
+ main_menu.preheat = PREHEAT_TEXT_EN;
+ main_menu.move = MOVE_TEXT_EN;
+ main_menu.home = HOME_TEXT_EN;
+ main_menu.print = PRINT_TEXT_EN;
+ main_menu.extrude = EXTRUDE_TEXT_EN;
+ main_menu.leveling = LEVELING_TEXT_EN;
+ main_menu.autoleveling = AUTO_LEVELING_TEXT_EN;
+ main_menu.fan = FAN_TEXT_EN;
+ main_menu.set = SET_TEXT_EN;
+ main_menu.more = MORE_TEXT_EN;
+ main_menu.tool = TOOL_TEXT_EN;
+ // TOOL
+ tool_menu.title = TOOL_TEXT_EN;
+ tool_menu.preheat = TOOL_PREHEAT_EN;
+ tool_menu.extrude = TOOL_EXTRUDE_EN;
+ tool_menu.move = TOOL_MOVE_EN;
+ tool_menu.home = TOOL_HOME_EN;
+ tool_menu.leveling = TOOL_LEVELING_EN;
+ tool_menu.autoleveling = TOOL_AUTO_LEVELING_EN;
+ tool_menu.filament = TOOL_FILAMENT_EN;
+ tool_menu.more = TOOL_MORE_EN;
+ //
+ preheat_menu.adjust_title = TITLE_ADJUST_EN;
+ preheat_menu.title = TITLE_PREHEAT_EN;
+ preheat_menu.add = ADD_TEXT_EN;
+ preheat_menu.dec = DEC_TEXT_EN;
+ preheat_menu.ext1 = EXTRUDER_1_TEXT_EN;
+ preheat_menu.ext2 = EXTRUDER_2_TEXT_EN;
+ preheat_menu.hotbed = HEATBED_TEXT_EN;
+ preheat_menu.off = CLOSE_TEXT_EN;
+ //
+ move_menu.title = TITLE_MOVE_EN;
+ //
+ home_menu.title = TITLE_HOME_EN;
+ home_menu.stopmove = HOME_STOPMOVE_EN;
+ //
+ file_menu.title = TITLE_CHOOSEFILE_EN;
+ file_menu.page_up = PAGE_UP_TEXT_EN;
+ file_menu.page_down = PAGE_DOWN_TEXT_EN;
+ file_menu.file_loading = FILE_LOADING_EN;
+ file_menu.no_file = NO_FILE_EN;
+ file_menu.no_file_and_check = NO_FILE_EN;
+ //
+ extrude_menu.title = TITLE_EXTRUDE_EN;
+ extrude_menu.in = EXTRUDER_IN_TEXT_EN;
+ extrude_menu.out = EXTRUDER_OUT_TEXT_EN;
+ extrude_menu.ext1 = EXTRUDER_1_TEXT_EN;
+ extrude_menu.ext2 = EXTRUDER_2_TEXT_EN;
+ extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_EN;
+ extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_EN;
+ extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_EN;
+ extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_EN;
+ //
+ leveling_menu.title = TITLE_LEVELING_EN;
+ leveling_menu.position1 = LEVELING_POINT1_TEXT_EN;
+ leveling_menu.position2 = LEVELING_POINT2_TEXT_EN;
+ leveling_menu.position3 = LEVELING_POINT3_TEXT_EN;
+ leveling_menu.position4 = LEVELING_POINT4_TEXT_EN;
+ leveling_menu.position5 = LEVELING_POINT5_TEXT_EN;
+ //
+ set_menu.title = TITLE_SET_EN;
+ set_menu.filesys = FILESYS_TEXT_EN;
+ set_menu.wifi = WIFI_TEXT_EN;
+ set_menu.about = ABOUT_TEXT_EN;
+ set_menu.fan = FAN_TEXT_EN;
+ set_menu.filament = FILAMENT_TEXT_EN;
+ set_menu.breakpoint = BREAK_POINT_TEXT_EN;
+ set_menu.motoroff = MOTOR_OFF_TEXT_EN;
+ set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_EN;
+ set_menu.language = LANGUAGE_TEXT_EN;
+ set_menu.shutdown = SHUTDOWN_TEXT_EN;
+ set_menu.machine_para = MACHINE_PARA_EN;
+ set_menu.eepromSet = EEPROM_SETTINGS_EN;
+ //
+ more_menu.title = TITLE_MORE_EN;
+ #if ENABLED(USER_CMD_1_ENABLE)
+ more_menu.custom1 = MORE_CUSTOM1_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_2_ENABLE)
+ more_menu.custom2 = MORE_CUSTOM2_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_3_ENABLE)
+ more_menu.custom3 = MORE_CUSTOM3_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_4_ENABLE)
+ more_menu.custom4 = MORE_CUSTOM4_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_5_ENABLE)
+ more_menu.custom5 = MORE_CUSTOM5_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_6_ENABLE)
+ more_menu.custom6 = MORE_CUSTOM6_TEXT_EN;
+ #endif
+ #if ENABLED(USER_CMD_7_ENABLE)
+ more_menu.custom7 = MORE_CUSTOM7_TEXT_EN;
+ #endif
+ //
+ filesys_menu.title = TITLE_FILESYS_EN;
+ filesys_menu.sd_sys = SD_CARD_TEXT_EN;
+ filesys_menu.usb_sys = U_DISK_TEXT_EN;
+ // WIFI
+ wifi_menu.title = WIFI_TEXT;
+ wifi_menu.cloud = CLOUD_TEXT_EN;
+ wifi_menu.reconnect = WIFI_RECONNECT_TEXT_EN;
+
+ cloud_menu.title = TITLE_CLOUD_TEXT_EN;
+ cloud_menu.bind = CLOUD_BINDED_EN;
+ cloud_menu.binded = CLOUD_BINDED_EN;
+ cloud_menu.unbind = CLOUD_UNBIND_EN;
+ cloud_menu.unbinding = CLOUD_UNBINDED_EN;
+ cloud_menu.disconnected = CLOUD_DISCONNECTED_EN;
+ cloud_menu.unbinded = CLOUD_UNBINDED_EN;
+ cloud_menu.disable = CLOUD_DISABLE_EN;
+ //
+ about_menu.title = TITLE_ABOUT_EN;
+ about_menu.type = ABOUT_TYPE_TEXT_EN;
+ about_menu.version = ABOUT_VERSION_TEXT_EN;
+ about_menu.wifi = ABOUT_WIFI_TEXT_EN;
+ //
+ fan_menu.title = TITLE_FAN_EN;
+ fan_menu.add = FAN_ADD_TEXT_EN;
+ fan_menu.dec = FAN_DEC_TEXT_EN;
+ fan_menu.state = FAN_TIPS1_TEXT_EN;
+ //
+ filament_menu.title = TITLE_FILAMENT_EN;
+ filament_menu.in = FILAMENT_IN_TEXT_EN;
+ filament_menu.out = FILAMENT_OUT_TEXT_EN;
+ filament_menu.ext1 = FILAMENT_EXT0_TEXT_EN;
+ filament_menu.ext2 = FILAMENT_EXT1_TEXT_EN;
+ filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_EN;
+ filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_EN;
+ filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_EN;
+ filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_EN;
+ filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_EN;
+ filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_EN;
+ filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_EN;
+ filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_EN;
+ filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_EN;
+
+ //
+ language_menu.title = TITLE_LANGUAGE_EN;
+ language_menu.next = PAGE_DOWN_TEXT_EN;
+ language_menu.up = PAGE_UP_TEXT_EN;
+ //
+ printing_menu.title = TITLE_PRINTING_EN;
+ printing_menu.option = PRINTING_OPERATION_EN;
+ printing_menu.stop = PRINTING_STOP_EN;
+ printing_menu.pause = PRINTING_PAUSE_EN;
+ printing_menu.resume = PRINTING_RESUME_EN;
+
+ //
+ operation_menu.title = TITLE_OPERATION_EN;
+ operation_menu.pause = PRINTING_PAUSE_EN;
+ operation_menu.stop = PRINTING_STOP_EN;
+ operation_menu.temp = PRINTING_TEMP_EN;
+ operation_menu.fan = FAN_TEXT_EN;
+ operation_menu.extr = PRINTING_EXTRUDER_EN;
+ operation_menu.speed = PRINTING_CHANGESPEED_EN;
+ operation_menu.filament = FILAMENT_TEXT_EN;
+ operation_menu.more = PRINTING_MORE_EN;
+ operation_menu.move = PRINTING_MOVE_EN;
+ operation_menu.auto_off = AUTO_SHUTDOWN_EN;
+ operation_menu.manual_off = MANUAL_SHUTDOWN_EN;
+ //
+ pause_menu.title = TITLE_PAUSE_EN;
+ pause_menu.resume = PRINTING_RESUME_EN;
+ pause_menu.stop = PRINTING_STOP_EN;
+ pause_menu.extrude = PRINTING_EXTRUDER_EN;
+ pause_menu.move = PRINTING_MOVE_EN;
+ pause_menu.filament = FILAMENT_TEXT_EN;
+ pause_menu.more = PRINTING_MORE_EN;
+
+ //
+ speed_menu.title = TITLE_CHANGESPEED_EN;
+ speed_menu.add = ADD_TEXT_EN;
+ speed_menu.dec = DEC_TEXT_EN;
+ speed_menu.move = MOVE_SPEED_EN;
+ speed_menu.extrude = EXTRUDER_SPEED_EN;
+ speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_EN;
+ speed_menu.move_speed = MOVE_SPEED_STATE_EN;
+ //
+ printing_more_menu.title = TITLE_MORE_EN;
+ printing_more_menu.fan = FAN_TEXT_EN;
+ printing_more_menu.auto_close = AUTO_SHUTDOWN_EN;
+ printing_more_menu.manual = MANUAL_SHUTDOWN_EN;
+ printing_more_menu.speed = PRINTING_CHANGESPEED_EN;
+ printing_more_menu.temp = PRINTING_TEMP_EN;
+
+ print_file_dialog_menu.confirm = DIALOG_CONFIRM_EN;
+ print_file_dialog_menu.cancel = DIALOG_CANCLE_EN;
+ print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_EN;
+ print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_EN;
+ print_file_dialog_menu.retry = DIALOG_RETRY_EN;
+ print_file_dialog_menu.stop = DIALOG_STOP_EN;
+ print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_EN;
+ print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_EN;
+ print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_EN;
+ print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_EN;
+ print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_EN;
+ print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_EN;
+ print_file_dialog_menu.reprint = DIALOG_REPRINT_EN;
+ print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_EN;
+ print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_EN;
+
+ pause_msg_menu.pausing = MESSAGE_PAUSING_EN;
+ pause_msg_menu.changing = MESSAGE_CHANGING_EN;
+ pause_msg_menu.unload = MESSAGE_UNLOAD_EN;
+ pause_msg_menu.waiting = MESSAGE_WAITING_EN;
+ pause_msg_menu.insert = MESSAGE_INSERT_EN;
+ pause_msg_menu.load = MESSAGE_LOAD_EN;
+ pause_msg_menu.purge = MESSAGE_PURGE_EN;
+ pause_msg_menu.resume = MESSAGE_RESUME_EN;
+ pause_msg_menu.heat = MESSAGE_HEAT_EN;
+ pause_msg_menu.heating = MESSAGE_HEATING_EN;
+ pause_msg_menu.option = MESSAGE_OPTION_EN;
+ pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_EN;
+ pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_EN;
+ eeprom_menu.title = EEPROM_SETTINGS_TITLE_EN;
+ eeprom_menu.store = EEPROM_SETTINGS_STORE_EN;
+ eeprom_menu.read = EEPROM_SETTINGS_READ_EN;
+ eeprom_menu.revert = EEPROM_SETTINGS_REVERT_EN;
+ eeprom_menu.storeTips = EEPROM_STORE_TIPS_EN;
+ eeprom_menu.readTips = EEPROM_READ_TIPS_EN;
+ eeprom_menu.revertTips = EEPROM_REVERT_TIPS_EN;
+ break;
+ }
+}
+
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h
new file mode 100644
index 0000000..7314da4
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h
@@ -0,0 +1,865 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "tft_Language_en.h"
+#include "tft_Language_s_cn.h"
+#include "tft_Language_t_cn.h"
+#include "tft_Language_ru.h"
+#include "tft_Language_fr.h"
+#include "tft_Language_sp.h"
+#include "tft_Language_it.h"
+
+extern void disp_language_init();
+
+#define LANG_SIMPLE_CHINESE 1
+#define LANG_COMPLEX_CHINESE 2
+#define LANG_ENGLISH 3
+#define LANG_JAPAN 4
+#define LANG_GERMAN 5
+#define LANG_FRENCH 6
+#define LANG_RUSSIAN 7
+#define LANG_KOREAN 8
+#define LANG_TURKISH 9
+#define LANG_SPANISH 10
+#define LANG_GREEK 11
+#define LANG_ITALY 12
+#define LANG_PORTUGUESE 13
+
+#define MULTI_LANGUAGE_ENABLE 1
+#define MULTI_LANGUAGE_DISABLE 0
+
+typedef struct machine_common_disp{
+ const char *default_value;
+
+ const char *next;
+ const char *previous;
+
+ const char *MachineConfigTitle;
+ const char *MachineType;
+ const char *Stroke;
+ const char *HomeDir;
+ const char *EndStopType;
+ const char *FilamentConf;
+
+ const char *MachineTypeConfTitle;
+ const char *xyz;
+ const char *delta;
+ const char *corexy;
+
+ const char *StrokeConfTitle;
+ const char *xStroke;
+ const char *yStroke;
+ const char *zStroke;
+
+ const char *xmin;
+ const char *ymin;
+ const char *zmin;
+
+ const char *HomeDirConfTitle;
+ const char *xHomeDir;
+ const char *yHomeDir;
+ const char *zHomeDir;
+ const char *min;
+ const char *max;
+
+ const char *EndstopConfTitle;
+ const char *xEndstop_min;
+ const char *yEndstop_min;
+ const char *zEndstop_min;
+ const char *xEndstop_max;
+ const char *yEndstop_max;
+ const char *zEndstop_max;
+ const char *FilamentEndstop;
+ const char *LevelingEndstop;
+ const char *opened;
+ const char *closed;
+
+ const char *FilamentConfTitle;
+ const char *InLength;
+ const char *InSpeed;
+ const char *FilamentTemperature;
+ const char *OutLength;
+ const char *OutSpeed;
+
+ const char *LevelingParaConfTitle;
+ const char *LevelingParaConf;
+ const char *LevelingManuPosConf;
+ const char *LevelingAutoCommandConf;
+ const char *LevelingAutoZoffsetConf;
+ const char *LevelingTouchmiConf;
+ const char *TouchmiInit;
+ const char *TouchmiOffsetpos;
+ const char *TouchmiOffsetneg;
+ const char *TouchmiSave;
+ const char *TouchmiTest;
+
+ const char *BLTouchLevelingConfTitle;
+ const char *BLTouchLevelingConf;
+ const char *BLTouchInit;
+ const char *BLTouchOffsetpos;
+ const char *BLTouchOffsetneg;
+ const char *BLTouchSave;
+ const char *BLTouchTest;
+
+ const char *LevelingSubConfTitle;
+ const char *AutoLevelEnable;
+ const char *BLtouchEnable;
+ const char *ProbePort;
+ const char *ProbeXoffset;
+ const char *ProbeYoffset;
+ const char *ProbeZoffset;
+ const char *ProbeXYspeed;
+ const char *ProbeZspeed;
+ const char *enable;
+ const char *disable;
+ const char *locked;
+ const char *z_min;
+ const char *z_max;
+
+ const char *LevelingSubDeltaConfTitle;
+ const char *MachineRadius;
+ const char *DiagonalRod;
+ const char *PrintableRadius;
+ const char *DeltaHeight;
+ const char *SmoothRodOffset;
+ const char *EffectorOffset;
+ const char *CalibrationRadius;
+
+ const char *LevelingSubXYZConfTitle;
+
+ const char *TemperatureConfTitle;
+ const char *NozzleConf;
+ const char *HotBedConf;
+ const char *PreheatTemperConf;
+
+ const char *NozzleCnt;
+ const char *NozzleConfTitle;
+ const char *NozzleType;
+ const char *NozzleAdjustType;
+ const char *NozzleMinTemperature;
+ const char *NozzleMaxTemperature;
+ const char *Extrude_Min_Temper;
+
+ const char *HotbedEnable;
+ const char *HotbedConfTitle;
+ const char *HotbedAjustType;
+ const char *HotbedMinTemperature;
+ const char *HotbedMaxTemperature;
+
+ const char *MotorConfTitle;
+ const char *MaxFeedRateConf;
+ const char *AccelerationConf;
+ const char *JerkConf;
+ const char *StepsConf;
+ const char *MotorDirConf;
+ const char *HomeFeedRateConf;
+ const char *TMCcurrentConf;
+ const char *TMCStepModeConf;
+ const char *HomingSensitivityConf;
+
+ const char *MaxFeedRateConfTitle;
+ const char *XMaxFeedRate;
+ const char *YMaxFeedRate;
+ const char *ZMaxFeedRate;
+ const char *E0MaxFeedRate;
+ const char *E1MaxFeedRate;
+
+ const char *AccelerationConfTitle;
+ const char *PrintAcceleration;
+ const char *RetractAcceleration;
+ const char *TravelAcceleration;
+ const char *X_Acceleration;
+ const char *Y_Acceleration;
+ const char *Z_Acceleration;
+ const char *E0_Acceleration;
+ const char *E1_Acceleration;
+
+ const char *JerkConfTitle;
+ const char *X_Jerk;
+ const char *Y_Jerk;
+ const char *Z_Jerk;
+ const char *E_Jerk;
+
+ const char *StepsConfTitle;
+ const char *X_Steps;
+ const char *Y_Steps;
+ const char *Z_Steps;
+ const char *E0_Steps;
+ const char *E1_Steps;
+
+ const char *TmcCurrentConfTitle;
+ const char *X_Current;
+ const char *Y_Current;
+ const char *Z_Current;
+ const char *E0_Current;
+ const char *E1_Current;
+
+ const char *TmcStepModeConfTitle;
+ const char *X_StepMode;
+ const char *Y_StepMode;
+ const char *Z_StepMode;
+ const char *E0_StepMode;
+ const char *E1_StepMode;
+
+ const char *HomingSensitivityConfTitle;
+ const char *X_Sensitivity;
+ const char *Y_Sensitivity;
+ const char *Z_Sensitivity;
+ const char *Z2_Sensitivity;
+
+ const char *MotorDirConfTitle;
+ const char *X_MotorDir;
+ const char *Y_MotorDir;
+ const char *Z_MotorDir;
+ const char *E0_MotorDir;
+ const char *E1_MotorDir;
+ const char *Invert_1;
+ const char *Invert_0;
+
+ const char *HomeFeedRateConfTitle;
+ const char *XY_HomeFeedRate;
+ const char *Y_HomeFeedRate;
+ const char *Z_HomeFeedRate;
+
+ const char *AdvancedConfTitle;
+ const char *PwrOffDection;
+ const char *PwrOffAfterPrint;
+ const char *HaveUps;
+ const char *Z2andZ2Endstop;
+ const char *EnablePinsInvert;
+ const char *PausePosition;
+ const char *WifiSettings;
+ const char *EncoderSettings;
+
+ const char *Z2ConfTitle;
+ const char *Z2Enable;
+ const char *Z2EndstopEnable;
+ const char *Z2Port;
+
+ const char *EnablePinsInvertTitle;
+ const char *XInvert;
+ const char *YInvert;
+ const char *ZInvert;
+ const char *EInvert;
+
+ const char *key_1;
+ const char *key_2;
+ const char *key_3;
+ const char *key_4;
+ const char *key_5;
+ const char *key_6;
+ const char *key_7;
+ const char *key_8;
+ const char *key_9;
+ const char *key_0;
+ const char *key_point;
+ const char *key_back;
+ const char *key_reset;
+ const char *key_confirm;
+ const char *negative;
+ const char *low_level;
+ const char *high_level;
+
+ const char *PausePosText;
+ const char *xPos;
+ const char *yPos;
+ const char *zPos;
+
+ const char *WifiConfTitle;
+ const char *wifiMode;
+ const char *wifiName;
+ const char *wifiPassWord;
+ const char *wifiCloud;
+ const char *wifiConfig;
+ const char *wifiEdit;
+ const char *wifiConfigTips;
+
+ const char *OffsetConfTitle;
+ const char *Xoffset;
+ const char *Yoffset;
+ const char *Zoffset;
+
+ const char *EncoderConfTitle;
+ const char *EncoderConfText;
+
+} machine_common_def;
+
+extern machine_common_def machine_menu;
+
+typedef struct common_menu_disp {
+ const char *text_back;
+ const char *dialog_confirm_title;
+ const char *close_machine_tips;
+ const char *unbind_printer_tips;
+ const char *print_special_title;
+ const char *pause_special_title;
+ const char *operate_special_title;
+ const char *next;
+ const char *previous;
+} common_menu_def;
+
+extern common_menu_def common_menu;
+
+typedef struct main_menu_disp {
+ const char *title;
+ const char *preheat;
+ const char *move;
+ const char *home;
+ const char *print;
+ const char *extrude;
+ const char *leveling;
+ const char *autoleveling;
+ const char *fan;
+ const char *set;
+ const char *tool;
+ const char *more;
+ const char *machine_para;
+} main_menu_def;
+
+extern main_menu_def main_menu;
+
+typedef struct preheat_menu_disp {
+ const char *adjust_title;
+ const char *title;
+ const char *add;
+ const char *dec;
+ const char *ext1;
+ const char *ext2;
+ const char *hotbed;
+ const char *off;
+ const char *step_1c;
+ const char *step_5c;
+ const char *step_10c;
+ const char *back;
+
+ const char *value_state;
+
+ const char *dialog_tips;
+
+} preheat_menu_def;
+
+extern preheat_menu_def preheat_menu;
+
+typedef struct move_menu_disp {
+ const char *title;
+ const char *x_add;
+ const char *x_dec;
+ const char *y_add;
+ const char *y_dec;
+ const char *z_add;
+ const char *z_dec;
+ const char *step_001mm;
+ const char *step_005mm;
+ const char *step_01mm;
+ const char *step_1mm;
+ const char *step_10mm;
+ const char *back;
+} move_menu_def;
+
+extern move_menu_def move_menu;
+
+typedef struct home_menu_disp {
+ const char *title;
+ const char *home_all;
+ const char *home_x;
+ const char *home_y;
+ const char *home_z;
+ const char *stopmove;
+ const char *back;
+} home_menu_def;
+
+extern home_menu_def home_menu;
+
+typedef struct touchmi_menu_disp {
+ const char *title;
+ const char *init;
+ const char *zoffsetpos;
+ const char *zoffsetneg;
+ const char *test;
+ const char *save;
+} touchmi_menu_def;
+
+extern touchmi_menu_def touchmi_menu;
+
+typedef struct file_menu_disp {
+ const char *title;
+ const char *page_up;
+ const char *page_down;
+ const char *back;
+
+ const char *file_loading;
+ const char *no_file;
+ const char *no_file_and_check;
+
+} file_menu_def;
+
+extern file_menu_def file_menu;
+
+typedef struct extrude_menu_disp {
+ const char *title;
+ const char *in;
+ const char *out;
+ const char *ext1;
+ const char *ext2;
+ const char *step_1mm;
+ const char *step_5mm;
+ const char *step_10mm;
+ const char *low;
+ const char *normal;
+ const char *high;
+ const char *back;
+
+ const char *count_value_mm;
+ const char *count_value_cm;
+ const char *count_value_m;
+ const char *temp_value;
+ const char *temper_text;
+} extrude_menu_def;
+
+extern extrude_menu_def extrude_menu;
+
+typedef struct leveling_menu_disp {
+ const char *title;
+ const char *position1;
+ const char *position2;
+ const char *position3;
+ const char *position4;
+ const char *position5;
+
+ char *back;
+} leveling_menu_def;
+
+extern leveling_menu_def leveling_menu;
+
+typedef struct set_menu_disp {
+ const char *title;
+ const char *filesys;
+ const char *wifi;
+ const char *about;
+ const char *fan;
+ const char *filament;
+ const char *breakpoint;
+ const char *motoroff;
+ const char *motoroffXY;
+ const char *shutdown;
+ const char *language;
+ const char *machine_para;
+ const char *eepromSet;
+ const char *back;
+} set_menu_def;
+
+extern set_menu_def set_menu;
+
+typedef struct filesys_menu_disp {
+ const char *title;
+ const char *filesys;
+ const char *sd_sys;
+ const char *usb_sys;
+ const char *back;
+} filesys_menu_def;
+
+extern filesys_menu_def filesys_menu;
+
+typedef struct more_menu_disp {
+ const char *title;
+ const char *custom1;
+ const char *custom2;
+ const char *custom3;
+ const char *custom4;
+ const char *custom5;
+ const char *custom6;
+ const char *custom7;
+ const char *back;
+} more_menu_def;
+
+extern more_menu_def more_menu;
+
+typedef struct wifi_menu_disp {
+ const char *title;
+ const char *ip;
+ const char *wifi;
+ const char *key;
+ const char *state_ap;
+ const char *state_sta;
+ const char *cloud;
+ const char *connected;
+ const char *disconnected;
+ const char *exception;
+ const char *back;
+ const char *reconnect;
+} wifi_menu_def;
+
+extern wifi_menu_def wifi_menu;
+
+typedef struct cloud_menu_disp {
+ const char *title;
+ const char *unbind;
+ const char *unbinding;
+ const char *unbinded;
+ const char *bind;
+ const char *binding;
+ const char *binded;
+ const char *disable;
+ const char *disconnected;
+ const char *back;
+ const char *unbind_printer_tips;
+} cloud_menu_def;
+
+extern cloud_menu_def cloud_menu;
+
+typedef struct about_menu_disp {
+ const char *title;
+ const char *type_name;
+ const char *firmware_v;
+ const char *type;
+ const char *version;
+ const char *wifi;
+ const char *type_robin;
+ const char *type_robin_mini;
+ const char *back;
+} about_menu_def;
+
+extern about_menu_def about_menu;
+
+typedef struct fan_menu_disp {
+ const char *title;
+ const char *add;
+ const char *dec;
+ const char *full;
+ const char *half;
+ const char *off;
+ const char *back;
+
+ const char *state;
+ const char *state_value;
+} fan_menu_def;
+
+extern fan_menu_def fan_menu;
+
+typedef struct filament_menu_disp {
+ const char *title;
+ const char *in;
+ const char *out;
+ const char *ext1;
+ const char *ext2;
+ const char *back;
+ const char *stat_temp;
+ const char *ready_replace;
+ const char *replacing;
+ const char *loading;
+ const char *unloading;
+ const char *heating;
+ const char *complete_and_back;
+ const char *filament_dialog_load_heat;
+ const char *filament_dialog_unload_heat;
+ const char *filament_dialog_load_heat_confirm;
+ const char *filament_dialog_unload_heat_confirm;
+ const char *filament_dialog_loading;
+ const char *filament_dialog_unloading;
+ const char *filament_dialog_load_completed;
+ const char *filament_dialog_unload_completed;
+ const char *filament_dialog_ok;
+ const char *filament_dialog_back;
+} filament_menu_def;
+
+extern filament_menu_def filament_menu;
+
+typedef struct language_menu {
+ const char *title;
+ const char *chinese_s;
+ const char *chinese_t;
+ const char *english;
+ const char *russian;
+ const char *japan;
+ const char *italy;
+ const char *german;
+ const char *spanish;
+ const char *korean;
+ const char *french;
+ const char *brazil;
+ const char *portuguese;
+ const char *next;
+ const char *up;
+ const char *back;
+} language_menu_def;
+
+extern language_menu_def language_menu;
+
+typedef struct printing_menu_disp {
+ const char *title;
+ const char *option;
+ const char *temp1;
+ const char *temp2;
+ const char *bed_temp;
+ const char *fan_speed;
+ const char *pause;
+ const char *resume;
+ const char *stop;
+} printing_menu_def;
+
+extern printing_menu_def printing_menu;
+
+typedef struct operation_menu_disp {
+ const char *title;
+ const char *pause;
+ const char *stop;
+ const char *temp;
+ const char *fan;
+ const char *filament;
+ const char *extr;
+ const char *speed;
+ const char *move;
+ const char *more;
+ const char *auto_off;
+ const char *manual_off;
+ const char *back;
+ const char *babystep;
+} operation_menu_def;
+
+extern operation_menu_def operation_menu;
+
+typedef struct pause_menu_disp {
+ const char *title;
+ const char *resume;
+ const char *stop;
+ const char *extrude;
+ const char *move;
+ const char *filament;
+ const char *more;
+} pause_menu_def;
+
+extern pause_menu_def pause_menu;
+
+typedef struct speed_menu_disp {
+ const char *title;
+ const char *add;
+ const char *dec;
+ const char *extrude;
+ const char *move;
+ const char *step_1percent;
+ const char *step_5percent;
+ const char *step_10percent;
+ const char *back;
+ const char *move_speed;
+ const char *extrude_speed;
+} speed_menu_def;
+
+extern speed_menu_def speed_menu;
+
+typedef struct printing_more_menu_disp {
+ const char *title;
+ const char *fan;
+ const char *auto_close;
+ const char *manual;
+ const char *temp;
+ const char *speed;
+ const char *back;
+} printing_more_menu_def;
+
+extern printing_more_menu_def printing_more_menu;
+
+typedef struct dialog_menu_disp {
+ const char *confirm_title;
+
+ const char *error1_repint_no_file;
+ const char *error2_communication_fail;
+ const char *error3_filename_too_long;
+ const char *error4_no_file;
+ const char *error5_check_filesys;
+
+ const char *tip1_print_file;
+ const char *tip2_stop_file;
+} dialog_menu_def;
+
+extern dialog_menu_def dialog_menu;
+
+typedef struct print_file_dialog_disp {
+ const char *title;
+ const char *confirm;
+ const char *cancel;
+ const char *print_file;
+ const char *cancel_print;
+ const char *retry;
+ const char *stop;
+ const char *no_file_print_tips;
+ const char *print_from_breakpoint;
+ const char *file_name_too_long_error;
+ const char *close_machine_error;
+ const char *filament_no_press;
+ const char *print_finish;
+ const char *print_time;
+ const char *reprint;
+ const char *wifi_enable_tips;
+ const char *machinePausingTips;
+} print_file_dialog_menu_def;
+
+extern print_file_dialog_menu_def print_file_dialog_menu;
+
+typedef struct tool_menu_disp {
+ const char *title;
+ const char *preheat;
+ const char *extrude;
+ const char *move;
+ const char *home;
+ const char *leveling;
+ const char *autoleveling;
+ const char *filament;
+ const char *more;
+ const char *back;
+} tool_menu_def;
+
+extern tool_menu_def tool_menu;
+
+typedef struct MachinePara_menu_disp {
+ const char *title;
+ const char *MachineSetting;
+ const char *MotorSetting;
+ const char *leveling;
+ const char *AdvanceSetting;
+} MachinePara_menu_def;
+
+extern MachinePara_menu_def MachinePara_menu;
+
+typedef struct pause_msg_disp {
+ const char *pausing;
+ const char *changing;
+ const char *unload;
+ const char *waiting;
+ const char *insert;
+ const char *load;
+ const char *purge;
+ const char *resume;
+ const char *heat;
+ const char *heating;
+ const char *option;
+ const char *purgeMore;
+ const char *continuePrint;
+} pause_msg_def;
+
+extern pause_msg_def pause_msg_menu;
+
+typedef struct eeprom_disp{
+ const char *title;
+ const char *store;
+ const char *read;
+ const char *revert;
+ const char *storeTips;
+ const char *readTips;
+ const char *revertTips;
+} eeprom_def;
+
+extern eeprom_def eeprom_menu;
+/*****************************************/
+//
+#define TEXT_VALUE "%d/%d"
+
+#define TEXT_VALUE_T ": %d℃"
+#define TEXT_VALUE_mm ": %dmm"
+#define TEXT_VALUE_cm ": %dcm"
+#define TEXT_VALUE_m ": %dm"
+
+#define TEMP_UNIT_SYBOL "%d℃"
+#define FLOAT_TEMP_UNIT_SYBOL "%.1f℃"
+
+#define TEXT_1C "1℃"
+#define TEXT_5C "5℃"
+#define TEXT_10C "10℃"
+
+#define AXIS_X_ADD_TEXT "X+"
+#define AXIS_X_DEC_TEXT "X-"
+#define AXIS_Y_ADD_TEXT "Y+"
+#define AXIS_Y_DEC_TEXT "Y-"
+#define AXIS_Z_ADD_TEXT "Z+"
+#define AXIS_Z_DEC_TEXT "Z-"
+#define TEXT_001MM "0.01 mm"
+#define TEXT_005MM "0.05 mm"
+#define TEXT_01MM "0.1 mm"
+#define TEXT_1MM "1 mm"
+#define TEXT_10MM "10 mm"
+
+#define EXTRUDE_1MM_TEXT "1 mm"
+#define EXTRUDE_5MM_TEXT "5 mm"
+#define EXTRUDE_10MM_TEXT "10 mm"
+
+#define STEP_1PERCENT "1%"
+#define STEP_5PERCENT "5%"
+#define STEP_10PERCENT "10%"
+
+#define LANGUAGE_S_CN "简体"
+#define LANGUAGE_T_CN "繁体"
+#define LANGUAGE_EN "English"
+#define LANGUAGE_JP "日本語"
+#define LANGUAGE_GE "Deutsch"
+#define LANGUAGE_FR "français"
+#define LANGUAGE_IT "Italiano"
+#define LANGUAGE_PR "português"
+#define LANGUAGE_KR "Korean"
+#define LANGUAGE_BR "Brazil"
+#define LANGUAGE_RU "русский"
+#define LANGUAGE_SP "español"
+
+#define HOME_X_TEXT "X"
+#define HOME_Y_TEXT "Y"
+#define HOME_Z_TEXT "Z"
+#define HOME_ALL_TEXT "All"
+
+#define TM_INIT "Init"
+#define TM_ZOFFSETPOS "Offset +"
+#define TM_ZOFFSETNEG "Offset -"
+#define TM_SAVE "Save"
+#define TM_TEST "Test"
+
+//#if defined(MKS_ROBIN_NANO)
+#define ABOUT_TYPE_TEXT "MKS Robin Pro"
+
+#define ABOUT_VERSION_TEXT "1.0.0"
+
+#define FAN_OPEN_TEXT "100%"
+#define FAN_HALF_TEXT "50%"
+#define FAN_CLOSE_TEXT "0%"
+
+#define WIFI_TEXT "WIFI"
+#define WIFI_IP_TEXT "IP: "
+#define WIFI_NAME_TEXT "WiFi: "
+#define WIFI_KEY_TEXT "Key: "
+#define WIFI_STATE_AP_TEXT "State: AP"
+#define WIFI_STATE_STA_TEXT "State: STA"
+#define WIFI_CONNECTED_TEXT "Connected"
+#define WIFI_DISCONNECTED_TEXT "Disconnected"
+#define WIFI_EXCEPTION_TEXT "Exception"
+
+#define FILAMENT_TIPS2_TEXT "T:"
+
+#define DIALOG_UPLOAD_ING_EN "Uploading......"
+#define DIALOG_UPLOAD_ERROR_EN "Upload error"
+#define DIALOG_UPLOAD_FINISH_EN "Upload finished"
+#define DIALOG_UPLOAD_SIZE_EN "Size"
+#define DIALOG_UPLOAD_TIME_EN "Time"
+#define DIALOG_UPLOAD_SPEED_EN "Speed"
+#define DIALOG_UPDATE_WIFI_FIRMWARE_EN "Updating wifi model firmware"
+#define DIALOG_UPDATE_WIFI_WEB_EN "Updating wifi model web data"
+#define DIALOG_UPDATE_NO_DEVICE_EN "Please check\nwether memory device insert!"
+
+#define ZOFFSET_STEP001 "0.01 mm"
+#define ZOFFSET_STEP01 "0.1 mm"
+#define ZOFFSET_STEP1 "1 mm"
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.cpp
new file mode 100644
index 0000000..d10d10e
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.cpp
@@ -0,0 +1,526 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "tft_lvgl_configuration.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+#include "draw_ui.h"
+#include "wifiSerial.h"
+
+#ifdef __STM32F1__
+
+ #include <libmaple/libmaple.h>
+ #include <libmaple/gpio.h>
+ #include <libmaple/timer.h>
+ #include <libmaple/usart.h>
+ #include <libmaple/ring_buffer.h>
+
+ #include "../../../../MarlinCore.h"
+
+ DEFINE_WFSERIAL(WifiSerial1, 1);
+
+ WifiSerial::WifiSerial(usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) {
+ this->usart_device = usart_device;
+ this->tx_pin = tx_pin;
+ this->rx_pin = rx_pin;
+ }
+
+ /**
+ * Set up / tear down
+ */
+ #if STM32_MCU_SERIES == STM32_SERIES_F1
+ /* F1 MCUs have no GPIO_AFR[HL], so turn off PWM if there's a conflict
+ * on this GPIO bit. */
+ static void disable_timer_if_necessary(timer_dev *dev, uint8 ch) {
+ if (dev) timer_set_mode(dev, ch, TIMER_DISABLED);
+ }
+ static void usart_enable_no_irq(usart_dev *usart_device, bool with_irq) {
+ if (with_irq) usart_enable(usart_device);
+ else {
+ usart_reg_map *regs = usart_device->regs;
+ regs->CR1 |= (USART_CR1_TE | USART_CR1_RE);// don't change the word length etc, and 'or' in the patten not overwrite |USART_CR1_M_8N1);
+ regs->CR1 |= USART_CR1_UE;
+ }
+ }
+
+ #elif STM32_MCU_SERIES == STM32_SERIES_F2 || STM32_MCU_SERIES == STM32_SERIES_F4
+ #define disable_timer_if_necessary(dev, ch) ((void)0)
+
+ static void usart_enable_no_irq(usart_dev *usart_device, bool with_irq) {
+ if (with_irq) usart_enable(usart_device);
+ else {
+ usart_reg_map *regs = usart_device->regs;
+ regs->CR1 |= (USART_CR1_TE | USART_CR1_RE);// don't change the word length etc, and 'or' in the patten not overwrite |USART_CR1_M_8N1);
+ regs->CR1 |= USART_CR1_UE;
+ }
+ }
+ #else
+ #warning "Unsupported STM32 series; timer conflicts are possible"
+ #define usart_enable_no_irq(X, Y) usart_enable(X)
+ #endif
+
+ void WifiSerial::begin(uint32 baud) { begin(baud, SERIAL_8N1); }
+
+ /**
+ * Roger Clark.
+ * Note. The config parameter is not currently used. This is a work in progress.
+ * Code needs to be written to set the config of the hardware serial control register in question.
+ */
+
+ void WifiSerial::begin(uint32 baud, uint8_t config) {
+ //ASSERT(baud <= this->usart_device->max_baud); // Roger Clark. Assert doesn't do anything useful, we may as well save the space in flash and ram etc
+
+ if (baud > this->usart_device->max_baud) return;
+
+ const stm32_pin_info *txi = &PIN_MAP[this->tx_pin],
+ *rxi = &PIN_MAP[this->rx_pin];
+
+ disable_timer_if_necessary(txi->timer_device, txi->timer_channel);
+
+ usart_init(this->usart_device);
+
+ // Reinitialize the receive buffer, mks_esp8266 fixed data frame length is 1k bytes
+ rb_init(this->usart_device->rb, WIFI_RX_BUF_SIZE, wifiRxBuf);
+
+ usart_config_gpios_async(this->usart_device,
+ rxi->gpio_device, rxi->gpio_bit,
+ txi->gpio_device, txi->gpio_bit,
+ config);
+ usart_set_baud_rate(this->usart_device, USART_USE_PCLK, baud);
+ usart_enable_no_irq(this->usart_device, baud == WIFI_BAUDRATE);
+ }
+
+ void WifiSerial::end(void) {
+ usart_disable(this->usart_device);
+ }
+
+ int WifiSerial::available(void) {
+ return usart_data_available(this->usart_device);
+ }
+
+ //
+ // I/O
+ //
+
+ int WifiSerial::read(void) {
+ if (usart_data_available(usart_device) <= 0) return -1;
+ return usart_getc(usart_device);
+ }
+
+ int WifiSerial::write(unsigned char ch) {
+ usart_putc(this->usart_device, ch);
+ return 1;
+ }
+
+ int WifiSerial::wifi_rb_is_full(void) {
+ return rb_is_full(this->usart_device->rb);
+ }
+
+#else
+
+ WifiSerial WifiSerial1(USART1);
+
+ void WifiSerial::setRx(uint32_t _rx)
+ {
+ _serial.pin_rx = digitalPinToPinName(_rx);
+ }
+
+ void WifiSerial::setTx(uint32_t _tx)
+ {
+ _serial.pin_tx = digitalPinToPinName(_tx);
+ }
+
+ void WifiSerial::setRx(PinName _rx)
+ {
+ _serial.pin_rx = _rx;
+ }
+
+ void WifiSerial::setTx(PinName _tx)
+ {
+ _serial.pin_tx = _tx;
+ }
+
+ void WifiSerial::init(PinName _rx, PinName _tx)
+ {
+ if (_rx == _tx) {
+ _serial.pin_rx = NC;
+ } else {
+ _serial.pin_rx = _rx;
+ }
+ _serial.pin_tx = _tx;
+ _serial.rx_buff = wifiRxBuf;
+ _serial.rx_head = 0;
+ _serial.rx_tail = 0;
+ _serial.tx_buff = wifiTxBuf;
+ _serial.tx_head = 0;
+ _serial.tx_tail = 0;
+ }
+
+ WifiSerial::WifiSerial(void *peripheral)
+ {
+ // If PIN_SERIALy_RX is not defined assume half-duplex
+ _serial.pin_rx = NC;
+ // If Serial is defined in variant set
+ // the Rx/Tx pins for com port if defined
+ #if defined(Serial) && defined(PIN_SERIAL_TX)
+ if ((void *)this == (void *)&Serial) {
+ #if defined(PIN_SERIAL_RX)
+ setRx(PIN_SERIAL_RX);
+ #endif
+ setTx(PIN_SERIAL_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL1_TX) && defined(USART1_BASE)
+ if (peripheral == USART1) {
+ #if defined(PIN_SERIAL1_RX)
+ setRx(PIN_SERIAL1_RX);
+ #endif
+ setTx(PIN_SERIAL1_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL2_TX) && defined(USART2_BASE)
+ if (peripheral == USART2) {
+ #if defined(PIN_SERIAL2_RX)
+ setRx(PIN_SERIAL2_RX);
+ #endif
+ setTx(PIN_SERIAL2_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL3_TX) && defined(USART3_BASE)
+ if (peripheral == USART3) {
+ #if defined(PIN_SERIAL3_RX)
+ setRx(PIN_SERIAL3_RX);
+ #endif
+ setTx(PIN_SERIAL3_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL4_TX) &&\
+ (defined(USART4_BASE) || defined(UART4_BASE))
+ #if defined(USART4_BASE)
+ if (peripheral == USART4)
+ #elif defined(UART4_BASE)
+ if (peripheral == UART4)
+ #endif
+ {
+ #if defined(PIN_SERIAL4_RX)
+ setRx(PIN_SERIAL4_RX);
+ #endif
+ setTx(PIN_SERIAL4_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL5_TX) &&\
+ (defined(USART5_BASE) || defined(UART5_BASE))
+ #if defined(USART5_BASE)
+ if (peripheral == USART5)
+ #elif defined(UART5_BASE)
+ if (peripheral == UART5)
+ #endif
+ {
+ #if defined(PIN_SERIAL5_RX)
+ setRx(PIN_SERIAL5_RX);
+ #endif
+ setTx(PIN_SERIAL5_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL6_TX) && defined(USART6_BASE)
+ if (peripheral == USART6) {
+ #if defined(PIN_SERIAL6_RX)
+ setRx(PIN_SERIAL6_RX);
+ #endif
+ setTx(PIN_SERIAL6_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL7_TX) &&\
+ (defined(USART7_BASE) || defined(UART7_BASE))
+ #if defined(USART7_BASE)
+ if (peripheral == USART7)
+ #elif defined(UART7_BASE)
+ if (peripheral == UART7)
+ #endif
+ {
+ #if defined(PIN_SERIAL7_RX)
+ setRx(PIN_SERIAL7_RX);
+ #endif
+ setTx(PIN_SERIAL7_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL8_TX) &&\
+ (defined(USART8_BASE) || defined(UART8_BASE))
+ #if defined(USART8_BASE)
+ if (peripheral == USART8)
+ #elif defined(UART8_BASE)
+ if (peripheral == UART8)
+ #endif
+ {
+ #if defined(PIN_SERIAL8_RX)
+ setRx(PIN_SERIAL8_RX);
+ #endif
+ setTx(PIN_SERIAL8_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL9_TX) && defined(UART9_BASE)
+ if (peripheral == UART9) {
+ #if defined(PIN_SERIAL9_RX)
+ setRx(PIN_SERIAL9_RX);
+ #endif
+ setTx(PIN_SERIAL9_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIAL10_TX) &&\
+ (defined(USART10_BASE) || defined(UART10_BASE))
+ #if defined(USART10_BASE)
+ if (peripheral == USART10)
+ #elif defined(UART10_BASE)
+ if (peripheral == UART10)
+ #endif
+ {
+ #if defined(PIN_SERIAL10_RX)
+ setRx(PIN_SERIAL10_RX);
+ #endif
+ setTx(PIN_SERIAL10_TX);
+ } else
+ #endif
+ #if defined(PIN_SERIALLP1_TX) && defined(LPUART1_BASE)
+ if (peripheral == LPUART1) {
+ #if defined(PIN_SERIALLP1_RX)
+ setRx(PIN_SERIALLP1_RX);
+ #endif
+ setTx(PIN_SERIALLP1_TX);
+ } else
+ #endif
+ // else get the pins of the first peripheral occurence in PinMap
+ {
+ _serial.pin_rx = pinmap_pin(peripheral, PinMap_UART_RX);
+ _serial.pin_tx = pinmap_pin(peripheral, PinMap_UART_TX);
+ }
+ // if (halfDuplex == HALF_DUPLEX_ENABLED) {
+ // _serial.pin_rx = NC;
+ // }
+ init(_serial.pin_rx, _serial.pin_tx);
+ }
+
+ void WifiSerial::flush()
+ {
+ // If we have never written a byte, no need to flush. This special
+ // case is needed since there is no way to force the TXC (transmit
+ // complete) bit to 1 during initialization
+ if (!_written) {
+ return;
+ }
+
+ while ((_serial.tx_head != _serial.tx_tail)) {
+ // nop, the interrupt handler will free up space for us
+ }
+ // If we get here, nothing is queued anymore (DRIE is disabled) and
+ // the hardware finished tranmission (TXC is set).
+ }
+
+ bool WifiSerial::isHalfDuplex(void) const
+ {
+ return _serial.pin_rx == NC;
+ }
+
+ void WifiSerial::enableHalfDuplexRx(void)
+ {
+ if (isHalfDuplex()) {
+ // In half-duplex mode we have to wait for all TX characters to
+ // be transmitted before we can receive data.
+ flush();
+ if (!_rx_enabled) {
+ _rx_enabled = true;
+ uart_enable_rx(&_serial);
+ }
+ }
+ }
+
+ // Actual interrupt handlers //////////////////////////////////////////////////////////////
+
+ void WifiSerial::_rx_complete_irq(serial_t *obj)
+ {
+ // No Parity error, read byte and store it in the buffer if there is room
+ unsigned char c;
+
+ if (uart_getc(obj, &c) == 0) {
+
+ WRITE(WIFI_IO1_PIN, HIGH);
+
+ rx_buffer_index_t i = (unsigned int)(obj->rx_head + 1) % WIFI_RX_BUF_SIZE;
+
+ // if we should be storing the received character into the location
+ // just before the tail (meaning that the head would advance to the
+ // current location of the tail), we're about to overflow the buffer
+ // and so we don't write the character or advance the head.
+ if (i != obj->rx_tail) {
+ obj->rx_buff[obj->rx_head] = c;
+ obj->rx_head = i;
+ }
+ }
+ }
+
+ // Actual interrupt handlers //////////////////////////////////////////////////////////////
+
+ int WifiSerial::_tx_complete_irq(serial_t *obj)
+ {
+ // If interrupts are enabled, there must be more data in the output
+ // buffer. Send the next byte
+ obj->tx_tail = (obj->tx_tail + 1) % WIFI_TX_BUF_SIZE;
+
+ if (obj->tx_head == obj->tx_tail) {
+ return -1;
+ }
+
+ return 0;
+ }
+
+ void WifiSerial::begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
+
+ void WifiSerial::begin(unsigned long baud, byte config) {
+ uint32_t databits = 0;
+ uint32_t stopbits = 0;
+ uint32_t parity = 0;
+
+ _baud = baud;
+ _config = config;
+
+ // Manage databits
+ switch (config & 0x07) {
+ case 0x02:
+ databits = 6;
+ break;
+ case 0x04:
+ databits = 7;
+ break;
+ case 0x06:
+ databits = 8;
+ break;
+ default:
+ databits = 0;
+ break;
+ }
+
+ if ((config & 0x30) == 0x30) {
+ parity = UART_PARITY_ODD;
+ databits++;
+ } else if ((config & 0x20) == 0x20) {
+ parity = UART_PARITY_EVEN;
+ databits++;
+ } else {
+ parity = UART_PARITY_NONE;
+ }
+
+ if ((config & 0x08) == 0x08) {
+ stopbits = UART_STOPBITS_2;
+ } else {
+ stopbits = UART_STOPBITS_1;
+ }
+
+ switch (databits) {
+ #ifdef UART_WORDLENGTH_7B
+ case 7:
+ databits = UART_WORDLENGTH_7B;
+ break;
+ #endif
+ case 8:
+ databits = UART_WORDLENGTH_8B;
+ break;
+ case 9:
+ databits = UART_WORDLENGTH_9B;
+ break;
+ default:
+ case 0:
+ Error_Handler();
+ break;
+ }
+
+ uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits);
+ enableHalfDuplexRx();
+ if (baud == WIFI_BAUDRATE) uart_attach_rx_callback(&_serial, _rx_complete_irq);
+ else {
+ USART1->CR1 |= (USART_CR1_RE);// don't change the word length etc, and 'or' in the patten not overwrite |USART_CR1_M_8N1);
+ }
+ }
+
+ void WifiSerial::end(void)
+ {
+ // wait for transmission of outgoing data
+ flush();
+
+ uart_deinit(&_serial);
+
+ // clear any received data
+ _serial.rx_head = _serial.rx_tail;
+ }
+
+ int WifiSerial::available(void) {
+ return ((unsigned int)(WIFI_RX_BUF_SIZE + _serial.rx_head - _serial.rx_tail)) % WIFI_RX_BUF_SIZE;
+ }
+
+ //
+ // I/O
+ //
+ int WifiSerial::read(void)
+ {
+ enableHalfDuplexRx();
+ // if the head isn't ahead of the tail, we don't have any characters
+ if (_serial.rx_head == _serial.rx_tail) {
+ return -1;
+ } else {
+ unsigned char c = _serial.rx_buff[_serial.rx_tail];
+ _serial.rx_tail = (rx_buffer_index_t)(_serial.rx_tail + 1) % WIFI_RX_BUF_SIZE;
+ return c;
+ }
+ }
+
+ int WifiSerial::write(uint8_t c)
+ {
+ _written = true;
+ if (isHalfDuplex()) {
+ if (_rx_enabled) {
+ _rx_enabled = false;
+ uart_enable_tx(&_serial);
+ }
+ }
+
+ tx_buffer_index_t i = (_serial.tx_head + 1) % WIFI_TX_BUF_SIZE;
+
+ // If the output buffer is full, there's nothing for it other than to
+ // wait for the interrupt handler to empty it a bit
+ while (i == _serial.tx_tail) {
+ // nop, the interrupt handler will free up space for us
+ }
+
+ _serial.tx_buff[_serial.tx_head] = c;
+ _serial.tx_head = i;
+
+ if (!serial_tx_active(&_serial)) {
+ uart_attach_tx_callback(&_serial, _tx_complete_irq);
+ }
+
+ return 1;
+ }
+#endif // __STM32F1__
+#endif // MKS_WIFI_MODULE
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h
new file mode 100644
index 0000000..cd11d6b
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h
@@ -0,0 +1,145 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "tft_lvgl_configuration.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+#ifdef SERIAL_PORT_2
+ #error "SERIAL_PORT_2 must be disabled with TFT_LVGL_UI* and MKS_WIFI_MODULE."
+#endif
+
+#define WIFI_BAUDRATE 115200
+#define WIFI_UPLOAD_BAUDRATE 1958400
+#define USART_SAFE_INSERT
+
+#define WIFI_RX_BUF_SIZE (1024)
+#define WIFI_TX_BUF_SIZE (64)
+
+#ifdef __STM32F1__
+
+ #include <libmaple/libmaple_types.h>
+ #include <libmaple/usart.h>
+ #include <libmaple/libmaple.h>
+ #include <libmaple/gpio.h>
+ #include <libmaple/timer.h>
+ #include <libmaple/ring_buffer.h>
+
+ #define DEFINE_WFSERIAL(name, n)\
+ WifiSerial name(USART##n, \
+ BOARD_USART##n##_TX_PIN, \
+ BOARD_USART##n##_RX_PIN)
+
+ class WifiSerial {
+ public:
+ uint8 wifiRxBuf[WIFI_RX_BUF_SIZE];
+
+ public:
+ WifiSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin);
+
+ /* Set up/tear down */
+ void begin(uint32 baud);
+ void begin(uint32 baud,uint8_t config);
+ void end();
+ int available(void);
+ int read(void);
+ int write(uint8_t);
+ inline void wifi_usart_irq(usart_reg_map *regs) {
+ /* Handling RXNEIE and TXEIE interrupts.
+ * RXNE signifies availability of a byte in DR.
+ *
+ * See table 198 (sec 27.4, p809) in STM document RM0008 rev 15.
+ * We enable RXNEIE.
+ */
+ if ((regs->CR1 & USART_CR1_RXNEIE) && (regs->SR & USART_SR_RXNE)) {
+ #ifdef USART_SAFE_INSERT
+ /* If the buffer is full and the user defines USART_SAFE_INSERT,
+ * ignore new bytes. */
+ rb_safe_insert(this->usart_device->rb, (uint8)regs->DR);
+ #else
+ /* By default, push bytes around in the ring buffer. */
+ rb_push_insert(this->usart_device->rb, (uint8)regs->DR);
+ #endif
+ }
+ /* TXE signifies readiness to send a byte to DR. */
+ if ((regs->CR1 & USART_CR1_TXEIE) && (regs->SR & USART_SR_TXE)) {
+ if (!rb_is_empty(this->usart_device->wb))
+ regs->DR=rb_remove(this->usart_device->wb);
+ else
+ regs->CR1 &= ~((uint32)USART_CR1_TXEIE); // disable TXEIE
+ }
+ }
+ int wifi_rb_is_full(void);
+ struct usart_dev *usart_device;
+ private:
+ uint8 tx_pin;
+ uint8 rx_pin;
+ };
+ extern WifiSerial WifiSerial1;
+ #define WIFISERIAL WifiSerial1
+#else
+
+ #include <inttypes.h>
+ #include "Stream.h"
+ #include "uart.h"
+
+ class WifiSerial {
+ protected:
+ // Has any byte been written to the UART since begin()
+ bool _written;
+ serial_t _serial;
+ public:
+ uint8_t wifiRxBuf[WIFI_RX_BUF_SIZE];
+ uint8_t wifiTxBuf[WIFI_TX_BUF_SIZE];
+ WifiSerial(void *peripheral);
+
+ /* Set up/tear down */
+ void begin(uint32_t baud);
+ void begin(uint32_t baud,uint8_t config);
+ void end();
+ int available(void);
+ int read(void);
+ int write(uint8_t);
+
+ // Interrupt handlers
+ static int _tx_complete_irq(serial_t *obj);
+ static void _rx_complete_irq(serial_t *obj);
+
+ void flush(void);
+ bool isHalfDuplex(void) const;
+ void enableHalfDuplexRx(void);
+
+ private:
+ void setRx(uint32_t _rx);
+ void setTx(uint32_t _tx);
+ void setRx(PinName _rx);
+ void setTx(PinName _tx);
+ void init(PinName _rx, PinName _tx);
+ bool _rx_enabled;
+ uint8_t _config;
+ unsigned long _baud;
+ };
+ extern WifiSerial WifiSerial1;
+ #define WIFISERIAL WifiSerial1
+#endif // __STM32F1__
+#endif // MKS_WIFI_MODULE
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp
new file mode 100644
index 0000000..0e4163c
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp
@@ -0,0 +1,2231 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if HAS_TFT_LVGL_UI
+
+#include "draw_ui.h"
+#include "wifi_module.h"
+#include "wifi_upload.h"
+#include "SPI_TFT.h"
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+#include "../../../../MarlinCore.h"
+#include "../../../../module/temperature.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../gcode/gcode.h"
+#include "../../../../lcd/marlinui.h"
+#include "../../../../sd/cardreader.h"
+#include "../../../../module/planner.h"
+#include "../../../../module/servo.h"
+#include "../../../../module/probe.h"
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+#if ENABLED(PARK_HEAD_ON_PAUSE)
+ #include "../../../../feature/pause.h"
+#endif
+
+#define WIFI_SET() WRITE(WIFI_RESET_PIN, HIGH);
+#define WIFI_RESET() WRITE(WIFI_RESET_PIN, LOW);
+#define WIFI_IO1_SET() WRITE(WIFI_IO1_PIN, HIGH);
+#define WIFI_IO1_RESET() WRITE(WIFI_IO1_PIN, LOW);
+
+extern uint8_t Explore_Disk (char* path , uint8_t recu_level);
+
+extern uint8_t commands_in_queue;
+extern uint8_t sel_id;
+extern unsigned int getTickDiff(unsigned int curTick, unsigned int lastTick);
+
+SZ_USART_FIFO WifiRxFifo;
+
+#define WAIT_ESP_TRANS_TIMEOUT_TICK 10500
+
+int cfg_cloud_flag = 0;
+
+extern PRINT_TIME print_time;
+
+char wifi_firm_ver[20] = { 0 };
+WIFI_GCODE_BUFFER espGcodeFifo;
+extern uint8_t pause_resum;
+
+uint8_t wifi_connect_flg = 0;
+extern volatile uint8_t get_temp_flag;
+
+#define WIFI_MODE 2
+#define WIFI_AP_MODE 3
+
+int upload_result = 0;
+
+uint32_t upload_time = 0;
+uint32_t upload_size = 0;
+
+volatile WIFI_STATE wifi_link_state;
+WIFI_PARA wifiPara;
+IP_PARA ipPara;
+CLOUD_PARA cloud_para;
+
+char wifi_check_time = 0;
+
+extern uint8_t gCurDir[100];
+
+extern uint32_t wifi_loop_cycle;
+
+volatile TRANSFER_STATE esp_state;
+
+uint8_t left_to_send = 0;
+uint8_t left_to_save[96] = { 0 };
+
+volatile WIFI_DMA_RCV_FIFO wifiDmaRcvFifo;
+
+volatile WIFI_TRANS_ERROR wifiTransError;
+
+static bool need_ok_later = false;
+
+extern volatile WIFI_STATE wifi_link_state;
+extern WIFI_PARA wifiPara;
+extern IP_PARA ipPara;
+extern CLOUD_PARA cloud_para;
+
+extern bool once_flag, flash_preview_begin, default_preview_flg, gcode_preview_over;
+extern char flash_dma_mode;
+
+uint32_t getWifiTick() {
+ return millis();
+}
+
+uint32_t getWifiTickDiff(int32_t lastTick, int32_t curTick) {
+ if (lastTick <= curTick)
+ return (curTick - lastTick) * TICK_CYCLE;
+ else
+ return (0xFFFFFFFF - lastTick + curTick) * TICK_CYCLE;
+}
+
+void wifi_delay(int n) {
+ uint32_t begin = getWifiTick();
+ uint32_t end = begin;
+ while (getWifiTickDiff(begin, end) < (uint32_t)n) {
+ end = getWifiTick();
+ }
+}
+
+void wifi_reset() {
+ uint32_t start, now;
+ start = getWifiTick();
+ now = start;
+ WIFI_RESET();
+ while (getWifiTickDiff(start, now) < 500)
+ now = getWifiTick();
+
+ WIFI_SET();
+}
+
+void mount_file_sys(uint8_t disk_type) {
+ if (disk_type == FILE_SYS_SD) {
+ TERN_(SDSUPPORT, card.mount());
+ }
+ else if (disk_type == FILE_SYS_USB) {
+ }
+}
+
+static bool longName2DosName(const char *longName, uint8_t *dosName) {
+ uint8_t i = FILENAME_LENGTH;
+ while (i)
+ dosName[--i] = '\0';
+ while (*longName) {
+ uint8_t c = *longName++;
+ if (c == '.') { // For a dot...
+ if (i == 0) {
+ return false;
+ }
+ else {
+ strcat((char *)dosName, ".GCO");
+ return dosName[0] != '\0';
+ }
+ }
+ else {
+ // Fail for illegal characters
+ PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
+ while (uint8_t b = pgm_read_byte(p++))
+ if (b == c)
+ return false;
+ if (c < 0x21 || c == 0x7F)
+ return false; // Check size, non-printable characters
+ dosName[i++] = (c < 'a' || c > 'z') ? (c) : (c + ('A' - 'a')); // Uppercase required for 8.3 name
+ }
+ if (i >= 5) {
+ strcat((char *)dosName, "~1.GCO");
+ return dosName[0] != '\0';
+ }
+ }
+ return dosName[0] != '\0'; // Return true if any name was set
+}
+
+#ifdef __STM32F1__
+
+ #include <libmaple/timer.h>
+ #include <libmaple/util.h>
+ #include <libmaple/rcc.h>
+
+ #include <boards.h>
+ #include <wirish.h>
+
+ #include <libmaple/dma.h>
+ #include <libmaple/bitband.h>
+
+ #include <libmaple/libmaple.h>
+ #include <libmaple/gpio.h>
+ #include <libmaple/usart.h>
+ #include <libmaple/ring_buffer.h>
+
+ void exchangeFlashMode(char dmaMode) {
+ if (flash_dma_mode != dmaMode) {
+ flash_dma_mode = dmaMode;
+ if (flash_dma_mode == 1) {
+ }
+ else {
+ dma_disable(DMA1, DMA_CH5);
+ dma_clear_isr_bits(DMA1, DMA_CH4);
+ }
+ }
+ }
+
+ static int storeRcvData(volatile uint8_t *bufToCpy, int32_t len) {
+ unsigned char tmpW = wifiDmaRcvFifo.write_cur;
+ if (len > UDISKBUFLEN) return 0;
+ if (wifiDmaRcvFifo.state[tmpW] == udisk_buf_empty) {
+ memcpy((unsigned char *) wifiDmaRcvFifo.bufferAddr[tmpW], (uint8_t *)bufToCpy, len);
+ wifiDmaRcvFifo.state[tmpW] = udisk_buf_full;
+ wifiDmaRcvFifo.write_cur = (tmpW + 1) % TRANS_RCV_FIFO_BLOCK_NUM;
+ return 1;
+ }
+ return 0;
+ }
+
+ static void esp_dma_pre() {
+ dma_channel_reg_map *channel_regs = dma_tube_regs(DMA1, DMA_CH5);
+
+ CBI32(channel_regs->CCR, 0);
+ channel_regs->CMAR = (uint32_t)WIFISERIAL.usart_device->rb->buf;
+ channel_regs->CNDTR = 0x0000;
+ channel_regs->CNDTR = UART_RX_BUFFER_SIZE;
+ DMA1->regs->IFCR = 0xF0000;
+ SBI32(channel_regs->CCR, 0);
+ }
+
+ static void dma_ch5_irq_handle() {
+ uint8 status_bits = dma_get_isr_bits(DMA1, DMA_CH5);
+ dma_clear_isr_bits(DMA1, DMA_CH5);
+ if (status_bits & 0x8) {
+ // DMA transmit Error
+ }
+ else if (status_bits & 0x2) {
+ // DMA transmit complete
+ if (esp_state == TRANSFER_IDLE)
+ esp_state = TRANSFERING;
+
+ if (storeRcvData(WIFISERIAL.usart_device->rb->buf, UART_RX_BUFFER_SIZE)) {
+ esp_dma_pre();
+ if (wifiTransError.flag != 0x1)
+ WIFI_IO1_RESET();
+ }
+ else {
+ WIFI_IO1_SET();
+ esp_state = TRANSFER_STORE;
+ }
+ }
+ else if (status_bits & 0x4) {
+ // DMA transmit half
+ WIFI_IO1_SET();
+ }
+ }
+ static void wifi_usart_dma_init() {
+ dma_init(DMA1);
+ uint32_t flags = ( DMA_MINC_MODE | DMA_TRNS_CMPLT | DMA_HALF_TRNS | DMA_TRNS_ERR);
+ dma_xfer_size dma_bit_size = DMA_SIZE_8BITS;
+ dma_setup_transfer(DMA1, DMA_CH5, &USART1_BASE->DR, dma_bit_size,
+ (volatile void*)WIFISERIAL.usart_device->rb->buf, dma_bit_size, flags);// Transmit buffer DMA
+ dma_set_priority(DMA1, DMA_CH5, DMA_PRIORITY_LOW);
+ dma_attach_interrupt(DMA1, DMA_CH5, &dma_ch5_irq_handle);
+
+ dma_clear_isr_bits(DMA1, DMA_CH5);
+ dma_set_num_transfers(DMA1, DMA_CH5, UART_RX_BUFFER_SIZE);
+
+ bb_peri_set_bit(&USART1_BASE->CR3, USART_CR3_DMAR_BIT, 1);
+ dma_enable(DMA1, DMA_CH5); // enable transmit
+
+ for (uint8_t i = 0; i < TRANS_RCV_FIFO_BLOCK_NUM; i++) {
+ wifiDmaRcvFifo.bufferAddr[i] = &bmp_public_buf[1024 * i];
+ wifiDmaRcvFifo.state[i] = udisk_buf_empty;
+ }
+
+ memset(wifiDmaRcvFifo.bufferAddr[0], 0, 1024 * TRANS_RCV_FIFO_BLOCK_NUM);
+ wifiDmaRcvFifo.read_cur = 0;
+ wifiDmaRcvFifo.write_cur = 0;
+ }
+
+ void esp_port_begin(uint8_t interrupt) {
+ WifiRxFifo.uart_read_point = 0;
+ WifiRxFifo.uart_write_point = 0;
+ if (interrupt) {
+ #if ENABLED(MKS_WIFI_MODULE)
+ WIFISERIAL.end();
+ for (uint16_t i = 0; i < 65535; i++) { /*nada*/ }
+ WIFISERIAL.begin(WIFI_BAUDRATE);
+ uint32_t serial_connect_timeout = millis() + 1000UL;
+ while (PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+ #endif
+ }
+ else {
+ #if ENABLED(MKS_WIFI_MODULE)
+ WIFISERIAL.end();
+ WIFISERIAL.usart_device->regs->CR1 &= ~USART_CR1_RXNEIE;
+ WIFISERIAL.begin(WIFI_UPLOAD_BAUDRATE);
+ wifi_usart_dma_init();
+ #endif
+ }
+ }
+#else
+
+ DMA_HandleTypeDef wifiUsartDMArx;
+
+ void exchangeFlashMode(char dmaMode) {
+ if (flash_dma_mode != dmaMode) {
+ flash_dma_mode = dmaMode;
+ if (flash_dma_mode == 1) {
+ }
+ else {
+ }
+ }
+ }
+
+ #ifdef STM32F1xx
+
+ HAL_StatusTypeDef HAL_DMA_PollForTransferCustomize(DMA_HandleTypeDef *hdma, uint32_t CompleteLevel, uint32_t Timeout)
+ {
+ uint32_t temp;
+ uint32_t tickstart = 0U;
+
+ if(HAL_DMA_STATE_BUSY != hdma->State)
+ {
+ /* no transfer ongoing */
+ hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
+ __HAL_UNLOCK(hdma);
+ return HAL_ERROR;
+ }
+
+ /* Polling mode not supported in circular mode */
+ if (RESET != (hdma->Instance->CCR & DMA_CCR_CIRC))
+ {
+ hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
+ return HAL_ERROR;
+ }
+
+ /* Get the level transfer complete flag */
+ if(CompleteLevel == HAL_DMA_FULL_TRANSFER)
+ {
+ /* Transfer Complete flag */
+ temp = __HAL_DMA_GET_TC_FLAG_INDEX(hdma);
+ }
+ else
+ {
+ /* Half Transfer Complete flag */
+ temp = __HAL_DMA_GET_HT_FLAG_INDEX(hdma);
+ }
+
+ /* Get tick */
+ tickstart = HAL_GetTick();
+
+ while(__HAL_DMA_GET_FLAG(hdma, temp) == RESET)
+ {
+ if((__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma)) != RESET))
+ {
+ /* Clear the half transfer complete flag */
+ __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
+ WIFI_IO1_SET();
+ }
+
+ if((__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma)) != RESET))
+ {
+ /* When a DMA transfer error occurs */
+ /* A hardware clear of its EN bits is performed */
+ /* Clear all flags */
+ hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex);
+
+ /* Update error code */
+ SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TE);
+
+ /* Change the DMA state */
+ hdma->State= HAL_DMA_STATE_READY;
+
+ /* Process Unlocked */
+ __HAL_UNLOCK(hdma);
+
+ return HAL_ERROR;
+ }
+ /* Check for the Timeout */
+ if(Timeout != HAL_MAX_DELAY)
+ {
+ if((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout))
+ {
+ /* Update error code */
+ SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TIMEOUT);
+
+ /* Change the DMA state */
+ hdma->State = HAL_DMA_STATE_READY;
+
+ /* Process Unlocked */
+ __HAL_UNLOCK(hdma);
+
+ return HAL_ERROR;
+ }
+ }
+ }
+
+ if(CompleteLevel == HAL_DMA_FULL_TRANSFER)
+ {
+ /* Clear the transfer complete flag */
+ __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
+
+ /* The selected Channelx EN bit is cleared (DMA is disabled and
+ all transfers are complete) */
+ hdma->State = HAL_DMA_STATE_READY;
+ }
+ else
+ {
+ /* Clear the half transfer complete flag */
+ __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma));
+ }
+
+ /* Process unlocked */
+ __HAL_UNLOCK(hdma);
+
+ return HAL_OK;
+ }
+ #else
+
+ typedef struct
+ {
+ __IO uint32_t ISR; /*!< DMA interrupt status register */
+ __IO uint32_t Reserved0;
+ __IO uint32_t IFCR; /*!< DMA interrupt flag clear register */
+ } MYDMA_Base_Registers;
+
+ HAL_StatusTypeDef HAL_DMA_PollForTransferCustomize(DMA_HandleTypeDef *hdma, HAL_DMA_LevelCompleteTypeDef CompleteLevel, uint32_t Timeout)
+ {
+ HAL_StatusTypeDef status = HAL_OK;
+ uint32_t mask_cpltlevel;
+ uint32_t tickstart = HAL_GetTick();
+ uint32_t tmpisr;
+
+ /* calculate DMA base and stream number */
+ MYDMA_Base_Registers *regs;
+
+ if(HAL_DMA_STATE_BUSY != hdma->State)
+ {
+ /* No transfer ongoing */
+ hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
+ __HAL_UNLOCK(hdma);
+ return HAL_ERROR;
+ }
+
+ /* Polling mode not supported in circular mode and double buffering mode */
+ if ((hdma->Instance->CR & DMA_SxCR_CIRC) != RESET)
+ {
+ hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED;
+ return HAL_ERROR;
+ }
+
+ /* Get the level transfer complete flag */
+ if(CompleteLevel == HAL_DMA_FULL_TRANSFER)
+ {
+ /* Transfer Complete flag */
+ mask_cpltlevel = DMA_FLAG_TCIF0_4 << hdma->StreamIndex;
+ }
+ else
+ {
+ /* Half Transfer Complete flag */
+ mask_cpltlevel = DMA_FLAG_HTIF0_4 << hdma->StreamIndex;
+ }
+
+ regs = (MYDMA_Base_Registers *)hdma->StreamBaseAddress;
+ tmpisr = regs->ISR;
+
+ while(((tmpisr & mask_cpltlevel) == RESET) && ((hdma->ErrorCode & HAL_DMA_ERROR_TE) == RESET))
+ {
+ /* Check for the Timeout (Not applicable in circular mode)*/
+ if(Timeout != HAL_MAX_DELAY)
+ {
+ if((Timeout == 0U)||((HAL_GetTick() - tickstart ) > Timeout))
+ {
+ /* Update error code */
+ hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT;
+
+ /* Process Unlocked */
+ __HAL_UNLOCK(hdma);
+
+ /* Change the DMA state */
+ hdma->State = HAL_DMA_STATE_READY;
+
+ return HAL_TIMEOUT;
+ }
+ }
+
+ /* Get the ISR register value */
+ tmpisr = regs->ISR;
+
+ if((tmpisr & (DMA_FLAG_HTIF0_4 << hdma->StreamIndex)) != RESET)
+ {
+ /* Clear the Direct Mode error flag */
+ regs->IFCR = DMA_FLAG_HTIF0_4 << hdma->StreamIndex;
+ WIFI_IO1_SET();
+ }
+
+ if((tmpisr & (DMA_FLAG_TEIF0_4 << hdma->StreamIndex)) != RESET)
+ {
+ /* Update error code */
+ hdma->ErrorCode |= HAL_DMA_ERROR_TE;
+
+ /* Clear the transfer error flag */
+ regs->IFCR = DMA_FLAG_TEIF0_4 << hdma->StreamIndex;
+ }
+
+ if((tmpisr & (DMA_FLAG_FEIF0_4 << hdma->StreamIndex)) != RESET)
+ {
+ /* Update error code */
+ hdma->ErrorCode |= HAL_DMA_ERROR_FE;
+
+ /* Clear the FIFO error flag */
+ regs->IFCR = DMA_FLAG_FEIF0_4 << hdma->StreamIndex;
+ }
+
+ if((tmpisr & (DMA_FLAG_DMEIF0_4 << hdma->StreamIndex)) != RESET)
+ {
+ /* Update error code */
+ hdma->ErrorCode |= HAL_DMA_ERROR_DME;
+
+ /* Clear the Direct Mode error flag */
+ regs->IFCR = DMA_FLAG_DMEIF0_4 << hdma->StreamIndex;
+ }
+ }
+
+ if(hdma->ErrorCode != HAL_DMA_ERROR_NONE)
+ {
+ if((hdma->ErrorCode & HAL_DMA_ERROR_TE) != RESET)
+ {
+ HAL_DMA_Abort(hdma);
+
+ /* Clear the half transfer and transfer complete flags */
+ regs->IFCR = (DMA_FLAG_HTIF0_4 | DMA_FLAG_TCIF0_4) << hdma->StreamIndex;
+
+ /* Process Unlocked */
+ __HAL_UNLOCK(hdma);
+
+ /* Change the DMA state */
+ hdma->State= HAL_DMA_STATE_READY;
+
+ return HAL_ERROR;
+ }
+ }
+
+ /* Get the level transfer complete flag */
+ if(CompleteLevel == HAL_DMA_FULL_TRANSFER)
+ {
+ /* Clear the half transfer and transfer complete flags */
+ regs->IFCR = (DMA_FLAG_HTIF0_4 | DMA_FLAG_TCIF0_4) << hdma->StreamIndex;
+
+ /* Process Unlocked */
+ __HAL_UNLOCK(hdma);
+
+ hdma->State = HAL_DMA_STATE_READY;
+ }
+ else
+ {
+ /* Clear the half transfer and transfer complete flags */
+ regs->IFCR = (DMA_FLAG_HTIF0_4) << hdma->StreamIndex;
+ }
+
+ return status;
+ }
+ #endif
+
+ static void dmaTransmitBegin() {
+ wifiUsartDMArx.Init.MemInc = DMA_MINC_ENABLE;
+ if (HAL_DMA_Init((DMA_HandleTypeDef *)&wifiUsartDMArx) != HAL_OK) {
+ Error_Handler();
+ }
+ if (HAL_DMA_Start(&wifiUsartDMArx, (uint32_t)&(USART1->DR), (uint32_t)WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE)) {
+ Error_Handler();
+ }
+ USART1->CR1 |= USART_CR1_UE;
+
+ SET_BIT(USART1->CR3, USART_CR3_DMAR);
+ WIFI_IO1_RESET();
+ }
+
+ static int storeRcvData(volatile uint8_t *bufToCpy, int32_t len) {
+ unsigned char tmpW = wifiDmaRcvFifo.write_cur;
+
+ if (len > UDISKBUFLEN) return 0;
+
+ if (wifiDmaRcvFifo.state[tmpW] == udisk_buf_empty) {
+ const int timeOut = 2000; //millisecond
+ dmaTransmitBegin();
+ if(HAL_DMA_PollForTransferCustomize(&wifiUsartDMArx, HAL_DMA_FULL_TRANSFER, timeOut) == HAL_OK) {
+ memcpy((unsigned char *) wifiDmaRcvFifo.bufferAddr[tmpW], (uint8_t *)bufToCpy, len);
+ wifiDmaRcvFifo.state[tmpW] = udisk_buf_full;
+ wifiDmaRcvFifo.write_cur = (tmpW + 1) % TRANS_RCV_FIFO_BLOCK_NUM;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ static void wifi_usart_dma_init() {
+ #ifdef STM32F1xx
+ __HAL_RCC_DMA1_CLK_ENABLE();
+ wifiUsartDMArx.Instance = DMA1_Channel5;
+ #else
+ __HAL_RCC_DMA2_CLK_ENABLE();
+ wifiUsartDMArx.Instance = DMA2_Stream2;
+ wifiUsartDMArx.Init.Channel = DMA_CHANNEL_4;
+ #endif
+ wifiUsartDMArx.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ wifiUsartDMArx.Init.PeriphInc = DMA_PINC_DISABLE;
+ wifiUsartDMArx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
+ wifiUsartDMArx.Init.MemDataAlignment = DMA_PDATAALIGN_BYTE;
+ wifiUsartDMArx.Init.Mode = DMA_NORMAL;
+ #ifdef STM32F4xx
+ wifiUsartDMArx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+ #endif
+ wifiUsartDMArx.Init.MemInc = DMA_MINC_ENABLE;
+ if (HAL_DMA_Init((DMA_HandleTypeDef *)&wifiUsartDMArx) != HAL_OK) {
+ Error_Handler();
+ }
+ if (HAL_DMA_Start(&wifiUsartDMArx, (uint32_t)&(USART1->DR), (uint32_t)WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE)) {
+ Error_Handler();
+ }
+ USART1->CR1 |= USART_CR1_UE;
+
+ SET_BIT(USART1->CR3, USART_CR3_DMAR); /* Enable Rx DMA Request */
+
+ for (uint8_t i = 0; i < TRANS_RCV_FIFO_BLOCK_NUM; i++) {
+ wifiDmaRcvFifo.bufferAddr[i] = &bmp_public_buf[1024 * i];
+ wifiDmaRcvFifo.state[i] = udisk_buf_empty;
+ }
+
+ memset(wifiDmaRcvFifo.bufferAddr[0], 0, 1024 * TRANS_RCV_FIFO_BLOCK_NUM);
+ wifiDmaRcvFifo.read_cur = 0;
+ wifiDmaRcvFifo.write_cur = 0;
+ }
+
+
+ void esp_port_begin(uint8_t interrupt) {
+ WifiRxFifo.uart_read_point = 0;
+ WifiRxFifo.uart_write_point = 0;
+
+ if (interrupt) {
+ #if ENABLED(MKS_WIFI_MODULE)
+ WIFISERIAL.end();
+ for (uint16_t i = 0; i < 65535; i++) { /*nada*/ }
+ WIFISERIAL.begin(WIFI_BAUDRATE);
+ uint32_t serial_connect_timeout = millis() + 1000UL;
+ while (PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+ #endif
+ }
+ else {
+ #if ENABLED(MKS_WIFI_MODULE)
+ WIFISERIAL.end();
+ USART1->CR1 &= ~USART_CR1_RXNEIE;
+ WIFISERIAL.begin(WIFI_UPLOAD_BAUDRATE);
+ wifi_usart_dma_init();
+ #endif
+ }
+ }
+#endif //
+
+#if ENABLED(MKS_WIFI_MODULE)
+
+ int raw_send_to_wifi(uint8_t *buf, int len) {
+ if (buf == 0 || len <= 0) return 0;
+ for (int i = 0; i < len; i++)
+ WIFISERIAL.write(*(buf + i));
+ return len;
+ }
+
+#endif
+
+void wifi_ret_ack() {}
+
+uint8_t buf_to_wifi[256];
+int index_to_wifi = 0;
+int package_to_wifi(WIFI_RET_TYPE type, uint8_t *buf, int len) {
+ uint8_t wifi_ret_head = 0xA5;
+ uint8_t wifi_ret_tail = 0xFC;
+
+ if (type == WIFI_PARA_SET) {
+ int data_offset = 4;
+ int apLen = strlen((const char *)uiCfg.wifi_name);
+ int keyLen = strlen((const char *)uiCfg.wifi_key);
+
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+
+ buf_to_wifi[data_offset] = gCfgItems.wifi_mode_sel;
+ buf_to_wifi[data_offset + 1] = apLen;
+ memcpy(&buf_to_wifi[data_offset + 2], (const char *)uiCfg.wifi_name, apLen);
+ buf_to_wifi[data_offset + apLen + 2] = keyLen;
+ memcpy(&buf_to_wifi[data_offset + apLen + 3], (const char *)uiCfg.wifi_key, keyLen);
+ buf_to_wifi[data_offset + apLen + keyLen + 3] = wifi_ret_tail;
+
+ index_to_wifi = apLen + keyLen + 3;
+
+ buf_to_wifi[0] = wifi_ret_head;
+ buf_to_wifi[1] = type;
+ buf_to_wifi[2] = index_to_wifi & 0xFF;
+ buf_to_wifi[3] = (index_to_wifi >> 8) & 0xFF;
+
+ raw_send_to_wifi(buf_to_wifi, 5 + index_to_wifi);
+
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+ }
+ else if (type == WIFI_TRANS_INF) {
+ if (len > (int)(sizeof(buf_to_wifi) - index_to_wifi - 5)) {
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+ return 0;
+ }
+
+ if (len > 0) {
+ memcpy(&buf_to_wifi[4 + index_to_wifi], buf, len);
+ index_to_wifi += len;
+
+ if (index_to_wifi < 1)
+ return 0;
+
+ if (buf_to_wifi[index_to_wifi + 3] == '\n') {
+ // mask "wait" "busy" "X:"
+ if (((buf_to_wifi[4] == 'w') && (buf_to_wifi[5] == 'a') && (buf_to_wifi[6] == 'i') && (buf_to_wifi[7] == 't') )
+ || ((buf_to_wifi[4] == 'b') && (buf_to_wifi[5] == 'u') && (buf_to_wifi[6] == 's') && (buf_to_wifi[7] == 'y') )
+ || ((buf_to_wifi[4] == 'X') && (buf_to_wifi[5] == ':') )
+ ) {
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+ return 0;
+ }
+
+ buf_to_wifi[0] = wifi_ret_head;
+ buf_to_wifi[1] = type;
+ buf_to_wifi[2] = index_to_wifi & 0xFF;
+ buf_to_wifi[3] = (index_to_wifi >> 8) & 0xFF;
+ buf_to_wifi[4 + index_to_wifi] = wifi_ret_tail;
+
+ raw_send_to_wifi(buf_to_wifi, 5 + index_to_wifi);
+
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+ }
+ }
+ }
+ else if (type == WIFI_EXCEP_INF) {
+ ZERO(buf_to_wifi);
+
+ buf_to_wifi[0] = wifi_ret_head;
+ buf_to_wifi[1] = type;
+ buf_to_wifi[2] = 1;
+ buf_to_wifi[3] = 0;
+ buf_to_wifi[4] = *buf;
+ buf_to_wifi[5] = wifi_ret_tail;
+
+ raw_send_to_wifi(buf_to_wifi, 6);
+
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+ }
+ else if (type == WIFI_CLOUD_CFG) {
+ int data_offset = 4;
+ int urlLen = strlen((const char *)uiCfg.cloud_hostUrl);
+
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+
+ buf_to_wifi[data_offset] = gCfgItems.cloud_enable ? 0x0A : 0x05;
+ buf_to_wifi[data_offset + 1] = urlLen;
+ memcpy(&buf_to_wifi[data_offset + 2], (const char *)uiCfg.cloud_hostUrl, urlLen);
+ buf_to_wifi[data_offset + urlLen + 2] = uiCfg.cloud_port & 0xFF;
+ buf_to_wifi[data_offset + urlLen + 3] = (uiCfg.cloud_port >> 8) & 0xFF;
+ buf_to_wifi[data_offset + urlLen + 4] = wifi_ret_tail;
+
+ index_to_wifi = urlLen + 4;
+
+ buf_to_wifi[0] = wifi_ret_head;
+ buf_to_wifi[1] = type;
+ buf_to_wifi[2] = index_to_wifi & 0xFF;
+ buf_to_wifi[3] = (index_to_wifi >> 8) & 0xFF;
+
+ raw_send_to_wifi(buf_to_wifi, 5 + index_to_wifi);
+
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+ }
+ else if (type == WIFI_CLOUD_UNBIND) {
+ ZERO(buf_to_wifi);
+
+ buf_to_wifi[0] = wifi_ret_head;
+ buf_to_wifi[1] = type;
+ buf_to_wifi[2] = 0;
+ buf_to_wifi[3] = 0;
+ buf_to_wifi[4] = wifi_ret_tail;
+
+ raw_send_to_wifi(buf_to_wifi, 5);
+
+ ZERO(buf_to_wifi);
+ index_to_wifi = 0;
+ }
+ return 1;
+}
+
+
+#define SEND_OK_TO_WIFI send_to_wifi((uint8_t *)"ok\r\n", strlen("ok\r\n"))
+int send_to_wifi(uint8_t *buf, int len) { return package_to_wifi(WIFI_TRANS_INF, buf, len); }
+
+void set_cur_file_sys(int fileType) { gCfgItems.fileSysType = fileType; }
+
+void get_file_list(char *path) {
+ if (!path) return;
+
+ if (gCfgItems.fileSysType == FILE_SYS_SD) {
+ TERN_(SDSUPPORT, card.mount());
+ }
+ else if (gCfgItems.fileSysType == FILE_SYS_USB) {
+ // udisk
+ }
+ Explore_Disk(path, 0);
+}
+
+char wait_ip_back_flag = 0;
+
+typedef struct {
+ int write_index;
+ uint8_t saveFileName[30];
+ uint8_t fileTransfer;
+ uint32_t fileLen;
+ uint32_t tick_begin;
+ uint32_t tick_end;
+} FILE_WRITER;
+
+FILE_WRITER file_writer;
+
+int32_t lastFragment = 0;
+
+char saveFilePath[50];
+
+static SdFile upload_file, *upload_curDir;
+static filepos_t pos;
+
+int write_to_file(char *buf, int len) {
+ int i;
+ int res = 0;
+
+ for (i = 0; i < len; i++) {
+ public_buf[file_writer.write_index++] = buf[i];
+ if (file_writer.write_index >= 512) {
+ res = upload_file.write(public_buf, file_writer.write_index);
+
+ if (res == -1) {
+ upload_file.close();
+ const char * const fname = card.diveToFile(true, upload_curDir, saveFilePath);
+
+ if (upload_file.open(upload_curDir, fname, O_WRITE)) {
+ upload_file.setpos(&pos);
+ res = upload_file.write(public_buf, file_writer.write_index);
+ }
+ }
+ if (res == -1) {
+ return -1;
+ }
+ upload_file.getpos(&pos);
+ file_writer.write_index = 0;
+ }
+ }
+
+ if (res == -1) {
+ memset(public_buf, 0, sizeof(public_buf));
+ file_writer.write_index = 0;
+ return -1;
+ }
+
+ return 0;
+}
+
+#define ESP_PROTOC_HEAD (uint8_t)0xA5
+#define ESP_PROTOC_TAIL (uint8_t)0xFC
+
+#define ESP_TYPE_NET (uint8_t)0x0
+#define ESP_TYPE_GCODE (uint8_t)0x1
+#define ESP_TYPE_FILE_FIRST (uint8_t)0x2
+#define ESP_TYPE_FILE_FRAGMENT (uint8_t)0x3
+
+#define ESP_TYPE_WIFI_LIST (uint8_t)0x4
+
+uint8_t esp_msg_buf[UART_RX_BUFFER_SIZE] = { 0 };
+uint16_t esp_msg_index = 0;
+
+typedef struct {
+ uint8_t head;
+ uint8_t type;
+ uint16_t dataLen;
+ uint8_t *data;
+ uint8_t tail;
+} ESP_PROTOC_FRAME;
+
+
+static int cut_msg_head(uint8_t *msg, uint16_t msgLen, uint16_t cutLen) {
+ if (msgLen < cutLen) return 0;
+
+ else if (msgLen == cutLen) {
+ memset(msg, 0, msgLen);
+ return 0;
+ }
+
+ for (int i = 0; i < (msgLen - cutLen); i++)
+ msg[i] = msg[cutLen + i];
+
+ memset(&msg[msgLen - cutLen], 0, cutLen);
+
+ return msgLen - cutLen;
+}
+
+uint8_t Explore_Disk(char* path , uint8_t recu_level) {
+ char tmp[200];
+ char Fstream[200];
+
+ if (!path) return 0;
+
+ const uint8_t fileCnt = card.get_num_Files();
+
+ for (uint8_t i = 0; i < fileCnt; i++) {
+ const uint16_t nr =
+ #if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA)
+ fileCnt - 1 -
+ #endif
+ i;
+
+ #if ENABLED(SDCARD_SORT_ALPHA)
+ card.getfilename_sorted(nr);
+ #else
+ card.getfilename_sorted(nr);
+ #endif
+ memset(tmp, 0, sizeof(tmp));
+ strcpy(tmp, card.filename);
+
+ ZERO(Fstream);
+ strcpy(Fstream, tmp);
+
+ if (card.flag.filenameIsDir && recu_level <= 10)
+ strcat(Fstream, ".DIR");
+
+ strcat(Fstream, "\r\n");
+ send_to_wifi((uint8_t*)Fstream, strlen(Fstream));
+ }
+
+ return fileCnt;
+}
+
+static void wifi_gcode_exec(uint8_t *cmd_line) {
+ int8_t tempBuf[100] = { 0 };
+ uint8_t *tmpStr = 0;
+ int cmd_value;
+ volatile int print_rate;
+ if (strchr((char *)cmd_line, '\n') && (strchr((char *)cmd_line, 'G') || strchr((char *)cmd_line, 'M') || strchr((char *)cmd_line, 'T'))) {
+ tmpStr = (uint8_t *)strchr((char *)cmd_line, '\n');
+ if (tmpStr) *tmpStr = '\0';
+
+ tmpStr = (uint8_t *)strchr((char *)cmd_line, '\r');
+ if (tmpStr) *tmpStr = '\0';
+
+ tmpStr = (uint8_t *)strchr((char *)cmd_line, '*');
+ if (tmpStr) *tmpStr = '\0';
+
+ tmpStr = (uint8_t *)strchr((char *)cmd_line, 'M');
+ if (tmpStr) {
+ cmd_value = atoi((char *)(tmpStr + 1));
+ tmpStr = (uint8_t *)strchr((char *)tmpStr, ' ');
+
+ switch (cmd_value) {
+
+ case 20: // M20: Print SD / µdisk file
+ file_writer.fileTransfer = 0;
+ if (uiCfg.print_state == IDLE) {
+ int index = 0;
+
+ if (tmpStr == 0) {
+ gCfgItems.fileSysType = FILE_SYS_SD;
+ send_to_wifi((uint8_t *)"Begin file list\r\n", strlen("Begin file list\r\n"));
+ get_file_list((char *)"0:/");
+ send_to_wifi((uint8_t *)"End file list\r\n", strlen("End file list\r\n"));
+ SEND_OK_TO_WIFI;
+ break;
+ }
+
+ while (tmpStr[index] == ' ') index++;
+
+ if (gCfgItems.wifi_type == ESP_WIFI) {
+ char *path = (char *)tempBuf;
+
+ if (strlen((char *)&tmpStr[index]) < 80) {
+ send_to_wifi((uint8_t *)"Begin file list\r\n", strlen("Begin file list\r\n"));
+
+ if (strncmp((char *)&tmpStr[index], "1:", 2) == 0)
+ gCfgItems.fileSysType = FILE_SYS_SD;
+ else if (strncmp((char *)&tmpStr[index], "0:", 2) == 0)
+ gCfgItems.fileSysType = FILE_SYS_USB;
+
+ strcpy((char *)path, (char *)&tmpStr[index]);
+ get_file_list(path);
+ send_to_wifi((uint8_t *)"End file list\r\n", strlen("End file list\r\n"));
+ }
+ SEND_OK_TO_WIFI;
+ }
+ }
+ break;
+
+ case 21:
+ /*init sd card*/
+ SEND_OK_TO_WIFI;
+ break;
+
+ case 23:
+ /*select the file*/
+ if (uiCfg.print_state == IDLE) {
+ int index = 0;
+ while (tmpStr[index] == ' ') index++;
+
+ if (strstr((char *)&tmpStr[index], ".g") || strstr((char *)&tmpStr[index], ".G")) {
+ if (strlen((char *)&tmpStr[index]) < 80) {
+ ZERO(list_file.file_name[sel_id]);
+ ZERO(list_file.long_name[sel_id]);
+ uint8_t has_path_selected = 0;
+
+ if (gCfgItems.wifi_type == ESP_WIFI) {
+ if (strncmp((char *)&tmpStr[index], "1:", 2) == 0) {
+ gCfgItems.fileSysType = FILE_SYS_SD;
+ has_path_selected = 1;
+ }
+ else if (strncmp((char *)&tmpStr[index], "0:", 2) == 0) {
+ gCfgItems.fileSysType = FILE_SYS_USB;
+ has_path_selected = 1;
+ }
+ else if (tmpStr[index] != '/')
+ strcat((char *)list_file.file_name[sel_id], "/");
+
+ if (file_writer.fileTransfer == 1) {
+ uint8_t dosName[FILENAME_LENGTH];
+ uint8_t fileName[sizeof(list_file.file_name[sel_id])];
+ fileName[0] = '\0';
+ if (has_path_selected == 1) {
+ strcat((char *)fileName, (char *)&tmpStr[index + 3]);
+ strcat((char *)list_file.file_name[sel_id], "/");
+ }
+ else strcat((char *)fileName, (char *)&tmpStr[index]);
+ if (!longName2DosName((const char *)fileName, dosName)) {
+ strcpy(list_file.file_name[sel_id], "notValid");
+ }
+ strcat((char *)list_file.file_name[sel_id], (char *)dosName);
+ strcat((char *)list_file.long_name[sel_id], (char *)dosName);
+ }
+ else {
+ strcat((char *)list_file.file_name[sel_id], (char *)&tmpStr[index]);
+ strcat((char *)list_file.long_name[sel_id], (char *)&tmpStr[index]);
+ }
+
+ }
+ else
+ strcpy(list_file.file_name[sel_id], (char *)&tmpStr[index]);
+
+ char *cur_name=strrchr(list_file.file_name[sel_id],'/');
+
+ card.openFileRead(cur_name);
+
+ if (card.isFileOpen())
+ send_to_wifi((uint8_t *)"File selected\r\n", strlen("File selected\r\n"));
+ else {
+ send_to_wifi((uint8_t *)"file.open failed\r\n", strlen("file.open failed\r\n"));
+ strcpy(list_file.file_name[sel_id], "notValid");
+ }
+ SEND_OK_TO_WIFI;
+ }
+ }
+ }
+ break;
+
+ case 24:
+ if (strcmp(list_file.file_name[sel_id], "notValid") != 0) {
+ if (uiCfg.print_state == IDLE) {
+ lv_clear_cur_ui();
+ reset_print_time();
+ start_print_time();
+ preview_gcode_prehandle(list_file.file_name[sel_id]);
+ uiCfg.print_state = WORKING;
+ lv_draw_printing();
+
+ #if ENABLED(SDSUPPORT)
+ if (!gcode_preview_over) {
+ char *cur_name = strrchr(list_file.file_name[sel_id], '/');
+
+ card.endFilePrint();
+
+ SdFile file;
+ SdFile *curDir;
+ card.endFilePrint();
+ const char * const fname = card.diveToFile(true, curDir, cur_name);
+ if (!fname) return;
+ if (file.open(curDir, fname, O_READ)) {
+ gCfgItems.curFilesize = file.fileSize();
+ file.close();
+ update_spi_flash();
+ }
+ card.openFileRead(cur_name);
+ if (card.isFileOpen()) {
+ //saved_feedrate_percentage = feedrate_percentage;
+ feedrate_percentage = 100;
+ planner.flow_percentage[0] = 100;
+ planner.e_factor[0] = planner.flow_percentage[0] * 0.01f;
+ #if EXTRUDERS == 2
+ planner.flow_percentage[1] = 100;
+ planner.e_factor[1] = planner.flow_percentage[1] * 0.01f;
+ #endif
+ card.startFileprint();
+ TERN_(POWER_LOSS_RECOVERY, recovery.prepare());
+ once_flag = false;
+ }
+ }
+ #endif
+ }
+ else if (uiCfg.print_state == PAUSED) {
+ uiCfg.print_state = RESUMING;
+ lv_clear_cur_ui();
+ start_print_time();
+
+ if (gCfgItems.from_flash_pic)
+ flash_preview_begin = true;
+ else
+ default_preview_flg = true;
+ lv_draw_printing();
+ }
+ else if (uiCfg.print_state == REPRINTING) {
+ uiCfg.print_state = REPRINTED;
+ lv_clear_cur_ui();
+ start_print_time();
+ if (gCfgItems.from_flash_pic)
+ flash_preview_begin = true;
+ else
+ default_preview_flg = true;
+ lv_draw_printing();
+ }
+ }
+ SEND_OK_TO_WIFI;
+ break;
+
+ case 25:
+ /*pause print file*/
+ if (uiCfg.print_state == WORKING) {
+ stop_print_time();
+
+ lv_clear_cur_ui();
+
+ #if ENABLED(SDSUPPORT)
+ card.pauseSDPrint();
+ uiCfg.print_state = PAUSING;
+ #endif
+ if (gCfgItems.from_flash_pic)
+ flash_preview_begin = true;
+ else
+ default_preview_flg = true;
+ lv_draw_printing();
+ SEND_OK_TO_WIFI;
+ }
+ break;
+
+ case 26:
+ /*stop print file*/
+ if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED) || (uiCfg.print_state == REPRINTING)) {
+ stop_print_time();
+
+ lv_clear_cur_ui();
+ #if ENABLED(SDSUPPORT)
+ uiCfg.print_state = IDLE;
+ card.flag.abort_sd_printing = true;
+ #endif
+
+ lv_draw_ready_print();
+
+ SEND_OK_TO_WIFI;
+ }
+ break;
+
+ case 27:
+ /*report print rate*/
+ if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED)|| (uiCfg.print_state == REPRINTING)) {
+ print_rate = uiCfg.totalSend;
+ ZERO(tempBuf);
+ sprintf((char *)tempBuf, "M27 %d\r\n", print_rate);
+ send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf));
+ }
+ break;
+
+ case 28:
+ /*begin to transfer file to filesys*/
+ if (uiCfg.print_state == IDLE) {
+
+ int index = 0;
+ while (tmpStr[index] == ' ') index++;
+
+ if (strstr((char *)&tmpStr[index], ".g") || strstr((char *)&tmpStr[index], ".G")) {
+ strcpy((char *)file_writer.saveFileName, (char *)&tmpStr[index]);
+
+ if (gCfgItems.fileSysType == FILE_SYS_SD) {
+ ZERO(tempBuf);
+ sprintf((char *)tempBuf, "%s", file_writer.saveFileName);
+ }
+ else if (gCfgItems.fileSysType == FILE_SYS_USB) {
+ ZERO(tempBuf);
+ sprintf((char *)tempBuf, "%s", (char *)file_writer.saveFileName);
+ }
+ mount_file_sys(gCfgItems.fileSysType);
+
+ #if ENABLED(SDSUPPORT)
+ char *cur_name = strrchr(list_file.file_name[sel_id], '/');
+ card.openFileWrite(cur_name);
+ if (card.isFileOpen()) {
+ ZERO(file_writer.saveFileName);
+ strcpy((char *)file_writer.saveFileName, (char *)&tmpStr[index]);
+ ZERO(tempBuf);
+ sprintf((char *)tempBuf, "Writing to file: %s\r\n", (char *)file_writer.saveFileName);
+ wifi_ret_ack();
+ send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf));
+ wifi_link_state = WIFI_WAIT_TRANS_START;
+ }
+ else {
+ wifi_link_state = WIFI_CONNECTED;
+ lv_clear_cur_ui();
+ lv_draw_dialog(DIALOG_TRANSFER_NO_DEVICE);
+ }
+ #endif
+ }
+ }
+ break;
+ case 105:
+ case 991:
+ ZERO(tempBuf);
+ if (cmd_value == 105) {
+ SEND_OK_TO_WIFI;
+ sprintf((char *)tempBuf,"T:%.1f /%.1f B:%.1f /%.1f T0:%.1f /%.1f T1:%.1f /%.1f @:0 B@:0\r\n",
+
+ (float)thermalManager.temp_hotend[0].celsius, (float)thermalManager.temp_hotend[0].target,
+ #if HAS_HEATED_BED
+ (float)thermalManager.temp_bed.celsius, (float)thermalManager.temp_bed.target,
+ #else
+ 0.0f, 0.0f,
+ #endif
+ (float)thermalManager.temp_hotend[0].celsius, (float)thermalManager.temp_hotend[0].target,
+ #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER
+ (float)thermalManager.temp_hotend[1].celsius, (float)thermalManager.temp_hotend[1].target
+ #else
+ 0.0f, 0.0f
+ #endif
+ );
+ }
+ else {
+ sprintf((char *)tempBuf,"T:%d /%d B:%d /%d T0:%d /%d T1:%d /%d @:0 B@:0\r\n",
+
+ (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target,
+ #if HAS_HEATED_BED
+ (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target,
+ #else
+ 0, 0,
+ #endif
+ (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target,
+ #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER
+ (int)thermalManager.temp_hotend[1].celsius, (int)thermalManager.temp_hotend[1].target
+ #else
+ 0, 0
+ #endif
+ );
+ }
+
+ send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf));
+ queue.enqueue_one_P(PSTR("M105"));
+ break;
+
+ case 992:
+ if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED)) {
+ ZERO(tempBuf);
+ sprintf((char *)tempBuf, "M992 %d%d:%d%d:%d%d\r\n", print_time.hours/10, print_time.hours%10, print_time.minutes/10, print_time.minutes%10, print_time.seconds/10, print_time.seconds%10);
+ wifi_ret_ack();
+ send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf));
+ }
+ break;
+
+ case 994:
+ if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED)) {
+ ZERO(tempBuf);
+ if (strlen((char *)list_file.file_name[sel_id]) > (100 - 1)) return;
+ sprintf((char *)tempBuf, "M994 %s;%d\n", list_file.file_name[sel_id],(int)gCfgItems.curFilesize);
+ wifi_ret_ack();
+ send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf));
+ }
+ break;
+
+ case 997:
+ if (uiCfg.print_state == IDLE) {
+ wifi_ret_ack();
+ send_to_wifi((uint8_t *)"M997 IDLE\r\n", strlen("M997 IDLE\r\n"));
+ }
+ else if (uiCfg.print_state == WORKING) {
+ wifi_ret_ack();
+ send_to_wifi((uint8_t *)"M997 PRINTING\r\n", strlen("M997 PRINTING\r\n"));
+ }
+ else if (uiCfg.print_state == PAUSED) {
+ wifi_ret_ack();
+ send_to_wifi((uint8_t *)"M997 PAUSE\r\n", strlen("M997 PAUSE\r\n"));
+ }
+ else if (uiCfg.print_state == REPRINTING) {
+ wifi_ret_ack();
+ send_to_wifi((uint8_t *)"M997 PAUSE\r\n", strlen("M997 PAUSE\r\n"));
+ }
+ if (uiCfg.command_send == 0) get_wifi_list_command_send();
+ break;
+
+ case 998:
+ if (uiCfg.print_state == IDLE) {
+ int v = atoi((char *)tmpStr);
+ if (v == 0)
+ set_cur_file_sys(0);
+ else if (v == 1)
+ set_cur_file_sys(1);
+ wifi_ret_ack();
+ }
+ break;
+
+ case 115:
+ ZERO(tempBuf);
+ SEND_OK_TO_WIFI;
+ send_to_wifi((uint8_t *)"FIRMWARE_NAME:Robin_nano\r\n", strlen("FIRMWARE_NAME:Robin_nano\r\n"));
+ break;
+
+ default:
+ strcat((char *)cmd_line, "\n");
+
+ if (espGcodeFifo.wait_tick > 5) {
+ uint32_t left;
+ if (espGcodeFifo.r > espGcodeFifo.w)
+ left = espGcodeFifo.r - espGcodeFifo.w - 1;
+ else
+ left = WIFI_GCODE_BUFFER_SIZE + espGcodeFifo.r - espGcodeFifo.w - 1;
+
+ if (left >= strlen((const char *)cmd_line)) {
+ uint32_t index = 0;
+ while (index < strlen((const char *)cmd_line)) {
+ espGcodeFifo.Buffer[espGcodeFifo.w] = cmd_line[index] ;
+ espGcodeFifo.w = (espGcodeFifo.w + 1) % WIFI_GCODE_BUFFER_SIZE;
+ index++;
+ }
+ if (left - WIFI_GCODE_BUFFER_LEAST_SIZE >= strlen((const char *)cmd_line))
+ SEND_OK_TO_WIFI;
+ else
+ need_ok_later = true;
+ }
+ }
+ break;
+ }
+ }
+ else {
+ strcat((char *)cmd_line, "\n");
+
+ if (espGcodeFifo.wait_tick > 5) {
+ uint32_t left_g;
+ if (espGcodeFifo.r > espGcodeFifo.w)
+ left_g = espGcodeFifo.r - espGcodeFifo.w - 1;
+ else
+ left_g = WIFI_GCODE_BUFFER_SIZE + espGcodeFifo.r - espGcodeFifo.w - 1;
+
+ if (left_g >= strlen((const char *)cmd_line)) {
+ uint32_t index = 0;
+ while (index < strlen((const char *)cmd_line)) {
+ espGcodeFifo.Buffer[espGcodeFifo.w] = cmd_line[index] ;
+ espGcodeFifo.w = (espGcodeFifo.w + 1) % WIFI_GCODE_BUFFER_SIZE;
+ index++;
+ }
+ if (left_g - WIFI_GCODE_BUFFER_LEAST_SIZE >= strlen((const char *)cmd_line))
+ SEND_OK_TO_WIFI;
+ else
+ need_ok_later = true;
+ }
+ }
+ }
+ }
+}
+
+static int32_t charAtArray(const uint8_t *_array, uint32_t _arrayLen, uint8_t _char) {
+ for (uint32_t i = 0; i < _arrayLen; i++)
+ if (*(_array + i) == _char) return i;
+ return -1;
+}
+
+void get_wifi_list_command_send() {
+ uint8_t cmd_wifi_list[] = { 0xA5, 0x07, 0x00, 0x00, 0xFC };
+ raw_send_to_wifi(cmd_wifi_list, COUNT(cmd_wifi_list));
+}
+
+static void net_msg_handle(uint8_t * msg, uint16_t msgLen) {
+ int wifiNameLen, wifiKeyLen, hostLen, id_len, ver_len;
+
+ if (msgLen <= 0) return;
+
+ // ip
+ sprintf(ipPara.ip_addr, "%d.%d.%d.%d", msg[0], msg[1], msg[2], msg[3]);
+
+ // port
+ // connect state
+ switch (msg[6]) {
+ case 0x0A: wifi_link_state = WIFI_CONNECTED; break;
+ case 0x0E: wifi_link_state = WIFI_EXCEPTION; break;
+ default: wifi_link_state = WIFI_NOT_CONFIG; break;
+ }
+
+ // mode
+ wifiPara.mode = msg[7];
+
+ // wifi name
+ wifiNameLen = msg[8];
+ wifiKeyLen = msg[9 + wifiNameLen];
+ if (wifiNameLen < 32) {
+ ZERO(wifiPara.ap_name);
+ memcpy(wifiPara.ap_name, &msg[9], wifiNameLen);
+
+ memset(&wifi_list.wifiConnectedName, 0, sizeof(wifi_list.wifiConnectedName));
+ memcpy(&wifi_list.wifiConnectedName, &msg[9], wifiNameLen);
+
+ // wifi key
+ if (wifiKeyLen < 64) {
+ ZERO(wifiPara.keyCode);
+ memcpy(wifiPara.keyCode, &msg[10 + wifiNameLen], wifiKeyLen);
+ }
+ }
+
+ cloud_para.state =msg[10 + wifiNameLen + wifiKeyLen];
+ hostLen = msg[11 + wifiNameLen + wifiKeyLen];
+ if (cloud_para.state) {
+ if (hostLen < 96) {
+ ZERO(cloud_para.hostUrl);
+ memcpy(cloud_para.hostUrl, &msg[12 + wifiNameLen + wifiKeyLen], hostLen);
+ }
+ cloud_para.port = msg[12 + wifiNameLen + wifiKeyLen + hostLen] + (msg[13 + wifiNameLen + wifiKeyLen + hostLen] << 8);
+ }
+
+ // id
+ id_len = msg[14 + wifiNameLen + wifiKeyLen + hostLen];
+ if (id_len == 20) {
+ ZERO(cloud_para.id);
+ memcpy(cloud_para.id, (const char *)&msg[15 + wifiNameLen + wifiKeyLen + hostLen], id_len);
+ }
+ ver_len = msg[15 + wifiNameLen + wifiKeyLen + hostLen + id_len];
+ if (ver_len < 20) {
+ ZERO(wifi_firm_ver);
+ memcpy(wifi_firm_ver, (const char *)&msg[16 + wifiNameLen + wifiKeyLen + hostLen + id_len], ver_len);
+ }
+
+ if (uiCfg.configWifi == 1) {
+ if ((wifiPara.mode != gCfgItems.wifi_mode_sel)
+ || (strncmp(wifiPara.ap_name, (const char *)uiCfg.wifi_name, 32) != 0)
+ || (strncmp(wifiPara.keyCode, (const char *)uiCfg.wifi_key, 64) != 0)) {
+ package_to_wifi(WIFI_PARA_SET, (uint8_t *)0, 0);
+ }
+ else uiCfg.configWifi = 0;
+ }
+ if (cfg_cloud_flag == 1) {
+ if (((cloud_para.state >> 4) != (char)gCfgItems.cloud_enable)
+ || (strncmp(cloud_para.hostUrl, (const char *)uiCfg.cloud_hostUrl, 96) != 0)
+ || (cloud_para.port != uiCfg.cloud_port)) {
+ package_to_wifi(WIFI_CLOUD_CFG, (uint8_t *)0, 0);
+ }
+ else cfg_cloud_flag = 0;
+ }
+}
+
+static void wifi_list_msg_handle(uint8_t * msg, uint16_t msgLen) {
+ int wifiNameLen,wifiMsgIdex = 1;
+ int8_t wifi_name_is_same = 0;
+ int8_t i, j;
+ int8_t wifi_name_num = 0;
+ uint8_t *str = 0;
+ int8_t valid_name_num;
+
+ if (msgLen <= 0) return;
+ if (disp_state == KEY_BOARD_UI) return;
+
+ wifi_list.getNameNum = msg[0];
+
+ if (wifi_list.getNameNum < 20) {
+ uiCfg.command_send = 1;
+ ZERO(wifi_list.wifiName);
+ wifi_name_num = wifi_list.getNameNum;
+ valid_name_num = 0;
+ str = wifi_list.wifiName[0];
+
+ if (wifi_list.getNameNum > 0) wifi_list.currentWifipage = 1;
+
+ for (i = 0; i < wifi_list.getNameNum; i++) {
+ wifiNameLen = msg[wifiMsgIdex++];
+ if (wifiNameLen < 32) {
+ memset(str, 0, WIFI_NAME_BUFFER_SIZE);
+ memcpy(str, &msg[wifiMsgIdex], wifiNameLen);
+ for (j = 0; j < valid_name_num; j++) {
+ if (strcmp((const char *)str,(const char *)wifi_list.wifiName[j]) == 0) {
+ wifi_name_is_same = 1;
+ break;
+ }
+ }
+ if (wifi_name_is_same != 1) {
+ if (str[0] > 0x80) {
+ wifi_name_is_same = 1;
+ }
+ }
+ if (wifi_name_is_same == 1) {
+ wifi_name_is_same = 0;
+ wifiMsgIdex += wifiNameLen;
+ wifiMsgIdex += 1;
+ wifi_name_num--;
+ //i--;
+ continue;
+ }
+ if (i < WIFI_TOTAL_NUMBER - 1)
+ str = wifi_list.wifiName[++valid_name_num];
+ }
+ wifiMsgIdex += wifiNameLen;
+ wifi_list.RSSI[i] = msg[wifiMsgIdex++];
+ }
+ wifi_list.getNameNum = wifi_name_num;
+ wifi_list.getPage = wifi_list.getNameNum / NUMBER_OF_PAGE + ((wifi_list.getNameNum % NUMBER_OF_PAGE) != 0);
+ wifi_list.nameIndex = 0;
+
+ if (disp_state == WIFI_LIST_UI) disp_wifi_list();
+ }
+}
+
+static void gcode_msg_handle(uint8_t * msg, uint16_t msgLen) {
+ uint8_t gcodeBuf[100] = { 0 };
+ char *index_s, *index_e;
+
+ if (msgLen <= 0) return;
+
+ index_s = (char *)msg;
+ index_e = (char *)strchr((char *)msg, '\n');
+ if (*msg == 'N') {
+ index_s = (char *)strchr((char *)msg, ' ');
+ while (*index_s == ' ') index_s++;
+ }
+ while ((index_e != 0) && ((int)index_s < (int)index_e)) {
+ if ((int)(index_e - index_s) < (int)sizeof(gcodeBuf)) {
+ ZERO(gcodeBuf);
+ memcpy(gcodeBuf, index_s, index_e - index_s + 1);
+ wifi_gcode_exec(gcodeBuf);
+ }
+ while ((*index_e == '\r') || (*index_e == '\n')) index_e++;
+ index_s = index_e;
+ index_e = (char *)strchr(index_s, '\n');
+ }
+}
+
+void utf8_2_unicode(uint8_t *source,uint8_t Len) {
+ uint8_t i = 0, char_i = 0, char_byte_num = 0;
+ uint16_t u16_h, u16_m, u16_l, u16_value;
+ uint8_t FileName_unicode[30];
+
+ ZERO(FileName_unicode);
+
+ while (1) {
+ char_byte_num = source[i] & 0xF0;
+ if (source[i] < 0X80) {
+ //ASCII --1byte
+ FileName_unicode[char_i] = source[i];
+ i += 1;
+ char_i += 1;
+ }
+ else if (char_byte_num == 0XC0 || char_byte_num == 0XD0) {
+ //--2byte
+
+ u16_h = (((uint16_t)source[i] << 8) & 0x1F00) >> 2;
+ u16_l = ((uint16_t)source[i + 1] & 0x003F);
+ u16_value = (u16_h | u16_l);
+ FileName_unicode[char_i] = (uint8_t)((u16_value & 0xFF00) >> 8);
+ FileName_unicode[char_i + 1] = (uint8_t)(u16_value & 0x00FF);
+ i += 2;
+ char_i += 2;
+ }
+ else if (char_byte_num == 0XE0) {
+ //--3byte
+ u16_h = (((uint16_t)source[i] << 8) & 0x0F00) << 4;
+ u16_m = (((uint16_t)source[i + 1] << 8) & 0x3F00) >> 2;
+ u16_l = ((uint16_t)source[i + 2] & 0x003F);
+ u16_value = (u16_h | u16_m | u16_l);
+ FileName_unicode[char_i] = (uint8_t)((u16_value & 0xFF00) >> 8);
+ FileName_unicode[char_i + 1] = (uint8_t)(u16_value & 0x00FF);
+ i += 3;
+ char_i += 2;
+ }
+ else if (char_byte_num == 0XF0) {
+ //--4byte
+ i += 4;
+ //char_i += 3;
+ }
+ else {
+ break;
+ }
+ if (i >= Len || i >= 255) break;
+ }
+ COPY(source, FileName_unicode);
+}
+
+static void file_first_msg_handle(uint8_t * msg, uint16_t msgLen) {
+ uint8_t fileNameLen = *msg;
+
+ if (msgLen != fileNameLen + 5) return;
+
+ file_writer.fileLen = *((uint32_t *)(msg + 1));
+ ZERO(file_writer.saveFileName);
+
+ memcpy(file_writer.saveFileName, msg + 5, fileNameLen);
+
+ utf8_2_unicode(file_writer.saveFileName,fileNameLen);
+
+ ZERO(public_buf);
+
+ if (strlen((const char *)file_writer.saveFileName) > sizeof(saveFilePath))
+ return;
+
+ ZERO(saveFilePath);
+
+ if (gCfgItems.fileSysType == FILE_SYS_SD) {
+ TERN_(SDSUPPORT, card.mount());
+ }
+ else if (gCfgItems.fileSysType == FILE_SYS_USB) {
+
+ }
+ file_writer.write_index = 0;
+ lastFragment = -1;
+
+ wifiTransError.flag = 0;
+ wifiTransError.start_tick = 0;
+ wifiTransError.now_tick = 0;
+
+ TERN_(SDSUPPORT, card.closefile());
+
+ wifi_delay(1000);
+
+ #if ENABLED(SDSUPPORT)
+
+ uint8_t dosName[FILENAME_LENGTH];
+
+ if (!longName2DosName((const char *)file_writer.saveFileName,dosName)) {
+ lv_clear_cur_ui();
+ upload_result = 2;
+ wifiTransError.flag = 1;
+ wifiTransError.start_tick = getWifiTick();
+ lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE);
+ return;
+ }
+ sprintf((char *)saveFilePath, "%s", dosName);
+
+ card.cdroot();
+ upload_file.close();
+ const char * const fname = card.diveToFile(true, upload_curDir, saveFilePath);
+
+ if (!upload_file.open(upload_curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) {
+ lv_clear_cur_ui();
+ upload_result = 2;
+
+ wifiTransError.flag = 1;
+ wifiTransError.start_tick = getWifiTick();
+
+ lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE);
+ return;
+ }
+ #endif
+
+ wifi_link_state = WIFI_TRANS_FILE;
+
+ upload_result = 1;
+
+ lv_clear_cur_ui();
+ lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE);
+
+ lv_task_handler();
+
+ file_writer.tick_begin = getWifiTick();
+
+ file_writer.fileTransfer = 1;
+}
+
+#define FRAG_MASK ~(1 << 31)
+
+static void file_fragment_msg_handle(uint8_t * msg, uint16_t msgLen) {
+ uint32_t frag = *((uint32_t *)msg);
+
+ if ((frag & FRAG_MASK) != (uint32_t)(lastFragment + 1)) {
+ ZERO(public_buf);
+ file_writer.write_index = 0;
+ wifi_link_state = WIFI_CONNECTED;
+ upload_result = 2;
+ }
+ else {
+ if (write_to_file((char *)msg + 4, msgLen - 4) < 0) {
+ ZERO(public_buf);
+ file_writer.write_index = 0;
+ wifi_link_state = WIFI_CONNECTED;
+ upload_result = 2;
+ return;
+ }
+ lastFragment = frag;
+
+ if ((frag & (~FRAG_MASK)) != 0) {
+ wifiDmaRcvFifo.receiveEspData = false;
+ int res = upload_file.write(public_buf, file_writer.write_index);
+ if (res == -1) {
+ upload_file.close();
+ const char * const fname = card.diveToFile(true, upload_curDir, saveFilePath);
+
+ if (upload_file.open(upload_curDir, fname, O_WRITE)) {
+ upload_file.setpos(&pos);
+ res = upload_file.write(public_buf, file_writer.write_index);
+ }
+ }
+ upload_file.close();
+ SdFile file, *curDir;
+ const char * const fname = card.diveToFile(true, curDir, saveFilePath);
+ if (file.open(curDir, fname, O_RDWR)) {
+ gCfgItems.curFilesize = file.fileSize();
+ file.close();
+ }
+ else {
+ ZERO(public_buf);
+ file_writer.write_index = 0;
+ wifi_link_state = WIFI_CONNECTED;
+ upload_result = 2;
+ return;
+ }
+ ZERO(public_buf);
+ file_writer.write_index = 0;
+ file_writer.tick_end = getWifiTick();
+ upload_time = getWifiTickDiff(file_writer.tick_begin, file_writer.tick_end) / 1000;
+ upload_size = gCfgItems.curFilesize;
+ wifi_link_state = WIFI_CONNECTED;
+ upload_result = 3;
+ }
+
+ }
+}
+
+void esp_data_parser(char *cmdRxBuf, int len) {
+ int32_t head_pos;
+ int32_t tail_pos;
+ uint16_t cpyLen;
+ int16_t leftLen = len;
+ bool loop_again = false;
+
+ ESP_PROTOC_FRAME esp_frame;
+
+ while (leftLen > 0 || loop_again) {
+ loop_again = false;
+
+ if (esp_msg_index != 0) {
+ head_pos = 0;
+ cpyLen = (leftLen < (int16_t)((sizeof(esp_msg_buf) - esp_msg_index)) ? leftLen : sizeof(esp_msg_buf) - esp_msg_index);
+
+ memcpy(&esp_msg_buf[esp_msg_index], cmdRxBuf + len - leftLen, cpyLen);
+
+ esp_msg_index += cpyLen;
+
+ leftLen = leftLen - cpyLen;
+ tail_pos = charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_TAIL);
+
+ if (tail_pos == -1) {
+ if (esp_msg_index >= sizeof(esp_msg_buf)) {
+ ZERO(esp_msg_buf);
+ esp_msg_index = 0;
+ }
+ return;
+ }
+ }
+ else {
+ head_pos = charAtArray((uint8_t const *)&cmdRxBuf[len - leftLen], leftLen, ESP_PROTOC_HEAD);
+ if (head_pos == -1) return;
+
+ ZERO(esp_msg_buf);
+ memcpy(esp_msg_buf, &cmdRxBuf[len - leftLen + head_pos], leftLen - head_pos);
+
+ esp_msg_index = leftLen - head_pos;
+
+ leftLen = 0;
+ head_pos = 0;
+ tail_pos = charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_TAIL);
+ if (tail_pos == -1) {
+ if (esp_msg_index >= sizeof(esp_msg_buf)) {
+ ZERO(esp_msg_buf);
+ esp_msg_index = 0;
+ }
+ return;
+ }
+ }
+
+ esp_frame.type = esp_msg_buf[1];
+ if ( esp_frame.type != ESP_TYPE_NET
+ && esp_frame.type != ESP_TYPE_GCODE
+ && esp_frame.type != ESP_TYPE_FILE_FIRST
+ && esp_frame.type != ESP_TYPE_FILE_FRAGMENT
+ && esp_frame.type != ESP_TYPE_WIFI_LIST
+ ) {
+ ZERO(esp_msg_buf);
+ esp_msg_index = 0;
+ return;
+ }
+
+ esp_frame.dataLen = esp_msg_buf[2] + (esp_msg_buf[3] << 8);
+
+ if ((int)(4 + esp_frame.dataLen) > (int)(sizeof(esp_msg_buf))) {
+ ZERO(esp_msg_buf);
+ esp_msg_index = 0;
+ return;
+ }
+
+ if (esp_msg_buf[4 + esp_frame.dataLen] != ESP_PROTOC_TAIL) {
+ if (esp_msg_index >= sizeof(esp_msg_buf)) {
+ ZERO(esp_msg_buf);
+ esp_msg_index = 0;
+ }
+ return;
+ }
+
+ esp_frame.data = &esp_msg_buf[4];
+ switch (esp_frame.type) {
+ case ESP_TYPE_NET:
+ net_msg_handle(esp_frame.data, esp_frame.dataLen);
+ break;
+ case ESP_TYPE_GCODE:
+ gcode_msg_handle(esp_frame.data, esp_frame.dataLen);
+ break;
+ case ESP_TYPE_FILE_FIRST:
+ file_first_msg_handle(esp_frame.data, esp_frame.dataLen);
+ break;
+ case ESP_TYPE_FILE_FRAGMENT:
+ file_fragment_msg_handle(esp_frame.data, esp_frame.dataLen);
+ break;
+ case ESP_TYPE_WIFI_LIST:
+ wifi_list_msg_handle(esp_frame.data, esp_frame.dataLen);
+ break;
+ default: break;
+ }
+
+ esp_msg_index = cut_msg_head(esp_msg_buf, esp_msg_index, esp_frame.dataLen + 5);
+ if (esp_msg_index > 0) {
+ if (charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_HEAD) == -1) {
+ ZERO(esp_msg_buf);
+ esp_msg_index = 0;
+ return;
+ }
+
+ if ((charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_HEAD) != -1) && (charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_TAIL) != -1))
+ loop_again = true;
+ }
+ }
+}
+
+int32_t tick_net_time1, tick_net_time2;
+int32_t readWifiFifo(uint8_t *retBuf, uint32_t bufLen) {
+ unsigned char tmpR = wifiDmaRcvFifo.read_cur;
+ if (bufLen >= UDISKBUFLEN && wifiDmaRcvFifo.state[tmpR] == udisk_buf_full) {
+ memcpy(retBuf, (unsigned char *)wifiDmaRcvFifo.bufferAddr[tmpR], UDISKBUFLEN);
+ wifiDmaRcvFifo.state[tmpR] = udisk_buf_empty;
+ wifiDmaRcvFifo.read_cur = (tmpR + 1) % TRANS_RCV_FIFO_BLOCK_NUM;
+ return UDISKBUFLEN;
+ }
+ return 0;
+}
+
+void stopEspTransfer() {
+ if (wifi_link_state == WIFI_TRANS_FILE)
+ wifi_link_state = WIFI_CONNECTED;
+
+ TERN_(SDSUPPORT, card.closefile());
+
+ if (upload_result != 3) {
+ wifiTransError.flag = 1;
+ wifiTransError.start_tick = getWifiTick();
+ card.removeFile((const char *)saveFilePath);
+ }
+
+ wifi_delay(200);
+
+ WIFI_IO1_SET();
+
+ // disable dma
+ #ifdef __STM32F1__
+ dma_clear_isr_bits(DMA1, DMA_CH5);
+ bb_peri_set_bit(&USART1_BASE->CR3, USART_CR3_DMAR_BIT, 0);
+ dma_disable(DMA1, DMA_CH5);
+ #else
+ // First, abort any running dma
+ HAL_DMA_Abort(&wifiUsartDMArx);
+ // DeInit objects
+ HAL_DMA_DeInit(&wifiUsartDMArx);
+ #endif
+
+ wifi_delay(200);
+
+ exchangeFlashMode(1); //change spi flash to use dma mode
+
+ esp_port_begin(1);
+
+ wifi_delay(200);
+
+ W25QXX.init(SPI_QUARTER_SPEED);
+
+ #if HAS_TFT_LVGL_UI_SPI
+ SPI_TFT.spi_init(SPI_FULL_SPEED);
+ #endif
+
+ TERN_(HAS_SERVOS, servo_init());
+
+ TERN_(HAS_Z_SERVO_PROBE, probe.servo_probe_init());
+
+ if (wifiTransError.flag != 0x1)
+ WIFI_IO1_RESET();
+}
+
+void wifi_rcv_handle() {
+ int32_t len = 0;
+ uint8_t ucStr[(UART_RX_BUFFER_SIZE) + 1] = {0};
+ int8_t getDataF = 0;
+
+ if (wifi_link_state == WIFI_TRANS_FILE) {
+ #if 0
+ if (WIFISERIAL.available() == UART_RX_BUFFER_SIZE) {
+ for (uint16_t i=0;i<UART_RX_BUFFER_SIZE;i++) {
+ ucStr[i] = WIFISERIAL.read();
+ len++;
+ }
+ }
+ #else
+ #ifndef __STM32F1__
+ if (wifiDmaRcvFifo.receiveEspData) storeRcvData(WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE);
+ #endif
+ len = readWifiFifo(ucStr, UART_RX_BUFFER_SIZE);
+ #endif
+ if (len > 0) {
+ esp_data_parser((char *)ucStr, len);
+ if (wifi_link_state == WIFI_CONNECTED) {
+ lv_clear_cur_ui();
+ lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE);
+ stopEspTransfer();
+ }
+ getDataF = 1;
+ }
+ #ifdef __STM32F1__
+ if (esp_state == TRANSFER_STORE) {
+ if (storeRcvData(WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE)) {
+ esp_state = TRANSFERING;
+ esp_dma_pre();
+ if (wifiTransError.flag != 0x1) WIFI_IO1_RESET();
+ }
+ else WIFI_IO1_SET();
+ }
+ #endif
+ }
+ else {
+ len = readWifiBuf((int8_t *)ucStr, UART_RX_BUFFER_SIZE);
+ if (len > 0) {
+ esp_data_parser((char *)ucStr, len);
+
+ if (wifi_link_state == WIFI_TRANS_FILE) {
+ exchangeFlashMode(0); //change spi flash not use dma mode
+
+ wifi_delay(10);
+
+ esp_port_begin(0);
+
+ wifi_delay(10);
+
+ tick_net_time1 = 0;
+ #ifndef __STM32F1__
+ wifiDmaRcvFifo.receiveEspData = true;
+ return;
+ #endif
+ }
+ if (wifiTransError.flag != 0x1) {
+ WIFI_IO1_RESET();
+ }
+ getDataF = 1;
+ }
+ if (need_ok_later && (queue.length < BUFSIZE)) {
+ need_ok_later = false;
+ send_to_wifi((uint8_t *)"ok\r\n", strlen("ok\r\n"));
+ }
+ }
+
+ if (getDataF == 1) {
+ tick_net_time1 = getWifiTick();
+ }
+ else {
+ tick_net_time2 = getWifiTick();
+
+ if (wifi_link_state == WIFI_TRANS_FILE) {
+ if ((tick_net_time1 != 0) && (getWifiTickDiff(tick_net_time1, tick_net_time2) > 8000)) {
+ wifi_link_state = WIFI_CONNECTED;
+
+ upload_result = 2;
+
+ lv_clear_cur_ui();
+
+ stopEspTransfer();
+
+ lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE);
+ }
+ }
+ if ((tick_net_time1 != 0) && (getWifiTickDiff(tick_net_time1, tick_net_time2) > 10000)) {
+ wifi_link_state = WIFI_NOT_CONFIG;
+ }
+ if ((tick_net_time1 != 0) && (getWifiTickDiff(tick_net_time1, tick_net_time2) > 120000)) {
+ wifi_link_state = WIFI_NOT_CONFIG;
+
+ wifi_reset();
+
+ tick_net_time1 = getWifiTick();
+ }
+ }
+
+ if (wifiTransError.flag == 0x1) {
+ wifiTransError.now_tick = getWifiTick();
+ if (getWifiTickDiff(wifiTransError.start_tick, wifiTransError.now_tick) > WAIT_ESP_TRANS_TIMEOUT_TICK) {
+ wifiTransError.flag = 0;
+ WIFI_IO1_RESET();
+ }
+ }
+}
+
+void wifi_looping() {
+ do {
+ wifi_rcv_handle();
+ watchdog_refresh();
+ } while (wifi_link_state == WIFI_TRANS_FILE);
+}
+
+void mks_esp_wifi_init() {
+ wifi_link_state = WIFI_NOT_CONFIG;
+
+ SET_OUTPUT(WIFI_RESET_PIN);
+ WIFI_SET();
+ SET_OUTPUT(WIFI_IO1_PIN);
+ SET_INPUT_PULLUP(WIFI_IO0_PIN);
+ WIFI_IO1_SET();
+
+ esp_state = TRANSFER_IDLE;
+ esp_port_begin(1);
+
+ wifi_reset();
+
+ #if 0
+ if (update_flag == 0) {
+ res = f_open(&esp_upload.uploadFile, ESP_WEB_FIRMWARE_FILE, FA_OPEN_EXISTING | FA_READ);
+
+ if (res == FR_OK) {
+ f_close(&esp_upload.uploadFile);
+
+ wifi_delay(2000);
+
+ if (usartFifoAvailable((SZ_USART_FIFO *)&WifiRxFifo) < 20) {
+ return;
+ }
+
+ lv_clear_cur_ui();
+
+ draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMARE);
+ if (wifi_upload(1) >= 0) {
+
+ f_unlink("1:/MKS_WIFI_CUR");
+ f_rename(ESP_WEB_FIRMWARE_FILE,"/MKS_WIFI_CUR");
+ }
+ lv_draw_return_ui();
+ update_flag = 1;
+ }
+
+ }
+ if (update_flag == 0) {
+ res = f_open(&esp_upload.uploadFile, ESP_WEB_FILE, FA_OPEN_EXISTING | FA_READ);
+ if (res == FR_OK) {
+ f_close(&esp_upload.uploadFile);
+
+ wifi_delay(2000);
+
+ if (usartFifoAvailable((SZ_USART_FIFO *)&WifiRxFifo) < 20) {
+ return;
+ }
+
+ lv_clear_cur_ui();
+
+ draw_dialog(DIALOG_TYPE_UPDATE_ESP_DATA);
+
+ if (wifi_upload(2) >= 0) {
+
+ f_unlink("1:/MKS_WEB_CONTROL_CUR");
+ f_rename(ESP_WEB_FILE,"/MKS_WEB_CONTROL_CUR");
+ }
+ lv_draw_return_ui();
+ }
+ }
+ #endif
+ wifiPara.decodeType = WIFI_DECODE_TYPE;
+ wifiPara.baud = 115200;
+ wifi_link_state = WIFI_NOT_CONFIG;
+}
+
+
+void mks_wifi_firmware_upddate() {
+ card.openFileRead((char *)ESP_FIRMWARE_FILE);
+
+ if (card.isFileOpen()) {
+ card.closefile();
+
+ wifi_delay(2000);
+
+ if (usartFifoAvailable((SZ_USART_FIFO *)&WifiRxFifo) < 20)
+ return;
+
+ lv_clear_cur_ui();
+
+ lv_draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMARE);
+
+ lv_task_handler();
+ watchdog_refresh();
+
+ if (wifi_upload(0) >= 0) {
+ card.removeFile((char *)ESP_FIRMWARE_FILE_RENAME);
+ SdFile file, *curDir;
+ const char * const fname = card.diveToFile(true, curDir, ESP_FIRMWARE_FILE);
+ if (file.open(curDir, fname, O_READ)) {
+ file.rename(curDir, (char *)ESP_FIRMWARE_FILE_RENAME);
+ file.close();
+ }
+ }
+ lv_clear_cur_ui();
+ }
+}
+
+void get_wifi_commands() {
+ static char wifi_line_buffer[MAX_CMD_SIZE];
+ static bool wifi_comment_mode = false;
+ static int wifi_read_count = 0;
+
+ if (espGcodeFifo.wait_tick > 5) {
+ while ((queue.length < BUFSIZE) && (espGcodeFifo.r != espGcodeFifo.w)) {
+
+ espGcodeFifo.wait_tick = 0;
+
+ char wifi_char = espGcodeFifo.Buffer[espGcodeFifo.r];
+
+ espGcodeFifo.r = (espGcodeFifo.r + 1) % WIFI_GCODE_BUFFER_SIZE;
+
+ /**
+ * If the character ends the line
+ */
+ if (wifi_char == '\n' || wifi_char == '\r') {
+
+ wifi_comment_mode = false; // end of line == end of comment
+
+ if (!wifi_read_count) continue; // skip empty lines
+
+ wifi_line_buffer[wifi_read_count] = 0; // terminate string
+ wifi_read_count = 0; //reset buffer
+
+ char* command = wifi_line_buffer;
+ while (*command == ' ') command++; // skip any leading spaces
+
+ // Movement commands alert when stopped
+ if (IsStopped()) {
+ char* gpos = strchr(command, 'G');
+ if (gpos) {
+ switch (strtol(gpos + 1, nullptr, 10)) {
+ case 0 ... 1:
+ #if ENABLED(ARC_SUPPORT)
+ case 2 ... 3:
+ #endif
+ #if ENABLED(BEZIER_CURVE_SUPPORT)
+ case 5:
+ #endif
+ SERIAL_ECHOLNPGM(STR_ERR_STOPPED);
+ LCD_MESSAGEPGM(MSG_STOPPED);
+ break;
+ }
+ }
+ }
+
+ #if DISABLED(EMERGENCY_PARSER)
+ // Process critical commands early
+ if (strcmp(command, "M108") == 0) {
+ wait_for_heatup = false;
+ TERN_(HAS_LCD_MENU, wait_for_user = false);
+ }
+ if (strcmp(command, "M112") == 0) kill(M112_KILL_STR, nullptr, true);
+ if (strcmp(command, "M410") == 0) quickstop_stepper();
+ #endif
+
+ // Add the command to the queue
+ queue.enqueue_one_P(wifi_line_buffer);
+ }
+ else if (wifi_read_count >= MAX_CMD_SIZE - 1) {
+
+ }
+ else { // it's not a newline, carriage return or escape char
+ if (wifi_char == ';') wifi_comment_mode = true;
+ if (!wifi_comment_mode) wifi_line_buffer[wifi_read_count++] = wifi_char;
+ }
+ }
+ } // queue has space, serial has data
+ else
+ espGcodeFifo.wait_tick++;
+}
+
+int readWifiBuf(int8_t *buf, int32_t len) {
+ int i = 0;
+ while (i < len && WIFISERIAL.available())
+ buf[i++] = WIFISERIAL.read();
+ return i;
+}
+
+int usartFifoAvailable(SZ_USART_FIFO *fifo) {
+ return WIFISERIAL.available();
+}
+
+#endif // MKS_WIFI_MODULE
+#endif // HAS_TFT_LVGL_UI
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.h b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.h
new file mode 100644
index 0000000..856c619
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.h
@@ -0,0 +1,201 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define UART_RX_BUFFER_SIZE 1024
+#define UART_FIFO_BUFFER_SIZE 1024
+
+#define WIFI_DECODE_TYPE 1
+
+#define IP_DHCP_FLAG 1
+
+#define WIFI_AP_NAME "TP-LINK_MKS"
+#define WIFI_KEY_CODE "makerbase"
+
+#define IP_ADDR "192.168.3.100"
+#define IP_MASK "255.255.255.0"
+#define IP_GATE "192.168.3.1"
+#define IP_DNS "192.168.3.1"
+
+#define AP_IP_DHCP_FLAG 1
+#define AP_IP_ADDR "192.168.3.100"
+#define AP_IP_MASK "255.255.255.0"
+#define AP_IP_GATE "192.168.3.1"
+#define AP_IP_DNS "192.168.3.1"
+#define IP_START_IP "192.168.3.1"
+#define IP_END_IP "192.168.3.255"
+
+#define UDISKBUFLEN 1024
+
+typedef enum{
+ udisk_buf_empty = 0,
+ udisk_buf_full,
+} UDISK_DATA_BUFFER_STATE;
+
+#define TRANS_RCV_FIFO_BLOCK_NUM 14
+
+typedef struct {
+ bool receiveEspData;
+ unsigned char *bufferAddr[TRANS_RCV_FIFO_BLOCK_NUM];
+ unsigned char *p;
+ UDISK_DATA_BUFFER_STATE state[TRANS_RCV_FIFO_BLOCK_NUM];
+ unsigned char read_cur;
+ unsigned char write_cur;
+} WIFI_DMA_RCV_FIFO;
+
+typedef struct {
+ uint8_t flag; // 0x0: no error; 0x01: error
+ uint32_t start_tick; //error start time
+ uint32_t now_tick;
+} WIFI_TRANS_ERROR;
+
+extern volatile WIFI_TRANS_ERROR wifiTransError;
+
+typedef struct {
+ char ap_name[32]; //wifi-name
+ char keyCode[64]; //wifi password
+ int decodeType;
+ int baud;
+ int mode;
+} WIFI_PARA;
+
+typedef struct {
+ char state;
+ char hostUrl[96];
+ int port;
+ char id[21];
+} CLOUD_PARA;
+
+typedef struct {
+ char dhcp_flag;
+ char ip_addr[16];
+ char mask[16];
+ char gate[16];
+ char dns[16];
+
+ char dhcpd_flag;
+ char dhcpd_ip[16];
+ char dhcpd_mask[16];
+ char dhcpd_gate[16];
+ char dhcpd_dns[16];
+ char start_ip_addr[16];
+ char end_ip_addr[16];
+} IP_PARA;
+
+typedef enum {
+ WIFI_NOT_CONFIG,
+ WIFI_CONFIG_MODE,
+ WIFI_CONFIG_DHCP,
+ WIFI_CONFIG_AP,
+ WIFI_CONFIG_IP_INF,
+ WIFI_CONFIG_DNS,
+ WIFI_CONFIG_TCP,
+ WIFI_CONFIG_SERVER,
+ WIFI_CONFIG_REMOTE_PORT,
+ WIFI_CONFIG_BAUD,
+ WIFI_CONFIG_COMMINT,
+ WIFI_CONFIG_OK,
+ WIFI_GET_IP_OK,
+ WIFI_RECONN,
+ WIFI_CONNECTED,
+ WIFI_WAIT_TRANS_START,
+ WIFI_TRANS_FILE,
+ WIFI_CONFIG_DHCPD,
+ WIFI_COFIG_DHCPD_IP,
+ WIFI_COFIG_DHCPD_DNS,
+ WIFI_EXCEPTION,
+} WIFI_STATE;
+
+typedef enum {
+ TRANSFER_IDLE,
+ TRANSFERING,
+ TRANSFER_STORE,
+} TRANSFER_STATE;
+extern volatile TRANSFER_STATE esp_state;
+
+typedef struct {
+ char buf[20][80];
+ int rd_index;
+ int wt_index;
+} QUEUE;
+
+typedef enum {
+ WIFI_PARA_SET, // 0x0:net parameter
+ WIFI_PRINT_INF, // 0x1:print message
+ WIFI_TRANS_INF, // 0x2:Pass through information
+ WIFI_EXCEP_INF, // 0x3:Exception information
+ WIFI_CLOUD_CFG, // 0x4:cloud config
+ WIFI_CLOUD_UNBIND, // 0x5:Unbind ID
+} WIFI_RET_TYPE;
+
+typedef struct {
+ uint32_t uart_read_point;
+ uint32_t uart_write_point;
+ //uint8_t uartTxBuffer[UART_FIFO_BUFFER_SIZE];
+} SZ_USART_FIFO;
+
+#define WIFI_GCODE_BUFFER_LEAST_SIZE 96
+#define WIFI_GCODE_BUFFER_SIZE (WIFI_GCODE_BUFFER_LEAST_SIZE * 3)
+typedef struct {
+ uint8_t wait_tick;
+ uint8_t Buffer[WIFI_GCODE_BUFFER_SIZE];
+ uint32_t r;
+ uint32_t w;
+} WIFI_GCODE_BUFFER;
+
+extern volatile WIFI_STATE wifi_link_state;
+extern WIFI_PARA wifiPara;
+extern IP_PARA ipPara;
+extern CLOUD_PARA cloud_para;
+
+extern WIFI_GCODE_BUFFER espGcodeFifo;
+
+extern uint32_t getWifiTick();
+extern uint32_t getWifiTickDiff(int32_t lastTick, int32_t curTick);
+
+extern void mks_esp_wifi_init();
+extern int cfg_cloud_flag;
+extern int send_to_wifi(uint8_t *buf, int len);
+extern void wifi_looping();
+extern int raw_send_to_wifi(uint8_t *buf, int len);
+extern int package_to_wifi(WIFI_RET_TYPE type, uint8_t *buf, int len);
+extern void get_wifi_list_command_send();
+extern void get_wifi_commands();
+extern int readWifiBuf(int8_t *buf, int32_t len);
+extern void mks_wifi_firmware_upddate();
+extern int usartFifoAvailable(SZ_USART_FIFO *fifo);
+extern int readUsartFifo(SZ_USART_FIFO *fifo, int8_t *buf, int32_t len);
+extern void esp_port_begin(uint8_t interrupt);
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp
new file mode 100644
index 0000000..da35254
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp
@@ -0,0 +1,726 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if BOTH(HAS_TFT_LVGL_UI, MKS_WIFI_MODULE)
+
+#include "draw_ui.h"
+#include "wifi_module.h"
+#include "wifi_upload.h"
+
+#include "../../../../MarlinCore.h"
+#include "../../../../sd/cardreader.h"
+
+#define WIFI_SET() WRITE(WIFI_RESET_PIN, HIGH);
+#define WIFI_RESET() WRITE(WIFI_RESET_PIN, LOW);
+#define WIFI_IO1_SET() WRITE(WIFI_IO1_PIN, HIGH);
+#define WIFI_IO1_RESET() WRITE(WIFI_IO1_PIN, LOW);
+
+extern SZ_USART_FIFO WifiRxFifo;
+
+extern int readUsartFifo(SZ_USART_FIFO *fifo, int8_t *buf, int32_t len);
+extern int writeUsartFifo(SZ_USART_FIFO * fifo, int8_t * buf, int32_t len);
+extern void esp_port_begin(uint8_t interrupt);
+extern void wifi_delay(int n);
+
+#define ARRAY_SIZE(a) sizeof(a) / sizeof((a)[0])
+
+//typedef signed char bool;
+
+// ESP8266 command codes
+const uint8_t ESP_FLASH_BEGIN = 0x02;
+const uint8_t ESP_FLASH_DATA = 0x03;
+const uint8_t ESP_FLASH_END = 0x04;
+const uint8_t ESP_MEM_BEGIN = 0x05;
+const uint8_t ESP_MEM_END = 0x06;
+const uint8_t ESP_MEM_DATA = 0x07;
+const uint8_t ESP_SYNC = 0x08;
+const uint8_t ESP_WRITE_REG = 0x09;
+const uint8_t ESP_READ_REG = 0x0A;
+
+// MAC address storage locations
+const uint32_t ESP_OTP_MAC0 = 0x3FF00050;
+const uint32_t ESP_OTP_MAC1 = 0x3FF00054;
+const uint32_t ESP_OTP_MAC2 = 0x3FF00058;
+const uint32_t ESP_OTP_MAC3 = 0x3FF0005C;
+
+const size_t EspFlashBlockSize = 0x0400; // 1K byte blocks
+
+const uint8_t ESP_IMAGE_MAGIC = 0xE9;
+const uint8_t ESP_CHECKSUM_MAGIC = 0xEF;
+
+const uint32_t ESP_ERASE_CHIP_ADDR = 0x40004984; // &SPIEraseChip
+const uint32_t ESP_SEND_PACKET_ADDR = 0x40003C80; // &send_packet
+const uint32_t ESP_SPI_READ_ADDR = 0x40004B1C; // &SPIRead
+const uint32_t ESP_UNKNOWN_ADDR = 0x40001121; // not used
+const uint32_t ESP_USER_DATA_RAM_ADDR = 0x3FFE8000; // &user data ram
+const uint32_t ESP_IRAM_ADDR = 0x40100000; // instruction RAM
+const uint32_t ESP_FLASH_ADDR = 0x40200000; // address of start of Flash
+
+UPLOAD_STRUCT esp_upload;
+
+static const unsigned int retriesPerReset = 3;
+static const uint32_t connectAttemptInterval = 50;
+static const unsigned int percentToReportIncrement = 5; // how often we report % complete
+static const uint32_t defaultTimeout = 500;
+static const uint32_t eraseTimeout = 15000;
+static const uint32_t blockWriteTimeout = 200;
+static const uint32_t blockWriteInterval = 15; // 15ms is long enough, 10ms is mostly too short
+static SdFile update_file, *update_curDir;
+
+// Messages corresponding to result codes, should make sense when followed by " error"
+const char *resultMessages[] = {
+ "no",
+ "timeout",
+ "comm write",
+ "connect",
+ "bad reply",
+ "file read",
+ "empty file",
+ "response header",
+ "slip frame",
+ "slip state",
+ "slip data"
+};
+
+// A note on baud rates.
+// The ESP8266 supports 921600, 460800, 230400, 115200, 74880 and some lower baud rates.
+// 921600b is not reliable because even though it sometimes succeeds in connecting, we get a bad response during uploading after a few blocks.
+// Probably our UART ISR cannot receive bytes fast enough, perhaps because of the latency of the system tick ISR.
+// 460800b doesn't always manage to connect, but if it does then uploading appears to be reliable.
+// 230400b always manages to connect.
+static const uint32_t uploadBaudRates[] = { 460800, 230400, 115200, 74880 };
+
+signed char IsReady() {
+ return esp_upload.state == upload_idle;
+}
+
+void uploadPort_write(const uint8_t *buf, size_t len) {
+ for(size_t i = 0; i < len; i++) {
+ WIFISERIAL.write(*(buf + i));
+ }
+}
+
+char uploadPort_read() {
+ uint8_t retChar;
+ retChar = WIFISERIAL.read();
+ if (retChar > 0) return retChar;
+ else return 0;
+}
+
+int uploadPort_available() {
+ return usartFifoAvailable(&WifiRxFifo);
+}
+
+void uploadPort_begin() {
+ esp_port_begin(1);
+}
+
+void uploadPort_close() {
+ //WIFI_COM.end();
+ //WIFI_COM.begin(115200, true);
+ esp_port_begin(0);
+}
+
+void flushInput() {
+ while (uploadPort_available() != 0) {
+ (void)uploadPort_read();
+ //IWDG_ReloadCounter();
+ }
+}
+
+// Extract 1-4 bytes of a value in little-endian order from a buffer beginning at a specified offset
+uint32_t getData(unsigned byteCnt, const uint8_t *buf, int ofst) {
+ uint32_t val = 0;
+
+ if (buf && byteCnt) {
+ unsigned int shiftCnt = 0;
+ if (byteCnt > 4)
+ byteCnt = 4;
+ do{
+ val |= (uint32_t)buf[ofst++] << shiftCnt;
+ shiftCnt += 8;
+ } while (--byteCnt);
+ }
+ return(val);
+}
+
+// Put 1-4 bytes of a value in little-endian order into a buffer beginning at a specified offset.
+void putData(uint32_t val, unsigned byteCnt, uint8_t *buf, int ofst) {
+ if (buf && byteCnt) {
+ if (byteCnt > 4) {
+ byteCnt = 4;
+ }
+ do {
+ buf[ofst++] = (uint8_t)(val & 0xFF);
+ val >>= 8;
+ } while (--byteCnt);
+ }
+}
+
+// Read a byte optionally performing SLIP decoding. The return values are:
+//
+// 2 - an escaped byte was read successfully
+// 1 - a non-escaped byte was read successfully
+// 0 - no data was available
+// -1 - the value 0xC0 was encountered (shouldn't happen)
+// -2 - a SLIP escape byte was found but the following byte wasn't available
+// -3 - a SLIP escape byte was followed by an invalid byte
+int ReadByte(uint8_t *data, signed char slipDecode) {
+ if (uploadPort_available() == 0) {
+ return(0);
+ }
+
+ // at least one byte is available
+ *data = uploadPort_read();
+ if (!slipDecode) {
+ return(1);
+ }
+
+ if (*data == 0xC0) {
+ // this shouldn't happen
+ return(-1);
+ }
+
+ // if not the SLIP escape, we're done
+ if (*data != 0xDB) {
+ return(1);
+ }
+
+ // SLIP escape, check availability of subsequent byte
+ if (uploadPort_available() == 0) {
+ return(-2);
+ }
+
+ // process the escaped byte
+ *data = uploadPort_read();
+ if (*data == 0xDC) {
+ *data = 0xC0;
+ return(2);
+ }
+
+ if (*data == 0xDD) {
+ *data = 0xDB;
+ return(2);
+ }
+ // invalid
+ return(-3);
+}
+// When we write a sync packet, there must be no gaps between most of the characters.
+// So use this function, which does a block write to the UART buffer in the latest CoreNG.
+void _writePacketRaw(const uint8_t *buf, size_t len) {
+ uploadPort_write(buf, len);
+}
+
+// Write a byte to the serial port optionally SLIP encoding. Return the number of bytes actually written.
+void WriteByteRaw(uint8_t b) {
+ uploadPort_write((const uint8_t *)&b, 1);
+}
+
+// Write a byte to the serial port optionally SLIP encoding. Return the number of bytes actually written.
+void WriteByteSlip(uint8_t b) {
+ if (b == 0xC0) {
+ WriteByteRaw(0xDB);
+ WriteByteRaw(0xDC);
+ }
+ else if (b == 0xDB) {
+ WriteByteRaw(0xDB);
+ WriteByteRaw(0xDD);
+ }
+ else {
+ uploadPort_write((const uint8_t *)&b, 1);
+ }
+}
+
+// Wait for a data packet to be returned. If the body of the packet is
+// non-zero length, return an allocated buffer indirectly containing the
+// data and return the data length. Note that if the pointer for returning
+// the data buffer is nullptr, the response is expected to be two bytes of zero.
+//
+// If an error occurs, return a negative value. Otherwise, return the number
+// of bytes in the response (or zero if the response was not the standard "two bytes of zero").
+EspUploadResult readPacket(uint8_t op, uint32_t *valp, size_t *bodyLen, uint32_t msTimeout) {
+ typedef enum {
+ begin = 0,
+ header,
+ body,
+ end,
+ done
+ } PacketState;
+
+ uint8_t resp, opRet;
+
+ const size_t headerLength = 8;
+
+ uint32_t startTime = getWifiTick();
+ uint8_t hdr[headerLength];
+ uint16_t hdrIdx = 0;
+
+ uint16_t bodyIdx = 0;
+ uint8_t respBuf[2];
+
+ // wait for the response
+ uint16_t needBytes = 1;
+
+ PacketState state = begin;
+
+ *bodyLen = 0;
+
+ while (state != done) {
+ uint8_t c;
+ EspUploadResult stat;
+
+ //IWDG_ReloadCounter();
+ watchdog_refresh();
+
+ if (getWifiTickDiff(startTime, getWifiTick()) > msTimeout)
+ return timeout;
+
+ if (uploadPort_available() < needBytes) {
+ // insufficient data available
+ // preferably, return to Spin() here
+ continue;
+ }
+
+ // sufficient bytes have been received for the current state, process them
+ switch (state) {
+ case begin: // expecting frame start
+ c = uploadPort_read();
+ if (c != (uint8_t)0xC0) break;
+ state = header;
+ needBytes = 2;
+ break;
+ case end: // expecting frame end
+ c = uploadPort_read();
+ if (c != (uint8_t)0xC0) return slipFrame;
+ state = done;
+ break;
+
+ case header: // reading an 8-byte header
+ case body: { // reading the response body
+ int rslt;
+ // retrieve a byte with SLIP decoding
+ rslt = ReadByte(&c, 1);
+ if (rslt != 1 && rslt != 2) {
+ // some error occurred
+ stat = (rslt == 0 || rslt == -2) ? slipData : slipFrame;
+ return stat;
+ }
+ else if (state == header) {
+ //store the header byte
+ hdr[hdrIdx++] = c;
+ if (hdrIdx >= headerLength) {
+ // get the body length, prepare a buffer for it
+ *bodyLen = (uint16_t)getData(2, hdr, 2);
+
+ // extract the value, if requested
+ if (valp)
+ *valp = getData(4, hdr, 4);
+
+ if (*bodyLen != 0)
+ state = body;
+ else {
+ needBytes = 1;
+ state = end;
+ }
+ }
+ }
+ else {
+ // Store the response body byte, check for completion
+ if (bodyIdx < ARRAY_SIZE(respBuf))
+ respBuf[bodyIdx] = c;
+
+ if (++bodyIdx >= *bodyLen) {
+ needBytes = 1;
+ state = end;
+ }
+ }
+ } break;
+
+ default: return slipState; // this shouldn't happen
+ }
+ }
+
+ // Extract elements from the header
+ resp = (uint8_t)getData(1, hdr, 0);
+ opRet = (uint8_t)getData(1, hdr, 1);
+ // Sync packets often provoke a response with a zero opcode instead of ESP_SYNC
+ if (resp != 0x01 || opRet != op) {
+ return respHeader;
+ }
+
+ return success;
+}
+
+// Send a block of data performing SLIP encoding of the content.
+void _writePacket(const uint8_t *data, size_t len) {
+ unsigned char outBuf[2048] = {0};
+ unsigned int outIndex = 0;
+ while (len != 0) {
+ if (*data == 0xC0) {
+ outBuf[outIndex++] = 0xDB;
+ outBuf[outIndex++] = 0xDC;
+ }
+ else if (*data == 0xDB) {
+ outBuf[outIndex++] = 0xDB;
+ outBuf[outIndex++] = 0xDD;
+ }
+ else {
+ outBuf[outIndex++] = *data;
+ }
+ data++;
+ --len;
+ }
+ uploadPort_write((const uint8_t *)outBuf, outIndex);
+}
+
+// Send a packet to the serial port while performing SLIP framing. The packet data comprises a header and an optional data block.
+// A SLIP packet begins and ends with 0xC0. The data encapsulated has the bytes
+// 0xC0 and 0xDB replaced by the two-byte sequences {0xDB, 0xDC} and {0xDB, 0xDD} respectively.
+
+void writePacket(const uint8_t *hdr, size_t hdrLen, const uint8_t *data, size_t dataLen) {
+ WriteByteRaw(0xC0); // send the packet start character
+ _writePacket(hdr, hdrLen); // send the header
+ _writePacket(data, dataLen); // send the data block
+ WriteByteRaw(0xC0); // send the packet end character
+}
+
+// Send a packet to the serial port while performing SLIP framing. The packet data comprises a header and an optional data block.
+// This is like writePacket except that it does a fast block write for both the header and the main data with no SLIP encoding. Used to send sync commands.
+void writePacketRaw(const uint8_t *hdr, size_t hdrLen, const uint8_t *data, size_t dataLen) {
+ WriteByteRaw(0xC0); // send the packet start character
+ _writePacketRaw(hdr, hdrLen); // send the header
+ _writePacketRaw(data, dataLen); // send the data block in raw mode
+ WriteByteRaw(0xC0); // send the packet end character
+}
+
+// Send a command to the attached device together with the supplied data, if any.
+// The data is supplied via a list of one or more segments.
+void sendCommand(uint8_t op, uint32_t checkVal, const uint8_t *data, size_t dataLen) {
+ // populate the header
+ uint8_t hdr[8];
+ putData(0, 1, hdr, 0);
+ putData(op, 1, hdr, 1);
+ putData(dataLen, 2, hdr, 2);
+ putData(checkVal, 4, hdr, 4);
+
+ // send the packet
+ if (op == ESP_SYNC)
+ writePacketRaw(hdr, sizeof(hdr), data, dataLen);
+ else
+ writePacket(hdr, sizeof(hdr), data, dataLen);
+}
+
+// Send a command to the attached device together with the supplied data, if any, and get the response
+EspUploadResult doCommand(uint8_t op, const uint8_t *data, size_t dataLen, uint32_t checkVal, uint32_t *valp, uint32_t msTimeout) {
+ size_t bodyLen;
+ EspUploadResult stat;
+
+ sendCommand(op, checkVal, data, dataLen);
+
+ stat = readPacket(op, valp, &bodyLen, msTimeout);
+ if (stat == success && bodyLen != 2)
+ stat = badReply;
+
+ return stat;
+}
+
+// Send a synchronising packet to the serial port in an attempt to induce
+// the ESP8266 to auto-baud lock on the baud rate.
+EspUploadResult Sync(uint16_t timeout) {
+ uint8_t buf[36];
+ EspUploadResult stat;
+ int i ;
+
+ // compose the data for the sync attempt
+ memset(buf, 0x55, sizeof(buf));
+ buf[0] = 0x07;
+ buf[1] = 0x07;
+ buf[2] = 0x12;
+ buf[3] = 0x20;
+
+ stat = doCommand(ESP_SYNC, buf, sizeof(buf), 0, 0, timeout);
+
+ // If we got a response other than sync, discard it and wait for a sync response. This happens at higher baud rates.
+ for (i = 0; i < 10 && stat == respHeader; ++i) {
+ size_t bodyLen;
+ stat = readPacket(ESP_SYNC, 0, &bodyLen, timeout);
+ }
+
+ if (stat == success) {
+ // Read and discard additional replies
+ for (;;) {
+ size_t bodyLen;
+ EspUploadResult rc = readPacket(ESP_SYNC, 0, &bodyLen, defaultTimeout);
+ watchdog_refresh();
+ if (rc != success || bodyLen != 2) break;
+ }
+ }
+ //DEBUG
+ //else debug//printf("stat=%d\n", (int)stat);
+ return stat;
+}
+
+// Send a command to the device to begin the Flash process.
+EspUploadResult flashBegin(uint32_t addr, uint32_t size) {
+ // determine the number of blocks represented by the size
+ uint32_t blkCnt;
+ uint8_t buf[16];
+ uint32_t timeout;
+
+ blkCnt = (size + EspFlashBlockSize - 1) / EspFlashBlockSize;
+
+ // ensure that the address is on a block boundary
+ addr &= ~(EspFlashBlockSize - 1);
+
+ // begin the Flash process
+ putData(size, 4, buf, 0);
+ putData(blkCnt, 4, buf, 4);
+ putData(EspFlashBlockSize, 4, buf, 8);
+ putData(addr, 4, buf, 12);
+
+ timeout = (size != 0) ? eraseTimeout : defaultTimeout;
+ return doCommand(ESP_FLASH_BEGIN, buf, sizeof(buf), 0, 0, timeout);
+}
+
+// Send a command to the device to terminate the Flash process
+EspUploadResult flashFinish(signed char reboot) {
+ uint8_t buf[4];
+ putData(reboot ? 0 : 1, 4, buf, 0);
+ return doCommand(ESP_FLASH_END, buf, sizeof(buf), 0, 0, defaultTimeout);
+}
+
+// Compute the checksum of a block of data
+uint16_t checksum(const uint8_t *data, uint16_t dataLen, uint16_t cksum) {
+ if (data) while (dataLen--) cksum ^= (uint16_t)*data++;
+ return cksum;
+}
+
+EspUploadResult flashWriteBlock(uint16_t flashParmVal, uint16_t flashParmMask) {
+ const uint32_t blkSize = EspFlashBlockSize;
+ int i;
+
+ // Allocate a data buffer for the combined header and block data
+ const uint16_t hdrOfst = 0;
+ const uint16_t dataOfst = 16;
+ const uint16_t blkBufSize = dataOfst + blkSize;
+ uint32_t blkBuf32[blkBufSize/4];
+ uint8_t * const blkBuf = (uint8_t*)(blkBuf32);
+ uint32_t cnt;
+ uint16_t cksum;
+ EspUploadResult stat;
+
+ // Prepare the header for the block
+ putData(blkSize, 4, blkBuf, hdrOfst + 0);
+ putData(esp_upload.uploadBlockNumber, 4, blkBuf, hdrOfst + 4);
+ putData(0, 4, blkBuf, hdrOfst + 8);
+ putData(0, 4, blkBuf, hdrOfst + 12);
+
+ // Get the data for the block
+ cnt = update_file.read(blkBuf + dataOfst, blkSize);//->Read(reinterpret_cast<char *>(blkBuf + dataOfst), blkSize);
+ if (cnt != blkSize) {
+ if (update_file.curPosition() == esp_upload.fileSize) {
+ // partial last block, fill the remainder
+ memset(blkBuf + dataOfst + cnt, 0xff, blkSize - cnt);
+ }
+ else
+ return fileRead;
+ }
+
+ // Patch the flash parameters into the first block if it is loaded at address 0
+ if (esp_upload.uploadBlockNumber == 0 && esp_upload.uploadAddress == 0 && blkBuf[dataOfst] == ESP_IMAGE_MAGIC && flashParmMask != 0) {
+ // update the Flash parameters
+ uint32_t flashParm = getData(2, blkBuf + dataOfst + 2, 0) & ~(uint32_t)flashParmMask;
+ putData(flashParm | flashParmVal, 2, blkBuf + dataOfst + 2, 0);
+ }
+
+ // Calculate the block checksum
+ cksum = checksum(blkBuf + dataOfst, blkSize, ESP_CHECKSUM_MAGIC);
+
+ for (i = 0; i < 3; i++)
+ if ((stat = doCommand(ESP_FLASH_DATA, blkBuf, blkBufSize, cksum, 0, blockWriteTimeout)) == success)
+ break;
+ return stat;
+}
+
+void upload_spin() {
+
+ switch (esp_upload.state) {
+ case resetting:
+
+ if (esp_upload.connectAttemptNumber == 9) {
+ esp_upload.uploadResult = connected;
+ esp_upload.state = done;
+ }
+ else{
+ uploadPort_begin();
+
+ wifi_delay(2000);
+
+ flushInput();
+
+ esp_upload.lastAttemptTime = esp_upload.lastResetTime = getWifiTick();
+ esp_upload.state = connecting;
+ }
+
+ break;
+
+ case connecting:
+ if ((getWifiTickDiff(esp_upload.lastAttemptTime, getWifiTick()) >= connectAttemptInterval) && (getWifiTickDiff(esp_upload.lastResetTime, getWifiTick()) >= 500)) {
+ EspUploadResult res = Sync(5000);
+ esp_upload.lastAttemptTime = getWifiTick();
+ if (res == success) {
+ esp_upload.state = erasing;
+ }
+ else {
+ esp_upload.connectAttemptNumber++;
+ if (esp_upload.connectAttemptNumber % retriesPerReset == 0) {
+ esp_upload.state = resetting;
+ }
+ }
+ }
+ break;
+
+ case erasing:
+ if (getWifiTickDiff(esp_upload.lastAttemptTime, getWifiTick()) >= blockWriteInterval) {
+ uint32_t eraseSize;
+ const uint32_t sectorsPerBlock = 16;
+ const uint32_t sectorSize = 4096;
+ const uint32_t numSectors = (esp_upload.fileSize + sectorSize - 1)/sectorSize;
+ const uint32_t startSector = esp_upload.uploadAddress/sectorSize;
+
+ uint32_t headSectors = sectorsPerBlock - (startSector % sectorsPerBlock);
+ NOMORE(headSectors, numSectors);
+
+ eraseSize = (numSectors < 2 * headSectors)
+ ? (numSectors + 1) / 2 * sectorSize
+ : (numSectors - headSectors) * sectorSize;
+
+ esp_upload.uploadResult = flashBegin(esp_upload.uploadAddress, eraseSize);
+ if (esp_upload.uploadResult == success) {
+ esp_upload.uploadBlockNumber = 0;
+ esp_upload.uploadNextPercentToReport = percentToReportIncrement;
+ esp_upload.lastAttemptTime = getWifiTick();
+ esp_upload.state = uploading;
+ }
+ else {
+ esp_upload.state = done;
+ }
+ }
+ break;
+
+ case uploading:
+ // The ESP needs several milliseconds to recover from one packet before it will accept another
+ if (getWifiTickDiff(esp_upload.lastAttemptTime, getWifiTick()) >= 15) {
+ unsigned int percentComplete;
+ const uint32_t blkCnt = (esp_upload.fileSize + EspFlashBlockSize - 1) / EspFlashBlockSize;
+ if (esp_upload.uploadBlockNumber < blkCnt) {
+ esp_upload.uploadResult = flashWriteBlock(0, 0);
+ esp_upload.lastAttemptTime = getWifiTick();
+ if (esp_upload.uploadResult != success) {
+ esp_upload.state = done;
+ }
+ percentComplete = (100 * esp_upload.uploadBlockNumber)/blkCnt;
+ ++esp_upload.uploadBlockNumber;
+ if (percentComplete >= esp_upload.uploadNextPercentToReport) {
+ esp_upload.uploadNextPercentToReport += percentToReportIncrement;
+ }
+ }
+ else
+ esp_upload.state = done;
+ }
+ break;
+
+ case done:
+ update_file.close();
+ esp_upload.state = upload_idle;//idle;
+ break;
+
+ default: break;
+ }
+}
+
+// Try to upload the given file at the given address
+void SendUpdateFile(const char *file, uint32_t address) {
+
+ const char * const fname = card.diveToFile(true, update_curDir, ESP_FIRMWARE_FILE);
+ if (!update_file.open(update_curDir, fname, O_READ)) return;
+
+ esp_upload.fileSize = update_file.fileSize();
+
+ if (esp_upload.fileSize == 0) {
+ update_file.close();
+ return;
+ }
+
+ esp_upload.uploadAddress = address;
+ esp_upload.connectAttemptNumber = 0;
+ esp_upload.state = resetting;
+}
+
+static const uint32_t FirmwareAddress = 0x00000000, WebFilesAddress = 0x00100000;
+
+void ResetWiFiForUpload(int begin_or_end) {
+ //#if 0
+ uint32_t start, now;
+
+ start = getWifiTick();
+ now = start;
+
+ if (begin_or_end == 0) {
+ SET_OUTPUT(WIFI_IO0_PIN);
+ WRITE(WIFI_IO0_PIN, LOW);
+ }
+ else
+ SET_INPUT_PULLUP(WIFI_IO0_PIN);
+
+ WIFI_RESET();
+ while (getWifiTickDiff(start, now) < 500) now = getWifiTick();
+ WIFI_SET();
+ //#endif
+}
+
+int32_t wifi_upload(int type) {
+ esp_upload.retriesPerBaudRate = 9;
+
+ ResetWiFiForUpload(0);
+
+ if (type == 0)
+ SendUpdateFile(ESP_FIRMWARE_FILE, FirmwareAddress);
+ else if (type == 1)
+ SendUpdateFile(ESP_WEB_FIRMWARE_FILE, FirmwareAddress);
+ else if (type == 2)
+ SendUpdateFile(ESP_WEB_FILE, WebFilesAddress);
+ else
+ return -1;
+
+ while (esp_upload.state != upload_idle) {
+ upload_spin();
+ watchdog_refresh();
+ }
+
+ ResetWiFiForUpload(1);
+
+ return esp_upload.uploadResult == success ? 0 : -1;
+}
+
+#endif // HAS_TFT_LVGL_UI && MKS_WIFI_MODULE
diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.h b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.h
new file mode 100644
index 0000000..ff98173
--- /dev/null
+++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.h
@@ -0,0 +1,74 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef __cplusplus
+ extern "C" { /* C-declarations for C++ */
+#endif
+
+#define ESP_FIRMWARE_FILE "MksWifi.bin"
+#define ESP_FIRMWARE_FILE_RENAME "MKSWIFI.CUR"
+#define ESP_WEB_FIRMWARE_FILE "1:/MksWifi_Web.bin"
+#define ESP_WEB_FILE "1:/MksWifi_WebView.bin"
+
+typedef enum {
+ upload_idle,
+ resetting,
+ connecting,
+ erasing,
+ uploading,
+ done
+} UploadState;
+
+typedef enum {
+ success = 0,
+ timeout,
+ connected,
+ badReply,
+ fileRead,
+ emptyFile,
+ respHeader,
+ slipFrame,
+ slipState,
+ slipData,
+} EspUploadResult;
+
+typedef struct {
+ uint32_t fileSize;
+
+ uint32_t uploadAddress;
+ UploadState state;
+ uint32_t retriesPerBaudRate;
+ uint32_t connectAttemptNumber;
+ uint32_t lastAttemptTime;
+ uint32_t lastResetTime;
+ uint32_t uploadBlockNumber;
+ uint32_t uploadNextPercentToReport;
+ EspUploadResult uploadResult;
+} UPLOAD_STRUCT;
+
+extern UPLOAD_STRUCT esp_upload;
+int32_t wifi_upload(int type);
+
+#ifdef __cplusplus
+ } /* C-declarations for C++ */
+#endif
diff --git a/Marlin/src/lcd/extui/malyan_lcd.cpp b/Marlin/src/lcd/extui/malyan_lcd.cpp
new file mode 100644
index 0000000..6c55eea
--- /dev/null
+++ b/Marlin/src/lcd/extui/malyan_lcd.cpp
@@ -0,0 +1,543 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * malyan_lcd.cpp
+ *
+ * LCD implementation for Malyan's LCD, a separate ESP8266 MCU running
+ * on Serial1 for the M200 board. This module outputs a pseudo-gcode
+ * wrapped in curly braces which the LCD implementation translates into
+ * actual G-code commands.
+ *
+ * Added to Marlin for Mini/Malyan M200
+ * Unknown commands as of Jan 2018: {H:}
+ * Not currently implemented:
+ * {E:} when sent by LCD. Meaning unknown.
+ *
+ * Notes for connecting to boards that are not Malyan:
+ * The LCD is 3.3v, so if powering from a RAMPS 1.4 board or
+ * other 5v/12v board, use a buck converter to power the LCD and
+ * the 3.3v side of a logic level shifter. Aux1 on the RAMPS board
+ * has Serial1 and 12v, making it perfect for this.
+ * Copyright (c) 2017 Jason Nelson (xC0000005)
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(MALYAN_LCD)
+
+//#define DEBUG_MALYAN_LCD
+
+#include "ui_api.h"
+
+#include "../marlinui.h"
+#include "../../sd/cardreader.h"
+#include "../../module/temperature.h"
+#include "../../module/stepper.h"
+#include "../../module/motion.h"
+#include "../../libs/duration_t.h"
+#include "../../module/printcounter.h"
+#include "../../gcode/queue.h"
+
+#define DEBUG_OUT ENABLED(DEBUG_MALYAN_LCD)
+#include "../../core/debug_out.h"
+
+// This is based on longest sys command + a filename, plus some buffer
+// in case we encounter some data we don't recognize
+// There is no evidence a line will ever be this long, but better safe than sorry
+#define MAX_CURLY_COMMAND (32 + LONG_FILENAME_LENGTH) * 2
+
+// Track incoming command bytes from the LCD
+uint16_t inbound_count;
+
+// For sending print completion messages
+bool last_printing_status = false;
+
+// Everything written needs the high bit set.
+void write_to_lcd_P(PGM_P const message) {
+ char encoded_message[MAX_CURLY_COMMAND];
+ uint8_t message_length = _MIN(strlen_P(message), sizeof(encoded_message));
+
+ LOOP_L_N(i, message_length)
+ encoded_message[i] = pgm_read_byte(&message[i]) | 0x80;
+
+ LCD_SERIAL.Print::write(encoded_message, message_length);
+}
+
+void write_to_lcd(const char * const message) {
+ char encoded_message[MAX_CURLY_COMMAND];
+ const uint8_t message_length = _MIN(strlen(message), sizeof(encoded_message));
+
+ LOOP_L_N(i, message_length)
+ encoded_message[i] = message[i] | 0x80;
+
+ LCD_SERIAL.Print::write(encoded_message, message_length);
+}
+
+// {E:<msg>} is for error states.
+void set_lcd_error_P(PGM_P const error, PGM_P const component=nullptr) {
+ write_to_lcd_P(PSTR("{E:"));
+ write_to_lcd_P(error);
+ if (component) {
+ write_to_lcd_P(PSTR(" "));
+ write_to_lcd_P(component);
+ }
+ write_to_lcd_P(PSTR("}"));
+}
+
+
+/**
+ * Process an LCD 'C' command.
+ * These are currently all temperature commands
+ * {C:T0190}
+ * Set temp for hotend to 190
+ * {C:P050}
+ * Set temp for bed to 50
+ *
+ * {C:S09} set feedrate to 90 %.
+ * {C:S12} set feedrate to 120 %.
+ *
+ * the command portion begins after the :
+ */
+void process_lcd_c_command(const char* command) {
+ const int target_val = command[1] ? atoi(command + 1) : -1;
+ if (target_val < 0) {
+ DEBUG_ECHOLNPAIR("UNKNOWN C COMMAND ", command);
+ return;
+ }
+ switch (command[0]) {
+ case 'C': // Cope with both V1 early rev and later LCDs.
+ case 'S':
+ feedrate_percentage = target_val * 10;
+ LIMIT(feedrate_percentage, 10, 999);
+ break;
+
+ case 'T':
+ // Sometimes the LCD will send commands to turn off both extruder and bed, though
+ // this should not happen since the printing screen is up. Better safe than sorry.
+ if (!print_job_timer.isRunning() || target_val > 0)
+ ExtUI::setTargetTemp_celsius(target_val, ExtUI::extruder_t::E0);
+ break;
+
+ #if HAS_HEATED_BED
+ case 'P': ExtUI::setTargetTemp_celsius(target_val, ExtUI::heater_t::BED); break;
+ #endif
+
+ default: DEBUG_ECHOLNPAIR("UNKNOWN C COMMAND ", command);
+ }
+}
+
+/**
+ * Process an LCD 'B' command.
+ * {B:0} results in: {T0:008/195}{T1:000/000}{TP:000/000}{TQ:000C}{TT:000000}
+ * T0/T1 are hot end temperatures, TP is bed, TQ is percent, and TT is probably
+ * time remaining (HH:MM:SS). The UI can't handle displaying a second hotend,
+ * but the stock firmware always sends it, and it's always zero.
+ */
+void process_lcd_eb_command(const char* command) {
+ char elapsed_buffer[10];
+ static uint8_t iteration = 0;
+ duration_t elapsed;
+ switch (command[0]) {
+ case '0': {
+ elapsed = print_job_timer.duration();
+ sprintf_P(elapsed_buffer, PSTR("%02u%02u%02u"), uint16_t(elapsed.hour()), uint16_t(elapsed.minute()) % 60, uint16_t(elapsed.second()) % 60);
+
+ char message_buffer[MAX_CURLY_COMMAND];
+ uint8_t done_pct = print_job_timer.isRunning() ? (iteration * 10) : 100;
+ iteration = (iteration + 1) % 10; // Provide progress animation
+ #if ENABLED(SDSUPPORT)
+ if (ExtUI::isPrintingFromMedia() || ExtUI::isPrintingFromMediaPaused())
+ done_pct = card.percentDone();
+ #endif
+
+ sprintf_P(message_buffer,
+ PSTR("{T0:%03i/%03i}{T1:000/000}{TP:%03i/%03i}{TQ:%03i}{TT:%s}"),
+ int(thermalManager.degHotend(0)), thermalManager.degTargetHotend(0),
+ #if HAS_HEATED_BED
+ int(thermalManager.degBed()), thermalManager.degTargetBed(),
+ #else
+ 0, 0,
+ #endif
+ #if ENABLED(SDSUPPORT)
+ done_pct,
+ #else
+ 0,
+ #endif
+ elapsed_buffer
+ );
+ write_to_lcd(message_buffer);
+ } break;
+
+ default: DEBUG_ECHOLNPAIR("UNKNOWN E/B COMMAND ", command);
+ }
+}
+
+/**
+ * Process an LCD 'J' command.
+ * These are currently all movement commands.
+ * The command portion begins after the :
+ * Move X Axis
+ *
+ * {J:E}{J:X-200}{J:E}
+ * {J:E}{J:X+200}{J:E}
+ * X, Y, Z, A (extruder)
+ */
+template<typename T>
+void j_move_axis(const char* command, const T axis) {
+ const float dist = atof(command + 1) / 10.0;
+ ExtUI::setAxisPosition_mm(ExtUI::getAxisPosition_mm(axis) + dist, axis);
+};
+
+void process_lcd_j_command(const char* command) {
+ switch (command[0]) {
+ case 'E': break;
+ case 'A': j_move_axis<ExtUI::extruder_t>(command, ExtUI::extruder_t::E0); break;
+ case 'Y': j_move_axis<ExtUI::axis_t>(command, ExtUI::axis_t::Y); break;
+ case 'Z': j_move_axis<ExtUI::axis_t>(command, ExtUI::axis_t::Z); break;
+ case 'X': j_move_axis<ExtUI::axis_t>(command, ExtUI::axis_t::X); break;
+ default: DEBUG_ECHOLNPAIR("UNKNOWN J COMMAND ", command);
+ }
+}
+
+/**
+ * Process an LCD 'P' command, related to homing and printing.
+ * Cancel:
+ * {P:X}
+ *
+ * Home all axes:
+ * {P:H}
+ *
+ * Print a file:
+ * {P:000}
+ * The File number is specified as a three digit value.
+ * Printer responds with:
+ * {PRINTFILE:Mini_SNES_Bottom.gcode}
+ * {SYS:BUILD}echo:Now fresh file: Mini_SNES_Bottom.gcode
+ * File opened: Mini_SNES_Bottom.gcode Size: 5805813
+ * File selected
+ * {SYS:BUILD}
+ * T:-2526.8 E:0
+ * T:-2533.0 E:0
+ * T:-2537.4 E:0
+ * Note only the curly brace stuff matters.
+ */
+void process_lcd_p_command(const char* command) {
+
+ switch (command[0]) {
+ case 'P':
+ ExtUI::pausePrint();
+ write_to_lcd_P(PSTR("{SYS:PAUSED}"));
+ break;
+ case 'R':
+ ExtUI::resumePrint();
+ write_to_lcd_P(PSTR("{SYS:RESUMED}"));
+ break;
+ case 'X':
+ write_to_lcd_P(PSTR("{SYS:CANCELING}"));
+ ExtUI::stopPrint();
+ write_to_lcd_P(PSTR("{SYS:STARTED}"));
+ break;
+ case 'H': queue.enqueue_now_P(G28_STR); break; // Home all axes
+ default: {
+ #if ENABLED(SDSUPPORT)
+ // Print file 000 - a three digit number indicating which
+ // file to print in the SD card. If it's a directory,
+ // then switch to the directory.
+
+ // Find the name of the file to print.
+ // It's needed to echo the PRINTFILE option.
+ // The {S:L} command should've ensured the SD card was mounted.
+ card.selectFileByIndex(atoi(command));
+
+ // There may be a difference in how V1 and V2 LCDs handle subdirectory
+ // prints. Investigate more. This matches the V1 motion controller actions
+ // but the V2 LCD switches to "print" mode on {SYS:DIR} response.
+ if (card.flag.filenameIsDir) {
+ card.cd(card.filename);
+ write_to_lcd_P(PSTR("{SYS:DIR}"));
+ }
+ else {
+ char message_buffer[MAX_CURLY_COMMAND];
+ sprintf_P(message_buffer, PSTR("{PRINTFILE:%s}"), card.longest_filename());
+ write_to_lcd(message_buffer);
+ write_to_lcd_P(PSTR("{SYS:BUILD}"));
+ card.openAndPrintFile(card.filename);
+ }
+ #endif
+ } break; // default
+ } // switch
+}
+
+/**
+ * Handle an lcd 'S' command
+ * {S:I} - Temperature request
+ * {T0:999/000}{T1:000/000}{TP:004/000}
+ *
+ * {S:L} - File Listing request
+ * Printer Response:
+ * {FILE:buttons.gcode}
+ * {FILE:update.bin}
+ * {FILE:nupdate.bin}
+ * {FILE:fcupdate.flg}
+ * {SYS:OK}
+ */
+void process_lcd_s_command(const char* command) {
+ switch (command[0]) {
+ case 'I': {
+ // temperature information
+ char message_buffer[MAX_CURLY_COMMAND];
+ sprintf_P(message_buffer, PSTR("{T0:%03i/%03i}{T1:000/000}{TP:%03i/%03i}"),
+ int(thermalManager.degHotend(0)), thermalManager.degTargetHotend(0),
+ #if HAS_HEATED_BED
+ int(thermalManager.degBed()), thermalManager.degTargetBed()
+ #else
+ 0, 0
+ #endif
+ );
+ write_to_lcd(message_buffer);
+ } break;
+
+ case 'L': {
+ #if ENABLED(SDSUPPORT)
+ if (!card.isMounted()) card.mount();
+
+ // A more efficient way to do this would be to
+ // implement a callback in the ls_SerialPrint code, but
+ // that requires changes to the core cardreader class that
+ // would not benefit the majority of users. Since one can't
+ // select a file for printing during a print, there's
+ // little reason not to do it this way.
+ char message_buffer[MAX_CURLY_COMMAND];
+ uint16_t file_count = card.get_num_Files();
+ for (uint16_t i = 0; i < file_count; i++) {
+ card.selectFileByIndex(i);
+ sprintf_P(message_buffer, card.flag.filenameIsDir ? PSTR("{DIR:%s}") : PSTR("{FILE:%s}"), card.longest_filename());
+ write_to_lcd(message_buffer);
+ }
+
+ write_to_lcd_P(PSTR("{SYS:OK}"));
+ #endif
+ } break;
+
+ default: DEBUG_ECHOLNPAIR("UNKNOWN S COMMAND ", command);
+ }
+}
+
+/**
+ * Receive a curly brace command and translate to G-code.
+ * Currently {E:0} is not handled. Its function is unknown,
+ * but it occurs during the temp window after a sys build.
+ */
+void process_lcd_command(const char* command) {
+ const char *current = command;
+
+ byte command_code = *current++;
+ if (*current == ':') {
+
+ current++; // skip the :
+
+ switch (command_code) {
+ case 'S': process_lcd_s_command(current); break;
+ case 'J': process_lcd_j_command(current); break;
+ case 'P': process_lcd_p_command(current); break;
+ case 'C': process_lcd_c_command(current); break;
+ case 'B':
+ case 'E': process_lcd_eb_command(current); break;
+ default: DEBUG_ECHOLNPAIR("UNKNOWN COMMAND ", command);
+ }
+ }
+ else
+ DEBUG_ECHOLNPAIR("UNKNOWN COMMAND FORMAT ", command);
+}
+
+//
+// Parse LCD commands mixed with G-Code
+//
+void parse_lcd_byte(const byte b) {
+ static char inbound_buffer[MAX_CURLY_COMMAND];
+
+ static uint8_t parsing = 0; // Parsing state
+ static bool prevcr = false; // Was the last c a CR?
+
+ const char c = b & 0x7F;
+
+ if (parsing) {
+ const bool is_lcd = parsing == 1; // 1 for LCD
+ if ( ( is_lcd && c == '}') // Closing brace on LCD command
+ || (!is_lcd && c == '\n') // LF on a G-code command
+ ) {
+ inbound_buffer[inbound_count] = '\0'; // Reset before processing
+ inbound_count = 0; // Reset buffer index
+ if (parsing == 1)
+ process_lcd_command(inbound_buffer); // Handle the LCD command
+ else
+ queue.enqueue_one_now(inbound_buffer); // Handle the G-code command
+ parsing = 0; // Unflag and...
+ }
+ else if (inbound_count < MAX_CURLY_COMMAND - 2)
+ inbound_buffer[inbound_count++] = is_lcd ? c : b; // Buffer while space remains
+ }
+ else {
+ if (c == '{') parsing = 1; // Brace opens an LCD command
+ else if (prevcr && c == '\n') parsing = 2; // CRLF indicates G-code
+ prevcr = (c == '\r'); // Remember if it was a CR
+ }
+}
+
+/**
+ * UC means connected.
+ * UD means disconnected
+ * The stock firmware considers USB initialized as "connected."
+ */
+void update_usb_status(const bool forceUpdate) {
+ static bool last_usb_connected_status = false;
+ // This is mildly different than stock, which
+ // appears to use the usb discovery status.
+ // This is more logical.
+ if (last_usb_connected_status != MYSERIAL0.connected() || forceUpdate) {
+ last_usb_connected_status = MYSERIAL0.connected();
+ write_to_lcd_P(last_usb_connected_status ? PSTR("{R:UC}\r\n") : PSTR("{R:UD}\r\n"));
+ }
+}
+
+namespace ExtUI {
+ void onStartup() {
+ /**
+ * The Malyan LCD actually runs as a separate MCU on Serial 1.
+ * This code's job is to siphon the weird curly-brace commands from
+ * it and translate into ExtUI operations where possible.
+ */
+ inbound_count = 0;
+
+ #ifndef LCD_BAUDRATE
+ #define LCD_BAUDRATE 500000
+ #endif
+ LCD_SERIAL.begin(LCD_BAUDRATE);
+
+ // Signal init
+ write_to_lcd_P(PSTR("{SYS:STARTED}\r\n"));
+
+ // send a version that says "unsupported"
+ write_to_lcd_P(PSTR("{VER:99}\r\n"));
+
+ // No idea why it does this twice.
+ write_to_lcd_P(PSTR("{SYS:STARTED}\r\n"));
+ update_usb_status(true);
+ }
+
+ void onIdle() {
+ /**
+ * - from printer on startup:
+ * {SYS:STARTED}{VER:29}{SYS:STARTED}{R:UD}
+ */
+
+ // First report USB status.
+ update_usb_status(false);
+
+ // now drain commands...
+ while (LCD_SERIAL.available())
+ parse_lcd_byte((byte)LCD_SERIAL.read());
+
+ #if ENABLED(SDSUPPORT)
+ // The way last printing status works is simple:
+ // The UI needs to see at least one TQ which is not 100%
+ // and then when the print is complete, one which is.
+ static uint8_t last_percent_done = 100;
+
+ // If there was a print in progress, we need to emit the final
+ // print status as {TQ:100}. Reset last percent done so a new print will
+ // issue a percent of 0.
+ const uint8_t percent_done = (ExtUI::isPrinting() || ExtUI::isPrintingFromMediaPaused()) ? ExtUI::getProgress_percent() : last_printing_status ? 100 : 0;
+ if (percent_done != last_percent_done) {
+ char message_buffer[16];
+ sprintf_P(message_buffer, PSTR("{TQ:%03i}"), percent_done);
+ write_to_lcd(message_buffer);
+ last_percent_done = percent_done;
+ last_printing_status = ExtUI::isPrinting();
+ }
+ #endif
+ }
+
+ void onPrinterKilled(PGM_P const error, PGM_P const component) {
+ set_lcd_error_P(error, component);
+ }
+
+ #if HAS_PID_HEATING
+
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ //SERIAL_ECHOLNPAIR("OnPidTuning:", rst);
+ switch (rst) {
+ case PID_BAD_EXTRUDER_NUM:
+ set_lcd_error_P(GET_TEXT(MSG_PID_BAD_EXTRUDER_NUM));
+ break;
+ case PID_TEMP_TOO_HIGH:
+ set_lcd_error_P(GET_TEXT(MSG_PID_TEMP_TOO_HIGH));
+ break;
+ case PID_TUNING_TIMEOUT:
+ set_lcd_error_P(GET_TEXT(MSG_PID_TIMEOUT));
+ break;
+ case PID_DONE:
+ set_lcd_error_P(GET_TEXT(MSG_PID_AUTOTUNE_DONE));
+ break;
+ }
+ }
+
+ #endif
+
+ void onPrintTimerStarted() { write_to_lcd_P(PSTR("{SYS:BUILD}")); }
+ void onPrintTimerPaused() {}
+ void onPrintTimerStopped() { write_to_lcd_P(PSTR("{TQ:100}")); }
+
+ // Not needed for Malyan LCD
+ void onStatusChanged(const char * const) {}
+ void onMediaInserted() {}
+ void onMediaError() {}
+ void onMediaRemoved() {}
+ void onPlayTone(const uint16_t, const uint16_t) {}
+ void onFilamentRunout(const extruder_t extruder) {}
+ void onUserConfirmRequired(const char * const) {}
+ void onHomingStart() {}
+ void onHomingComplete() {}
+ void onPrintFinished() {}
+ void onFactoryReset() {}
+ void onStoreSettings(char*) {}
+ void onLoadSettings(const char*) {}
+ void onConfigurationStoreWritten(bool) {}
+ void onConfigurationStoreRead(bool) {}
+
+ #if HAS_MESH
+ void onMeshLevelingStart() {}
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {}
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {}
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {}
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // MALYAN_LCD
diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp
new file mode 100644
index 0000000..d1ffb4c
--- /dev/null
+++ b/Marlin/src/lcd/extui/ui_api.cpp
@@ -0,0 +1,1074 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**************
+ * ui_api.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if ENABLED(EXTENSIBLE_UI)
+
+#include "../marlinui.h"
+#include "../../gcode/queue.h"
+#include "../../module/motion.h"
+#include "../../module/planner.h"
+#include "../../module/probe.h"
+#include "../../module/temperature.h"
+#include "../../module/printcounter.h"
+#include "../../libs/duration_t.h"
+#include "../../HAL/shared/Delay.h"
+#include "../../sd/cardreader.h"
+
+#if ENABLED(PRINTCOUNTER)
+ #include "../../core/utility.h"
+ #include "../../libs/numtostr.h"
+#endif
+
+#if HAS_MULTI_EXTRUDER
+ #include "../../module/tool_change.h"
+#endif
+
+#if ENABLED(EMERGENCY_PARSER)
+ #include "../../feature/e_parser.h"
+#endif
+
+#if HAS_TRINAMIC_CONFIG
+ #include "../../feature/tmc_util.h"
+ #include "../../module/stepper/indirection.h"
+#endif
+
+#include "ui_api.h"
+
+#if ENABLED(BACKLASH_GCODE)
+ #include "../../feature/backlash.h"
+#endif
+
+#if HAS_LEVELING
+ #include "../../feature/bedlevel/bedlevel.h"
+#endif
+
+#if HAS_FILAMENT_SENSOR
+ #include "../../feature/runout.h"
+#endif
+
+#if ENABLED(CASE_LIGHT_ENABLE)
+ #include "../../feature/caselight.h"
+#endif
+
+#if ENABLED(BABYSTEPPING)
+ #include "../../feature/babystep.h"
+#endif
+
+#if ENABLED(HOST_PROMPT_SUPPORT)
+ #include "../../feature/host_actions.h"
+#endif
+
+namespace ExtUI {
+ static struct {
+ uint8_t printer_killed : 1;
+ TERN_(JOYSTICK, uint8_t jogging : 1);
+ TERN_(SDSUPPORT, uint8_t was_sd_printing : 1);
+ } flags;
+
+ #ifdef __SAM3X8E__
+ /**
+ * Implement a special millis() to allow time measurement
+ * within an ISR (such as when the printer is killed).
+ *
+ * To keep proper time, must be called at least every 1s.
+ */
+ uint32_t safe_millis() {
+ // Not killed? Just call millis()
+ if (!flags.printer_killed) return millis();
+
+ static uint32_t currTimeHI = 0; /* Current time */
+
+ // Machine was killed, reinit SysTick so we are able to compute time without ISRs
+ if (currTimeHI == 0) {
+ // Get the last time the Arduino time computed (from CMSIS) and convert it to SysTick
+ currTimeHI = uint32_t((GetTickCount() * uint64_t(F_CPU / 8000)) >> 24);
+
+ // Reinit the SysTick timer to maximize its period
+ SysTick->LOAD = SysTick_LOAD_RELOAD_Msk; // get the full range for the systick timer
+ SysTick->VAL = 0; // Load the SysTick Counter Value
+ SysTick->CTRL = // MCLK/8 as source
+ // No interrupts
+ SysTick_CTRL_ENABLE_Msk; // Enable SysTick Timer
+ }
+
+ // Check if there was a timer overflow from the last read
+ if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) {
+ // There was. This means (SysTick_LOAD_RELOAD_Msk * 1000 * 8)/F_CPU ms has elapsed
+ currTimeHI++;
+ }
+
+ // Calculate current time in milliseconds
+ uint32_t currTimeLO = SysTick_LOAD_RELOAD_Msk - SysTick->VAL; // (in MCLK/8)
+ uint64_t currTime = ((uint64_t)currTimeLO) | (((uint64_t)currTimeHI) << 24);
+
+ // The ms count is
+ return (uint32_t)(currTime / (F_CPU / 8000));
+ }
+ #endif // __SAM3X8E__
+
+ void delay_us(uint32_t us) { DELAY_US(us); }
+
+ void delay_ms(uint32_t ms) {
+ if (flags.printer_killed)
+ DELAY_US(ms * 1000);
+ else
+ safe_delay(ms);
+ }
+
+ void yield() {
+ if (!flags.printer_killed) thermalManager.manage_heater();
+ }
+
+ void enableHeater(const extruder_t extruder) {
+ #if HAS_HOTEND && HEATER_IDLE_HANDLER
+ thermalManager.reset_hotend_idle_timer(extruder - E0);
+ #else
+ UNUSED(extruder);
+ #endif
+ }
+
+ void enableHeater(const heater_t heater) {
+ #if HEATER_IDLE_HANDLER
+ switch (heater) {
+ #if HAS_HEATED_BED
+ case BED: thermalManager.reset_bed_idle_timer(); return;
+ #endif
+ TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return); // Chamber has no idle timer
+ default:
+ TERN_(HAS_HOTEND, thermalManager.reset_hotend_idle_timer(heater - H0));
+ break;
+ }
+ #else
+ UNUSED(heater);
+ #endif
+ }
+
+ #if ENABLED(JOYSTICK)
+ /**
+ * Jogs in the direction given by the vector (dx, dy, dz).
+ * The values range from -1 to 1 mapping to the maximum
+ * feedrate for an axis.
+ *
+ * The axis will continue to jog until this function is
+ * called with all zeros.
+ */
+ void jog(const xyz_float_t &dir) {
+ // The "destination" variable is used as a scratchpad in
+ // Marlin by GCODE routines, but should remain untouched
+ // during manual jogging, allowing us to reuse the space
+ // for our direction vector.
+ destination = dir;
+ flags.jogging = !NEAR_ZERO(dir.x) || !NEAR_ZERO(dir.y) || !NEAR_ZERO(dir.z);
+ }
+
+ // Called by the polling routine in "joystick.cpp"
+ void _joystick_update(xyz_float_t &norm_jog) {
+ if (flags.jogging) {
+ #define OUT_OF_RANGE(VALUE) (VALUE < -1.0f || VALUE > 1.0f)
+
+ if (OUT_OF_RANGE(destination.x) || OUT_OF_RANGE(destination.y) || OUT_OF_RANGE(destination.z)) {
+ // If destination on any axis is out of range, it
+ // probably means the UI forgot to stop jogging and
+ // ran GCODE that wrote a position to destination.
+ // To prevent a disaster, stop jogging.
+ flags.jogging = false;
+ return;
+ }
+ norm_jog = destination;
+ }
+ }
+ #endif
+
+ bool isHeaterIdle(const extruder_t extruder) {
+ #if HAS_HOTEND && HEATER_IDLE_HANDLER
+ return thermalManager.heater_idle[extruder - E0].timed_out;
+ #else
+ UNUSED(extruder);
+ return false;
+ #endif
+ }
+
+ bool isHeaterIdle(const heater_t heater) {
+ #if HEATER_IDLE_HANDLER
+ switch (heater) {
+ TERN_(HAS_HEATED_BED, case BED: return thermalManager.heater_idle[thermalManager.IDLE_INDEX_BED].timed_out);
+ TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return false); // Chamber has no idle timer
+ default:
+ return TERN0(HAS_HOTEND, thermalManager.heater_idle[heater - H0].timed_out);
+ }
+ #else
+ UNUSED(heater);
+ return false;
+ #endif
+ }
+
+ #ifdef TOUCH_UI_LCD_TEMP_SCALING
+ #define GET_TEMP_ADJUSTMENT(A) (float(A) / (TOUCH_UI_LCD_TEMP_SCALING))
+ #else
+ #define GET_TEMP_ADJUSTMENT(A) A
+ #endif
+
+ float getActualTemp_celsius(const heater_t heater) {
+ switch (heater) {
+ TERN_(HAS_HEATED_BED, case BED: return GET_TEMP_ADJUSTMENT(thermalManager.degBed()));
+ TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return GET_TEMP_ADJUSTMENT(thermalManager.degChamber()));
+ default: return GET_TEMP_ADJUSTMENT(thermalManager.degHotend(heater - H0));
+ }
+ }
+
+ float getActualTemp_celsius(const extruder_t extruder) {
+ return GET_TEMP_ADJUSTMENT(thermalManager.degHotend(extruder - E0));
+ }
+
+ float getTargetTemp_celsius(const heater_t heater) {
+ switch (heater) {
+ TERN_(HAS_HEATED_BED, case BED: return GET_TEMP_ADJUSTMENT(thermalManager.degTargetBed()));
+ TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return GET_TEMP_ADJUSTMENT(thermalManager.degTargetChamber()));
+ default: return GET_TEMP_ADJUSTMENT(thermalManager.degTargetHotend(heater - H0));
+ }
+ }
+
+ float getTargetTemp_celsius(const extruder_t extruder) {
+ return GET_TEMP_ADJUSTMENT(thermalManager.degTargetHotend(extruder - E0));
+ }
+
+ float getTargetFan_percent(const fan_t fan) {
+ #if HAS_FAN
+ return thermalManager.fanPercent(thermalManager.fan_speed[fan - FAN0]);
+ #else
+ UNUSED(fan);
+ return 0;
+ #endif
+ }
+
+ float getActualFan_percent(const fan_t fan) {
+ #if HAS_FAN
+ return thermalManager.fanPercent(thermalManager.scaledFanSpeed(fan - FAN0));
+ #else
+ UNUSED(fan);
+ return 0;
+ #endif
+ }
+
+ float getAxisPosition_mm(const axis_t axis) {
+ return TERN_(JOYSTICK, flags.jogging ? destination[axis] :) current_position[axis];
+ }
+
+ float getAxisPosition_mm(const extruder_t extruder) {
+ const extruder_t old_tool = getActiveTool();
+ setActiveTool(extruder, true);
+ const float epos = TERN_(JOYSTICK, flags.jogging ? destination.e :) current_position.e;
+ setActiveTool(old_tool, true);
+ return epos;
+ }
+
+ void setAxisPosition_mm(const float position, const axis_t axis, const feedRate_t feedrate/*=0*/) {
+ // Get motion limit from software endstops, if any
+ float min, max;
+ soft_endstop.get_manual_axis_limits((AxisEnum)axis, min, max);
+
+ // Delta limits XY based on the current offset from center
+ // This assumes the center is 0,0
+ #if ENABLED(DELTA)
+ if (axis != Z) {
+ max = SQRT(sq(float(DELTA_PRINTABLE_RADIUS)) - sq(current_position[Y - axis])); // (Y - axis) == the other axis
+ min = -max;
+ }
+ #endif
+
+ current_position[axis] = constrain(position, min, max);
+ line_to_current_position(feedrate ?: manual_feedrate_mm_s[axis]);
+ }
+
+ void setAxisPosition_mm(const float position, const extruder_t extruder, const feedRate_t feedrate/*=0*/) {
+ setActiveTool(extruder, true);
+
+ current_position.e = position;
+ line_to_current_position(feedrate ?: manual_feedrate_mm_s.e);
+ }
+
+ void setActiveTool(const extruder_t extruder, bool no_move) {
+ #if HAS_MULTI_EXTRUDER
+ const uint8_t e = extruder - E0;
+ if (e != active_extruder) tool_change(e, no_move);
+ active_extruder = e;
+ #else
+ UNUSED(extruder);
+ UNUSED(no_move);
+ #endif
+ }
+
+ extruder_t getActiveTool() {
+ switch (active_extruder) {
+ case 5: return E5;
+ case 4: return E4;
+ case 3: return E3;
+ case 2: return E2;
+ case 1: return E1;
+ default: return E0;
+ }
+ }
+
+ bool isMoving() { return planner.has_blocks_queued(); }
+
+ bool canMove(const axis_t axis) {
+ switch (axis) {
+ #if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING)
+ case X: return axis_should_home(X_AXIS);
+ case Y: return axis_should_home(Y_AXIS);
+ case Z: return axis_should_home(Z_AXIS);
+ #else
+ case X: case Y: case Z: return true;
+ #endif
+ default: return false;
+ }
+ }
+
+ bool canMove(const extruder_t extruder) {
+ return !thermalManager.tooColdToExtrude(extruder - E0);
+ }
+
+ #if HAS_SOFTWARE_ENDSTOPS
+ bool getSoftEndstopState() { return soft_endstop._enabled; }
+ void setSoftEndstopState(const bool value) { soft_endstop._enabled = value; }
+ #endif
+
+ #if HAS_TRINAMIC_CONFIG
+ float getAxisCurrent_mA(const axis_t axis) {
+ switch (axis) {
+ #if AXIS_IS_TMC(X)
+ case X: return stepperX.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(X2)
+ case X2: return stepperX2.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(Y)
+ case Y: return stepperY.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(Y2)
+ case Y2: return stepperY2.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(Z)
+ case Z: return stepperZ.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(Z2)
+ case Z2: return stepperZ2.getMilliamps();
+ #endif
+ default: return NAN;
+ };
+ }
+
+ float getAxisCurrent_mA(const extruder_t extruder) {
+ switch (extruder) {
+ #if AXIS_IS_TMC(E0)
+ case E0: return stepperE0.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(E1)
+ case E1: return stepperE1.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(E2)
+ case E2: return stepperE2.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(E3)
+ case E3: return stepperE3.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(E4)
+ case E4: return stepperE4.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(E5)
+ case E5: return stepperE5.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(E6)
+ case E6: return stepperE6.getMilliamps();
+ #endif
+ #if AXIS_IS_TMC(E7)
+ case E7: return stepperE7.getMilliamps();
+ #endif
+ default: return NAN;
+ };
+ }
+
+ void setAxisCurrent_mA(const float mA, const axis_t axis) {
+ switch (axis) {
+ #if AXIS_IS_TMC(X)
+ case X: stepperX.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(X2)
+ case X2: stepperX2.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(Y)
+ case Y: stepperY.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(Y2)
+ case Y2: stepperY2.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(Z)
+ case Z: stepperZ.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(Z2)
+ case Z2: stepperZ2.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ default: break;
+ };
+ }
+
+ void setAxisCurrent_mA(const float mA, const extruder_t extruder) {
+ switch (extruder) {
+ #if AXIS_IS_TMC(E0)
+ case E0: stepperE0.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(E1)
+ case E1: stepperE1.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(E2)
+ case E2: stepperE2.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(E3)
+ case E3: stepperE3.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(E4)
+ case E4: stepperE4.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(E5)
+ case E5: stepperE5.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(E6)
+ case E6: stepperE6.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ #if AXIS_IS_TMC(E7)
+ case E7: stepperE7.rms_current(constrain(mA, 400, 1500)); break;
+ #endif
+ default: break;
+ };
+ }
+
+ int getTMCBumpSensitivity(const axis_t axis) {
+ switch (axis) {
+ TERN_(X_SENSORLESS, case X: return stepperX.homing_threshold());
+ TERN_(X2_SENSORLESS, case X2: return stepperX2.homing_threshold());
+ TERN_(Y_SENSORLESS, case Y: return stepperY.homing_threshold());
+ TERN_(Y2_SENSORLESS, case Y2: return stepperY2.homing_threshold());
+ TERN_(Z_SENSORLESS, case Z: return stepperZ.homing_threshold());
+ TERN_(Z2_SENSORLESS, case Z2: return stepperZ2.homing_threshold());
+ TERN_(Z3_SENSORLESS, case Z3: return stepperZ3.homing_threshold());
+ TERN_(Z4_SENSORLESS, case Z4: return stepperZ4.homing_threshold());
+ default: return 0;
+ }
+ }
+
+ void setTMCBumpSensitivity(const float value, const axis_t axis) {
+ switch (axis) {
+ #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS
+ #if X_SENSORLESS
+ case X: stepperX.homing_threshold(value); break;
+ #endif
+ #if X2_SENSORLESS
+ case X2: stepperX2.homing_threshold(value); break;
+ #endif
+ #if Y_SENSORLESS
+ case Y: stepperY.homing_threshold(value); break;
+ #endif
+ #if Y2_SENSORLESS
+ case Y2: stepperY2.homing_threshold(value); break;
+ #endif
+ #if Z_SENSORLESS
+ case Z: stepperZ.homing_threshold(value); break;
+ #endif
+ #if Z2_SENSORLESS
+ case Z2: stepperZ2.homing_threshold(value); break;
+ #endif
+ #if Z3_SENSORLESS
+ case Z3: stepperZ3.homing_threshold(value); break;
+ #endif
+ #if Z4_SENSORLESS
+ case Z4: stepperZ4.homing_threshold(value); break;
+ #endif
+ #else
+ UNUSED(value);
+ #endif
+ default: break;
+ }
+ }
+ #endif
+
+ float getAxisSteps_per_mm(const axis_t axis) {
+ return planner.settings.axis_steps_per_mm[axis];
+ }
+
+ float getAxisSteps_per_mm(const extruder_t extruder) {
+ UNUSED_E(extruder);
+ return planner.settings.axis_steps_per_mm[E_AXIS_N(extruder - E0)];
+ }
+
+ void setAxisSteps_per_mm(const float value, const axis_t axis) {
+ planner.settings.axis_steps_per_mm[axis] = value;
+ planner.refresh_positioning();
+ }
+
+ void setAxisSteps_per_mm(const float value, const extruder_t extruder) {
+ UNUSED_E(extruder);
+ planner.settings.axis_steps_per_mm[E_AXIS_N(extruder - E0)] = value;
+ planner.refresh_positioning();
+ }
+
+ feedRate_t getAxisMaxFeedrate_mm_s(const axis_t axis) {
+ return planner.settings.max_feedrate_mm_s[axis];
+ }
+
+ feedRate_t getAxisMaxFeedrate_mm_s(const extruder_t extruder) {
+ UNUSED_E(extruder);
+ return planner.settings.max_feedrate_mm_s[E_AXIS_N(extruder - E0)];
+ }
+
+ void setAxisMaxFeedrate_mm_s(const feedRate_t value, const axis_t axis) {
+ planner.set_max_feedrate(axis, value);
+ }
+
+ void setAxisMaxFeedrate_mm_s(const feedRate_t value, const extruder_t extruder) {
+ UNUSED_E(extruder);
+ planner.set_max_feedrate(E_AXIS_N(extruder - E0), value);
+ }
+
+ float getAxisMaxAcceleration_mm_s2(const axis_t axis) {
+ return planner.settings.max_acceleration_mm_per_s2[axis];
+ }
+
+ float getAxisMaxAcceleration_mm_s2(const extruder_t extruder) {
+ UNUSED_E(extruder);
+ return planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(extruder - E0)];
+ }
+
+ void setAxisMaxAcceleration_mm_s2(const float value, const axis_t axis) {
+ planner.set_max_acceleration(axis, value);
+ planner.reset_acceleration_rates();
+ }
+
+ void setAxisMaxAcceleration_mm_s2(const float value, const extruder_t extruder) {
+ UNUSED_E(extruder);
+ planner.set_max_acceleration(E_AXIS_N(extruder - E0), value);
+ planner.reset_acceleration_rates();
+ }
+
+ #if HAS_FILAMENT_SENSOR
+ bool getFilamentRunoutEnabled() { return runout.enabled; }
+ void setFilamentRunoutEnabled(const bool value) { runout.enabled = value; }
+ bool getFilamentRunoutState() { return runout.filament_ran_out; }
+ void setFilamentRunoutState(const bool value) { runout.filament_ran_out = value; }
+
+ #if HAS_FILAMENT_RUNOUT_DISTANCE
+ float getFilamentRunoutDistance_mm() { return runout.runout_distance(); }
+ void setFilamentRunoutDistance_mm(const float value) { runout.set_runout_distance(constrain(value, 0, 999)); }
+ #endif
+ #endif
+
+ #if ENABLED(CASE_LIGHT_ENABLE)
+ bool getCaseLightState() { return caselight.on; }
+ void setCaseLightState(const bool value) {
+ caselight.on = value;
+ caselight.update_enabled();
+ }
+
+ #if CASELIGHT_USES_BRIGHTNESS
+ float getCaseLightBrightness_percent() { return ui8_to_percent(caselight.brightness); }
+ void setCaseLightBrightness_percent(const float value) {
+ caselight.brightness = map(constrain(value, 0, 100), 0, 100, 0, 255);
+ caselight.update_brightness();
+ }
+ #endif
+ #endif
+
+ #if ENABLED(LIN_ADVANCE)
+ float getLinearAdvance_mm_mm_s(const extruder_t extruder) {
+ return (extruder < EXTRUDERS) ? planner.extruder_advance_K[extruder - E0] : 0;
+ }
+
+ void setLinearAdvance_mm_mm_s(const float value, const extruder_t extruder) {
+ if (extruder < EXTRUDERS)
+ planner.extruder_advance_K[extruder - E0] = constrain(value, 0, 10);
+ }
+ #endif
+
+ #if HAS_JUNCTION_DEVIATION
+
+ float getJunctionDeviation_mm() {
+ return planner.junction_deviation_mm;
+ }
+
+ void setJunctionDeviation_mm(const float value) {
+ planner.junction_deviation_mm = constrain(value, 0.001, 0.3);
+ TERN_(LIN_ADVANCE, planner.recalculate_max_e_jerk());
+ }
+
+ #else
+
+ float getAxisMaxJerk_mm_s(const axis_t axis) {
+ return planner.max_jerk[axis];
+ }
+
+ float getAxisMaxJerk_mm_s(const extruder_t) {
+ return planner.max_jerk.e;
+ }
+
+ void setAxisMaxJerk_mm_s(const float value, const axis_t axis) {
+ planner.set_max_jerk((AxisEnum)axis, value);
+ }
+
+ void setAxisMaxJerk_mm_s(const float value, const extruder_t) {
+ planner.set_max_jerk(E_AXIS, value);
+ }
+ #endif
+
+ feedRate_t getFeedrate_mm_s() { return feedrate_mm_s; }
+ int16_t getFlowPercentage(const extruder_t extr) { return planner.flow_percentage[extr]; }
+ feedRate_t getMinFeedrate_mm_s() { return planner.settings.min_feedrate_mm_s; }
+ feedRate_t getMinTravelFeedrate_mm_s() { return planner.settings.min_travel_feedrate_mm_s; }
+ float getPrintingAcceleration_mm_s2() { return planner.settings.acceleration; }
+ float getRetractAcceleration_mm_s2() { return planner.settings.retract_acceleration; }
+ float getTravelAcceleration_mm_s2() { return planner.settings.travel_acceleration; }
+ void setFeedrate_mm_s(const feedRate_t fr) { feedrate_mm_s = fr; }
+ void setFlow_percent(const int16_t flow, const extruder_t extr) { planner.set_flow(extr, flow); }
+ void setMinFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_feedrate_mm_s = fr; }
+ void setMinTravelFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_travel_feedrate_mm_s = fr; }
+ void setPrintingAcceleration_mm_s2(const float acc) { planner.settings.acceleration = acc; }
+ void setRetractAcceleration_mm_s2(const float acc) { planner.settings.retract_acceleration = acc; }
+ void setTravelAcceleration_mm_s2(const float acc) { planner.settings.travel_acceleration = acc; }
+
+ #if ENABLED(BABYSTEPPING)
+ bool babystepAxis_steps(const int16_t steps, const axis_t axis) {
+ switch (axis) {
+ #if ENABLED(BABYSTEP_XY)
+ case X: babystep.add_steps(X_AXIS, steps); break;
+ case Y: babystep.add_steps(Y_AXIS, steps); break;
+ #endif
+ case Z: babystep.add_steps(Z_AXIS, steps); break;
+ default: return false;
+ };
+ return true;
+ }
+
+ /**
+ * This function adjusts an axis during a print.
+ *
+ * When linked_nozzles is false, each nozzle in a multi-nozzle
+ * printer can be babystepped independently of the others. This
+ * lets the user to fine tune the Z-offset and Nozzle Offsets
+ * while observing the first layer of a print, regardless of
+ * what nozzle is printing.
+ */
+ void smartAdjustAxis_steps(const int16_t steps, const axis_t axis, bool linked_nozzles) {
+ const float mm = steps * planner.steps_to_mm[axis];
+ UNUSED(mm);
+
+ if (!babystepAxis_steps(steps, axis)) return;
+
+ #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
+ // Make it so babystepping in Z adjusts the Z probe offset.
+ if (axis == Z && TERN1(HAS_MULTI_EXTRUDER, (linked_nozzles || active_extruder == 0)))
+ probe.offset.z += mm;
+ #endif
+
+ #if HAS_MULTI_EXTRUDER && HAS_HOTEND_OFFSET
+ /**
+ * When linked_nozzles is false, as an axis is babystepped
+ * adjust the hotend offsets so that the other nozzles are
+ * unaffected by the babystepping of the active nozzle.
+ */
+ if (!linked_nozzles) {
+ HOTEND_LOOP()
+ if (e != active_extruder)
+ hotend_offset[e][axis] += mm;
+
+ normalizeNozzleOffset(X);
+ normalizeNozzleOffset(Y);
+ normalizeNozzleOffset(Z);
+ }
+ #else
+ UNUSED(linked_nozzles);
+ #endif
+ }
+
+ /**
+ * Converts a mm displacement to a number of whole number of
+ * steps that is at least mm long.
+ */
+ int16_t mmToWholeSteps(const float mm, const axis_t axis) {
+ const float steps = mm / planner.steps_to_mm[axis];
+ return steps > 0 ? CEIL(steps) : FLOOR(steps);
+ }
+ #endif
+
+ float getZOffset_mm() {
+ return (0.0f
+ #if HAS_BED_PROBE
+ + probe.offset.z
+ #elif ENABLED(BABYSTEP_DISPLAY_TOTAL)
+ + planner.steps_to_mm[Z_AXIS] * babystep.axis_total[BS_AXIS_IND(Z_AXIS)]
+ #endif
+ );
+ }
+
+ void setZOffset_mm(const float value) {
+ #if HAS_BED_PROBE
+ if (WITHIN(value, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX))
+ probe.offset.z = value;
+ #elif ENABLED(BABYSTEP_DISPLAY_TOTAL)
+ babystep.add_mm(Z_AXIS, value - getZOffset_mm());
+ #else
+ UNUSED(value);
+ #endif
+ }
+
+ #if HAS_HOTEND_OFFSET
+
+ float getNozzleOffset_mm(const axis_t axis, const extruder_t extruder) {
+ if (extruder - E0 >= HOTENDS) return 0;
+ return hotend_offset[extruder - E0][axis];
+ }
+
+ void setNozzleOffset_mm(const float value, const axis_t axis, const extruder_t extruder) {
+ if (extruder - E0 >= HOTENDS) return;
+ hotend_offset[extruder - E0][axis] = value;
+ }
+
+ /**
+ * The UI should call this if needs to guarantee the first
+ * nozzle offset is zero (such as when it doesn't allow the
+ * user to edit the offset the first nozzle).
+ */
+ void normalizeNozzleOffset(const axis_t axis) {
+ const float offs = hotend_offset[0][axis];
+ HOTEND_LOOP() hotend_offset[e][axis] -= offs;
+ }
+
+ #endif // HAS_HOTEND_OFFSET
+
+ #if HAS_BED_PROBE
+ float getProbeOffset_mm(const axis_t axis) {
+ return probe.offset.pos[axis];
+ }
+ void setProbeOffset_mm(const float val, const axis_t axis) {
+ probe.offset.pos[axis] = val;
+ }
+ #endif
+
+ #if ENABLED(BACKLASH_GCODE)
+ float getAxisBacklash_mm(const axis_t axis) { return backlash.distance_mm[axis]; }
+ void setAxisBacklash_mm(const float value, const axis_t axis)
+ { backlash.distance_mm[axis] = constrain(value,0,5); }
+
+ float getBacklashCorrection_percent() { return ui8_to_percent(backlash.correction); }
+ void setBacklashCorrection_percent(const float value) { backlash.correction = map(constrain(value, 0, 100), 0, 100, 0, 255); }
+
+ #ifdef BACKLASH_SMOOTHING_MM
+ float getBacklashSmoothing_mm() { return backlash.smoothing_mm; }
+ void setBacklashSmoothing_mm(const float value) { backlash.smoothing_mm = constrain(value, 0, 999); }
+ #endif
+ #endif
+
+ uint32_t getProgress_seconds_elapsed() {
+ const duration_t elapsed = print_job_timer.duration();
+ return elapsed.value;
+ }
+
+ #if HAS_LEVELING
+ bool getLevelingActive() { return planner.leveling_active; }
+ void setLevelingActive(const bool state) { set_bed_leveling_enabled(state); }
+ bool getMeshValid() { return leveling_is_valid(); }
+ #if HAS_MESH
+ bed_mesh_t& getMeshArray() { return Z_VALUES_ARR; }
+ float getMeshPoint(const xy_uint8_t &pos) { return Z_VALUES(pos.x, pos.y); }
+ void setMeshPoint(const xy_uint8_t &pos, const float zoff) {
+ if (WITHIN(pos.x, 0, GRID_MAX_POINTS_X) && WITHIN(pos.y, 0, GRID_MAX_POINTS_Y)) {
+ Z_VALUES(pos.x, pos.y) = zoff;
+ TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
+ }
+ }
+ #endif
+ #endif
+
+ #if ENABLED(HOST_PROMPT_SUPPORT)
+ void setHostResponse(const uint8_t response) { host_response_handler(response); }
+ #endif
+
+ #if ENABLED(PRINTCOUNTER)
+ char* getTotalPrints_str(char buffer[21]) { strcpy(buffer,i16tostr3left(print_job_timer.getStats().totalPrints)); return buffer; }
+ char* getFinishedPrints_str(char buffer[21]) { strcpy(buffer,i16tostr3left(print_job_timer.getStats().finishedPrints)); return buffer; }
+ char* getTotalPrintTime_str(char buffer[21]) { return duration_t(print_job_timer.getStats().printTime).toString(buffer); }
+ char* getLongestPrint_str(char buffer[21]) { return duration_t(print_job_timer.getStats().longestPrint).toString(buffer); }
+ char* getFilamentUsed_str(char buffer[21]) {
+ printStatistics stats = print_job_timer.getStats();
+ sprintf_P(buffer, PSTR("%ld.%im"), long(stats.filamentUsed / 1000), int16_t(stats.filamentUsed / 100) % 10);
+ return buffer;
+ }
+ #endif
+
+ float getFeedrate_percent() { return feedrate_percentage; }
+
+ #if ENABLED(PIDTEMP)
+ float getPIDValues_Kp(const extruder_t tool) { return PID_PARAM(Kp, tool); }
+ float getPIDValues_Ki(const extruder_t tool) { return unscalePID_i(PID_PARAM(Ki, tool)); }
+ float getPIDValues_Kd(const extruder_t tool) { return unscalePID_d(PID_PARAM(Kd, tool)); }
+
+ void setPIDValues(const float p, const float i, const float d, extruder_t tool) {
+ thermalManager.temp_hotend[tool].pid.Kp = p;
+ thermalManager.temp_hotend[tool].pid.Ki = scalePID_i(i);
+ thermalManager.temp_hotend[tool].pid.Kd = scalePID_d(d);
+ thermalManager.updatePID();
+ }
+
+ void startPIDTune(const float temp, extruder_t tool) {
+ thermalManager.PID_autotune(temp, (heater_id_t)tool, 8, true);
+ }
+ #endif
+
+ #if ENABLED(PIDTEMPBED)
+ float getBedPIDValues_Kp() { return thermalManager.temp_bed.pid.Kp; }
+ float getBedPIDValues_Ki() { return unscalePID_i(thermalManager.temp_bed.pid.Ki); }
+ float getBedPIDValues_Kd() { return unscalePID_d(thermalManager.temp_bed.pid.Kd); }
+
+ void setBedPIDValues(const float p, const float i, const float d) {
+ thermalManager.temp_bed.pid.Kp = p;
+ thermalManager.temp_bed.pid.Ki = scalePID_i(i);
+ thermalManager.temp_bed.pid.Kd = scalePID_d(d);
+ thermalManager.updatePID();
+ }
+
+ void startBedPIDTune(const float temp) {
+ thermalManager.PID_autotune(temp, H_BED, 4, true);
+ }
+ #endif
+
+ void injectCommands_P(PGM_P const gcode) { queue.inject_P(gcode); }
+ void injectCommands(char * const gcode) { queue.inject(gcode); }
+
+ bool commandsInQueue() { return (planner.movesplanned() || queue.has_commands_queued()); }
+
+ bool isAxisPositionKnown(const axis_t axis) { return axis_is_trusted((AxisEnum)axis); }
+ bool isAxisPositionKnown(const extruder_t) { return axis_is_trusted(E_AXIS); }
+ bool isPositionKnown() { return all_axes_trusted(); }
+ bool isMachineHomed() { return all_axes_homed(); }
+
+ PGM_P getFirmwareName_str() {
+ static PGMSTR(firmware_name, "Marlin " SHORT_BUILD_VERSION);
+ return firmware_name;
+ }
+
+ void setTargetTemp_celsius(float value, const heater_t heater) {
+ #ifdef TOUCH_UI_LCD_TEMP_SCALING
+ value *= TOUCH_UI_LCD_TEMP_SCALING;
+ #endif
+ enableHeater(heater);
+ #if HAS_HEATED_CHAMBER
+ if (heater == CHAMBER)
+ thermalManager.setTargetChamber(LROUND(constrain(value, 0, CHAMBER_MAXTEMP - 10)));
+ else
+ #endif
+ #if HAS_HEATED_BED
+ if (heater == BED)
+ thermalManager.setTargetBed(LROUND(constrain(value, 0, BED_MAX_TARGET)));
+ else
+ #endif
+ {
+ #if HAS_HOTEND
+ const int16_t e = heater - H0;
+ thermalManager.setTargetHotend(LROUND(constrain(value, 0, thermalManager.heater_maxtemp[e] - HOTEND_OVERSHOOT)), e);
+ #endif
+ }
+ }
+
+ void setTargetTemp_celsius(float value, const extruder_t extruder) {
+ #ifdef TOUCH_UI_LCD_TEMP_SCALING
+ value *= TOUCH_UI_LCD_TEMP_SCALING;
+ #endif
+ #if HAS_HOTEND
+ const int16_t e = extruder - E0;
+ enableHeater(extruder);
+ thermalManager.setTargetHotend(LROUND(constrain(value, 0, thermalManager.heater_maxtemp[e] - HOTEND_OVERSHOOT)), e);
+ #endif
+ }
+
+ void setTargetFan_percent(const float value, const fan_t fan) {
+ #if HAS_FAN
+ if (fan < FAN_COUNT)
+ thermalManager.set_fan_speed(fan - FAN0, map(constrain(value, 0, 100), 0, 100, 0, 255));
+ #else
+ UNUSED(value);
+ UNUSED(fan);
+ #endif
+ }
+
+ void setFeedrate_percent(const float value) {
+ feedrate_percentage = constrain(value, 10, 500);
+ }
+
+ bool awaitingUserConfirm() {
+ return wait_for_user;
+ }
+
+ void setUserConfirmed() {
+ TERN_(HAS_RESUME_CONTINUE, wait_for_user = false);
+ }
+
+ void printFile(const char *filename) {
+ UNUSED(filename);
+ IFSD(card.openAndPrintFile(filename), NOOP);
+ }
+
+ bool isPrintingFromMediaPaused() {
+ return IFSD(isPrintingFromMedia() && !IS_SD_PRINTING(), false);
+ }
+
+ bool isPrintingFromMedia() {
+ #if ENABLED(SDSUPPORT)
+ // Account for when IS_SD_PRINTING() reports the end of the
+ // print when there is still SD card data in the planner.
+ flags.was_sd_printing = card.isFileOpen() || (flags.was_sd_printing && commandsInQueue());
+ return flags.was_sd_printing;
+ #else
+ return false;
+ #endif
+ }
+
+ bool isPrinting() {
+ return (commandsInQueue() || isPrintingFromMedia() || IFSD(IS_SD_PRINTING(), false)) || print_job_timer.isRunning() || print_job_timer.isPaused();
+ }
+
+ bool isPrintingPaused() {
+ return isPrinting() && (isPrintingFromMediaPaused() || print_job_timer.isPaused());
+ }
+
+ bool isMediaInserted() {
+ return IFSD(IS_SD_INSERTED() && card.isMounted(), false);
+ }
+
+ void pausePrint() { ui.pause_print(); }
+ void resumePrint() { ui.resume_print(); }
+ void stopPrint() { ui.abort_print(); }
+
+ void onUserConfirmRequired_P(PGM_P const pstr) {
+ char msg[strlen_P(pstr) + 1];
+ strcpy_P(msg, pstr);
+ onUserConfirmRequired(msg);
+ }
+
+ void onStatusChanged_P(PGM_P const pstr) {
+ char msg[strlen_P(pstr) + 1];
+ strcpy_P(msg, pstr);
+ onStatusChanged(msg);
+ }
+
+ FileList::FileList() { refresh(); }
+
+ void FileList::refresh() { num_files = 0xFFFF; }
+
+ bool FileList::seek(const uint16_t pos, const bool skip_range_check) {
+ #if ENABLED(SDSUPPORT)
+ if (!skip_range_check && (pos + 1) > count()) return false;
+ card.getfilename_sorted(SD_ORDER(pos, count()));
+ return card.filename[0] != '\0';
+ #else
+ UNUSED(pos);
+ UNUSED(skip_range_check);
+ return false;
+ #endif
+ }
+
+ const char* FileList::filename() {
+ return IFSD(card.longest_filename(), "");
+ }
+
+ const char* FileList::shortFilename() {
+ return IFSD(card.filename, "");
+ }
+
+ const char* FileList::longFilename() {
+ return IFSD(card.longFilename, "");
+ }
+
+ bool FileList::isDir() {
+ return IFSD(card.flag.filenameIsDir, false);
+ }
+
+ uint16_t FileList::count() {
+ return IFSD((num_files = (num_files == 0xFFFF ? card.get_num_Files() : num_files)), 0);
+ }
+
+ bool FileList::isAtRootDir() {
+ return IFSD(card.flag.workDirIsRoot, true);
+ }
+
+ void FileList::upDir() {
+ #if ENABLED(SDSUPPORT)
+ card.cdup();
+ num_files = 0xFFFF;
+ #endif
+ }
+
+ void FileList::changeDir(const char * const dirname) {
+ #if ENABLED(SDSUPPORT)
+ card.cd(dirname);
+ num_files = 0xFFFF;
+ #else
+ UNUSED(dirname);
+ #endif
+ }
+
+} // namespace ExtUI
+
+// At the moment we hook into MarlinUI methods, but this could be cleaned up in the future
+
+void MarlinUI::init() { ExtUI::onStartup(); }
+
+void MarlinUI::update() { ExtUI::onIdle(); }
+
+void MarlinUI::kill_screen(PGM_P const error, PGM_P const component) {
+ using namespace ExtUI;
+ if (!flags.printer_killed) {
+ flags.printer_killed = true;
+ onPrinterKilled(error, component);
+ }
+}
+
+#endif // EXTENSIBLE_UI
diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h
new file mode 100644
index 0000000..bfd658b
--- /dev/null
+++ b/Marlin/src/lcd/extui/ui_api.h
@@ -0,0 +1,402 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/************
+ * ui_api.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: <https://www.gnu.org/licenses/>. *
+ ****************************************************************************/
+
+#include "../../inc/MarlinConfig.h"
+#include "../marlinui.h"
+
+namespace ExtUI {
+
+ // The ExtUI implementation can store up to this many bytes
+ // in the EEPROM when the methods onStoreSettings and
+ // onLoadSettings are called.
+
+ static constexpr size_t eeprom_data_size = 48;
+
+ enum axis_t : uint8_t { X, Y, Z, X2, Y2, Z2, Z3, Z4 };
+ enum extruder_t : uint8_t { E0, E1, E2, E3, E4, E5, E6, E7 };
+ enum heater_t : uint8_t { H0, H1, H2, H3, H4, H5, BED, CHAMBER };
+ enum fan_t : uint8_t { FAN0, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7 };
+ enum result_t : uint8_t { PID_BAD_EXTRUDER_NUM, PID_TEMP_TOO_HIGH, PID_TUNING_TIMEOUT, PID_DONE };
+
+ constexpr uint8_t extruderCount = EXTRUDERS;
+ constexpr uint8_t hotendCount = HOTENDS;
+ constexpr uint8_t fanCount = FAN_COUNT;
+
+ #if HAS_MESH
+ typedef float bed_mesh_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
+ #endif
+
+ bool isMoving();
+ bool isAxisPositionKnown(const axis_t);
+ bool isAxisPositionKnown(const extruder_t);
+ bool isPositionKnown(); // Axis position guaranteed, steppers active since homing
+ bool isMachineHomed(); // Axis position most likely correct, steppers may have deactivated
+ bool canMove(const axis_t);
+ bool canMove(const extruder_t);
+ void injectCommands_P(PGM_P const);
+ void injectCommands(char * const);
+ bool commandsInQueue();
+
+ bool isHeaterIdle(const heater_t);
+ bool isHeaterIdle(const extruder_t);
+ void enableHeater(const heater_t);
+ void enableHeater(const extruder_t);
+
+ #if ENABLED(JOYSTICK)
+ void jog(const xyz_float_t &dir);
+ void _joystick_update(xyz_float_t &norm_jog);
+ #endif
+
+ /**
+ * Getters and setters
+ * Should be used by the EXTENSIBLE_UI to query or change Marlin's state.
+ */
+ PGM_P getFirmwareName_str();
+
+ #if HAS_SOFTWARE_ENDSTOPS
+ bool getSoftEndstopState();
+ void setSoftEndstopState(const bool);
+ #endif
+
+ #if HAS_TRINAMIC_CONFIG
+ float getAxisCurrent_mA(const axis_t);
+ float getAxisCurrent_mA(const extruder_t);
+ void setAxisCurrent_mA(const float, const axis_t);
+ void setAxisCurrent_mA(const float, const extruder_t);
+
+ int getTMCBumpSensitivity(const axis_t);
+ void setTMCBumpSensitivity(const float, const axis_t);
+ #endif
+
+ float getActualTemp_celsius(const heater_t);
+ float getActualTemp_celsius(const extruder_t);
+ float getTargetTemp_celsius(const heater_t);
+ float getTargetTemp_celsius(const extruder_t);
+ float getTargetFan_percent(const fan_t);
+ float getActualFan_percent(const fan_t);
+ float getAxisPosition_mm(const axis_t);
+ float getAxisPosition_mm(const extruder_t);
+ float getAxisSteps_per_mm(const axis_t);
+ float getAxisSteps_per_mm(const extruder_t);
+ feedRate_t getAxisMaxFeedrate_mm_s(const axis_t);
+ feedRate_t getAxisMaxFeedrate_mm_s(const extruder_t);
+ float getAxisMaxAcceleration_mm_s2(const axis_t);
+ float getAxisMaxAcceleration_mm_s2(const extruder_t);
+ feedRate_t getMinFeedrate_mm_s();
+ feedRate_t getMinTravelFeedrate_mm_s();
+ float getPrintingAcceleration_mm_s2();
+ float getRetractAcceleration_mm_s2();
+ float getTravelAcceleration_mm_s2();
+ float getFeedrate_percent();
+ int16_t getFlowPercentage(const extruder_t);
+
+ inline uint8_t getProgress_percent() { return ui.get_progress_percent(); }
+
+ #if HAS_PRINT_PROGRESS_PERMYRIAD
+ inline uint16_t getProgress_permyriad() { return ui.get_progress_permyriad(); }
+ #endif
+
+ uint32_t getProgress_seconds_elapsed();
+
+ #if ENABLED(SHOW_REMAINING_TIME)
+ inline uint32_t getProgress_seconds_remaining() { return ui.get_remaining_time(); }
+ #endif
+
+ #if HAS_LEVELING
+ bool getLevelingActive();
+ void setLevelingActive(const bool);
+ bool getMeshValid();
+ #if HAS_MESH
+ bed_mesh_t& getMeshArray();
+ float getMeshPoint(const xy_uint8_t &pos);
+ void setMeshPoint(const xy_uint8_t &pos, const float zval);
+ void onMeshLevelingStart();
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval);
+ inline void onMeshUpdate(const xy_int8_t &pos, const float zval) { onMeshUpdate(pos.x, pos.y, zval); }
+
+ typedef enum : uint8_t {
+ MESH_START, // Prior to start of probe
+ MESH_FINISH, // Following probe of all points
+ PROBE_START, // Beginning probe of grid location
+ PROBE_FINISH // Finished probe of grid location
+ } probe_state_t;
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, probe_state_t state);
+ inline void onMeshUpdate(const xy_int8_t &pos, probe_state_t state) { onMeshUpdate(pos.x, pos.y, state); }
+ #endif
+ #endif
+
+ #if ENABLED(HOST_PROMPT_SUPPORT)
+ void setHostResponse(const uint8_t);
+ #endif
+
+ #if ENABLED(PRINTCOUNTER)
+ char* getTotalPrints_str(char buffer[21]);
+ char* getFinishedPrints_str(char buffer[21]);
+ char* getTotalPrintTime_str(char buffer[21]);
+ char* getLongestPrint_str(char buffer[21]);
+ char* getFilamentUsed_str(char buffer[21]);
+ #endif
+
+ void setTargetTemp_celsius(const float, const heater_t);
+ void setTargetTemp_celsius(const float, const extruder_t);
+ void setTargetFan_percent(const float, const fan_t);
+ void setAxisPosition_mm(const float, const axis_t, const feedRate_t=0);
+ void setAxisPosition_mm(const float, const extruder_t, const feedRate_t=0);
+ void setAxisSteps_per_mm(const float, const axis_t);
+ void setAxisSteps_per_mm(const float, const extruder_t);
+ void setAxisMaxFeedrate_mm_s(const feedRate_t, const axis_t);
+ void setAxisMaxFeedrate_mm_s(const feedRate_t, const extruder_t);
+ void setAxisMaxAcceleration_mm_s2(const float, const axis_t);
+ void setAxisMaxAcceleration_mm_s2(const float, const extruder_t);
+ void setFeedrate_mm_s(const feedRate_t);
+ void setMinFeedrate_mm_s(const feedRate_t);
+ void setMinTravelFeedrate_mm_s(const feedRate_t);
+ void setPrintingAcceleration_mm_s2(const float);
+ void setRetractAcceleration_mm_s2(const float);
+ void setTravelAcceleration_mm_s2(const float);
+ void setFeedrate_percent(const float);
+ void setFlow_percent(const int16_t, const extruder_t);
+ bool awaitingUserConfirm();
+ void setUserConfirmed();
+
+ #if ENABLED(LIN_ADVANCE)
+ float getLinearAdvance_mm_mm_s(const extruder_t);
+ void setLinearAdvance_mm_mm_s(const float, const extruder_t);
+ #endif
+
+ #if HAS_JUNCTION_DEVIATION
+ float getJunctionDeviation_mm();
+ void setJunctionDeviation_mm(const float);
+ #else
+ float getAxisMaxJerk_mm_s(const axis_t);
+ float getAxisMaxJerk_mm_s(const extruder_t);
+ void setAxisMaxJerk_mm_s(const float, const axis_t);
+ void setAxisMaxJerk_mm_s(const float, const extruder_t);
+ #endif
+
+ extruder_t getActiveTool();
+ void setActiveTool(const extruder_t, bool no_move);
+
+ #if ENABLED(BABYSTEPPING)
+ int16_t mmToWholeSteps(const float mm, const axis_t axis);
+
+ bool babystepAxis_steps(const int16_t steps, const axis_t axis);
+ void smartAdjustAxis_steps(const int16_t steps, const axis_t axis, bool linked_nozzles);
+ #endif
+
+ #if HAS_HOTEND_OFFSET
+ float getNozzleOffset_mm(const axis_t, const extruder_t);
+ void setNozzleOffset_mm(const float, const axis_t, const extruder_t);
+ void normalizeNozzleOffset(const axis_t axis);
+ #endif
+
+ float getZOffset_mm();
+ void setZOffset_mm(const float);
+
+ #if HAS_BED_PROBE
+ float getProbeOffset_mm(const axis_t);
+ void setProbeOffset_mm(const float, const axis_t);
+ #endif
+
+ #if ENABLED(BACKLASH_GCODE)
+ float getAxisBacklash_mm(const axis_t);
+ void setAxisBacklash_mm(const float, const axis_t);
+
+ float getBacklashCorrection_percent();
+ void setBacklashCorrection_percent(const float);
+
+ #ifdef BACKLASH_SMOOTHING_MM
+ float getBacklashSmoothing_mm();
+ void setBacklashSmoothing_mm(const float);
+ #endif
+ #endif
+
+ #if HAS_FILAMENT_SENSOR
+ bool getFilamentRunoutEnabled();
+ void setFilamentRunoutEnabled(const bool);
+ bool getFilamentRunoutState();
+ void setFilamentRunoutState(const bool);
+
+ #if HAS_FILAMENT_RUNOUT_DISTANCE
+ float getFilamentRunoutDistance_mm();
+ void setFilamentRunoutDistance_mm(const float);
+ #endif
+ #endif
+
+ #if ENABLED(CASE_LIGHT_ENABLE)
+ bool getCaseLightState();
+ void setCaseLightState(const bool);
+
+ #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS)
+ float getCaseLightBrightness_percent();
+ void setCaseLightBrightness_percent(const float);
+ #endif
+ #endif
+
+ #if ENABLED(PIDTEMP)
+ float getPIDValues_Kp(const extruder_t);
+ float getPIDValues_Ki(const extruder_t);
+ float getPIDValues_Kd(const extruder_t);
+ void setPIDValues(const float, const float, const float, extruder_t);
+ void startPIDTune(const float, extruder_t);
+ #endif
+
+ #if ENABLED(PIDTEMPBED)
+ float getBedPIDValues_Kp();
+ float getBedPIDValues_Ki();
+ float getBedPIDValues_Kd();
+ void setBedPIDValues(const float, const float, const float);
+ void startBedPIDTune(const float);
+ #endif
+
+ /**
+ * Delay and timing routines
+ * Should be used by the EXTENSIBLE_UI to safely pause or measure time
+ * safe_millis must be called at least every 1 sec to guarantee time
+ * yield should be called within lengthy loops
+ */
+ #ifdef __SAM3X8E__
+ uint32_t safe_millis();
+ #else
+ FORCE_INLINE uint32_t safe_millis() { return millis(); } // TODO: Implement for AVR
+ #endif
+
+ void delay_us(uint32_t us);
+ void delay_ms(uint32_t ms);
+ void yield();
+
+ /**
+ * Media access routines
+ *
+ * Should be used by the EXTENSIBLE_UI to operate on files
+ */
+ bool isMediaInserted();
+ bool isPrintingFromMediaPaused();
+ bool isPrintingFromMedia();
+ bool isPrinting();
+ bool isPrintingPaused();
+
+ void printFile(const char *filename);
+ void stopPrint();
+ void pausePrint();
+ void resumePrint();
+
+ class FileList {
+ private:
+ uint16_t num_files;
+
+ public:
+ FileList();
+ void refresh();
+ bool seek(const uint16_t, const bool skip_range_check = false);
+
+ const char *longFilename();
+ const char *shortFilename();
+ const char *filename();
+ bool isDir();
+
+ void changeDir(const char * const dirname);
+ void upDir();
+ bool isAtRootDir();
+ uint16_t count();
+ };
+
+ /**
+ * Event callback routines
+ *
+ * Should be declared by EXTENSIBLE_UI and will be called by Marlin
+ */
+ void onStartup();
+ void onIdle();
+ void onMediaInserted();
+ void onMediaError();
+ void onMediaRemoved();
+ void onPlayTone(const uint16_t frequency, const uint16_t duration);
+ void onPrinterKilled(PGM_P const error, PGM_P const component);
+ void onPrintTimerStarted();
+ void onPrintTimerPaused();
+ void onPrintTimerStopped();
+ void onPrintFinished();
+ void onFilamentRunout(const extruder_t extruder);
+ void onUserConfirmRequired(const char * const msg);
+ void onUserConfirmRequired_P(PGM_P const pstr);
+ void onStatusChanged(const char * const msg);
+ void onStatusChanged_P(PGM_P const pstr);
+ void onHomingStart();
+ void onHomingComplete();
+ void onSteppersDisabled();
+ void onSteppersEnabled();
+ void onFactoryReset();
+ void onStoreSettings(char *);
+ void onLoadSettings(const char *);
+ void onConfigurationStoreWritten(bool success);
+ void onConfigurationStoreRead(bool success);
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume();
+ #endif
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst);
+ #endif
+};
+
+/**
+ * Helper macros to increment or decrement a value. For example:
+ *
+ * UI_INCREMENT_BY(TargetTemp_celsius, 10, E0)
+ *
+ * Expands to:
+ *
+ * setTargetTemp_celsius(getTargetTemp_celsius(E0) + 10, E0);
+ *
+ * Or, in the case where a constant increment is desired:
+ *
+ * constexpr float increment = 10;
+ *
+ * UI_INCREMENT(TargetTemp_celsius, E0)
+ */
+#define UI_INCREMENT_BY(method, inc, ...) ExtUI::set ## method(ExtUI::get ## method (__VA_ARGS__) + inc, ##__VA_ARGS__)
+#define UI_DECREMENT_BY(method, inc, ...) ExtUI::set ## method(ExtUI::get ## method (__VA_ARGS__) - inc, ##__VA_ARGS__)
+
+#define UI_INCREMENT(method, ...) UI_INCREMENT_BY(method, increment, ##__VA_ARGS__)
+#define UI_DECREMENT(method, ...) UI_DECREMENT_BY(method, increment, ##__VA_ARGS__)