├── case ├── reppanel_stp.zip ├── reppanelcover_back_v1_3.stl └── reppanelcover_front_v1_3.stl ├── wiki ├── RepPanel_Job.png ├── RepPanel_Main.png ├── Wiring_ERTFT.jpg ├── Wiring_ERTFT_2.jpg ├── RepPanel_Console.png ├── RepPanel_JobStatus.png ├── RepPanel_Process.png ├── RepPanel_Working.jpg ├── RepPanel_with_case.png ├── NodeMCU_ESP32_Pinout.jpg ├── RepPanel_Console_NoKeyboard.png └── Wiring_ESP32_DevKit_38GPIOs.jpg ├── main ├── images_orig │ ├── g1407.png │ ├── g4936.png │ ├── g929.png │ ├── g971.png │ ├── play.png │ ├── stop.png │ ├── path1539.png │ ├── path3772.png │ ├── path3776.png │ ├── path4591.png │ ├── path6422.png │ ├── path6438.png │ ├── path6454.png │ ├── noti_bell.png │ ├── chamber_temp.png │ ├── console_button.png │ ├── fast_forward_32.png │ └── main_menue_button.png ├── reppanel_img_decoder.h ├── reppanel_macros.h ├── screen_saver.h ├── reppanel_machine.h ├── reppanel_info.h ├── reppanel_jobselect.h ├── rrf_objects.c ├── main.h ├── esp32_uart.h ├── reppanel_jobstatus.h ├── CMakeLists.txt ├── esp32_wifi.h ├── reppanel_process.h ├── reppanel_console.h ├── esp32_settings.h ├── reppanel_helper.h ├── reppanel_request.h ├── screen_saver.c ├── duet_status_json.h ├── rrf3_object_model_parser.h ├── Kconfig ├── custom_themes │ └── lv_theme_rep_panel_dark.h ├── rrf_objects.h ├── esp32_settings.c ├── reppanel_img_decoder.c ├── reppanel_helper.c ├── main.c ├── reppanel_macros.c ├── reppanel.h ├── esp32_uart.c ├── reppanel_console.c ├── fonts │ └── reppanel_font_roboto_regular_percent_40.c ├── reppanel_jobselect.c ├── reppanel_info.c ├── esp32_wifi.c └── images │ ├── arrowgoleft.c │ └── arrowgoright.c ├── partitions.csv ├── .gitmodules ├── debug_responses ├── RRF3_0_0 │ ├── filament_response.json │ ├── file_info.json │ ├── macro_response.json │ ├── example_response.json │ ├── message_response.json │ ├── printing.json │ ├── reprap_status_2.json │ ├── duet_serial.txt │ └── dwc2_config.json └── RRF3_1_0 │ ├── file_info.json │ ├── macro_response.json │ ├── job.json │ ├── state.json │ ├── dwc-settings.json │ ├── d99fn.json │ └── move.json ├── CMakeLists.txt ├── NOTICE ├── .github └── workflows │ └── build_supported_platforms.yml ├── .gitignore ├── README.md └── LICENSE.md /case/reppanel_stp.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/case/reppanel_stp.zip -------------------------------------------------------------------------------- /wiki/RepPanel_Job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_Job.png -------------------------------------------------------------------------------- /wiki/RepPanel_Main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_Main.png -------------------------------------------------------------------------------- /wiki/Wiring_ERTFT.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/Wiring_ERTFT.jpg -------------------------------------------------------------------------------- /wiki/Wiring_ERTFT_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/Wiring_ERTFT_2.jpg -------------------------------------------------------------------------------- /main/images_orig/g1407.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/g1407.png -------------------------------------------------------------------------------- /main/images_orig/g4936.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/g4936.png -------------------------------------------------------------------------------- /main/images_orig/g929.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/g929.png -------------------------------------------------------------------------------- /main/images_orig/g971.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/g971.png -------------------------------------------------------------------------------- /main/images_orig/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/play.png -------------------------------------------------------------------------------- /main/images_orig/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/stop.png -------------------------------------------------------------------------------- /wiki/RepPanel_Console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_Console.png -------------------------------------------------------------------------------- /wiki/RepPanel_JobStatus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_JobStatus.png -------------------------------------------------------------------------------- /wiki/RepPanel_Process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_Process.png -------------------------------------------------------------------------------- /wiki/RepPanel_Working.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_Working.jpg -------------------------------------------------------------------------------- /wiki/RepPanel_with_case.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_with_case.png -------------------------------------------------------------------------------- /main/images_orig/path1539.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/path1539.png -------------------------------------------------------------------------------- /main/images_orig/path3772.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/path3772.png -------------------------------------------------------------------------------- /main/images_orig/path3776.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/path3776.png -------------------------------------------------------------------------------- /main/images_orig/path4591.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/path4591.png -------------------------------------------------------------------------------- /main/images_orig/path6422.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/path6422.png -------------------------------------------------------------------------------- /main/images_orig/path6438.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/path6438.png -------------------------------------------------------------------------------- /main/images_orig/path6454.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/path6454.png -------------------------------------------------------------------------------- /wiki/NodeMCU_ESP32_Pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/NodeMCU_ESP32_Pinout.jpg -------------------------------------------------------------------------------- /case/reppanelcover_back_v1_3.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/case/reppanelcover_back_v1_3.stl -------------------------------------------------------------------------------- /main/images_orig/noti_bell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/noti_bell.png -------------------------------------------------------------------------------- /case/reppanelcover_front_v1_3.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/case/reppanelcover_front_v1_3.stl -------------------------------------------------------------------------------- /main/images_orig/chamber_temp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/chamber_temp.png -------------------------------------------------------------------------------- /main/images_orig/console_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/console_button.png -------------------------------------------------------------------------------- /main/images_orig/fast_forward_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/fast_forward_32.png -------------------------------------------------------------------------------- /wiki/RepPanel_Console_NoKeyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/RepPanel_Console_NoKeyboard.png -------------------------------------------------------------------------------- /wiki/Wiring_ESP32_DevKit_38GPIOs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/wiki/Wiring_ESP32_DevKit_38GPIOs.jpg -------------------------------------------------------------------------------- /main/images_orig/main_menue_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seeul8er/RepPanel_ESP32/HEAD/main/images_orig/main_menue_button.png -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # RepPanel ESP32 Partition Table 2 | # Name, Type, SubType, Offset, Size, Flags 3 | nvs, data, nvs, 0x9000, 0x6000, 4 | phy_init, data, phy, 0xf000, 0x1000, 5 | factory, app, factory, 0x10000, 2M, 6 | 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "externals/lv_port_esp32"] 2 | path = externals/lv_port_esp32 3 | url = https://github.com/seeul8er/lv_port_esp32.git 4 | [submodule "externals/qoi"] 5 | path = externals/qoi 6 | url = https://github.com/phoboslab/qoi.git 7 | -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/filament_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "dir": "0:/filaments", 3 | "first": 0, 4 | "files": [ 5 | { 6 | "type": "d", 7 | "name": "PLA white TEQstone", 8 | "size": 0, 9 | "date": "2019-12-29T21:03:09" 10 | } 11 | ], 12 | "next": 0 13 | } -------------------------------------------------------------------------------- /main/reppanel_img_decoder.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2022 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_REPPANEL_IMG_DECODER_H 6 | #define REPPANEL_ESP32_REPPANEL_IMG_DECODER_H 7 | 8 | #endif //REPPANEL_ESP32_REPPANEL_IMG_DECODER_H 9 | -------------------------------------------------------------------------------- /debug_responses/RRF3_1_0/file_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "err": 0, 3 | "size": 46357299, 4 | "lastModified": "2022-01-25T20:49:30", 5 | "height": 300.00, 6 | "firstLayerHeight": 0.20, 7 | "layerHeight": 0.20, 8 | "printTime": 76773, 9 | "filament": [ 10 | 310244.8 11 | ], 12 | "generatedBy": "SuperSlicer 2.3.57 on 2022-01-25 at 19:49:05 UTC" 13 | } 14 | -------------------------------------------------------------------------------- /main/reppanel_macros.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_REPPANEL_MACROS_H 6 | #define REPPANEL_ESP32_REPPANEL_MACROS_H 7 | 8 | void draw_macro(lv_obj_t *parent_screen); 9 | 10 | void update_macro_list_ui(); 11 | 12 | #endif //REPPANEL_ESP32_REPPANEL_MACROS_H 13 | -------------------------------------------------------------------------------- /main/screen_saver.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_SCREEN_SAVER_H 6 | #define REPPANEL_ESP32_SCREEN_SAVER_H 7 | 8 | #include 9 | 10 | void activate_screen_saver(); 11 | void deactivate_screen_saver(); 12 | 13 | #endif //REPPANEL_ESP32_SCREEN_SAVER_H 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | set(EXTRA_COMPONENT_DIRS 4 | externals/lv_port_esp32/components/lvgl_esp32_drivers 5 | externals/lv_port_esp32/components/lvgl_esp32_drivers/lvgl_touch 6 | externals/lv_port_esp32/components/lvgl_esp32_drivers/lvgl_tft 7 | externals/lv_port_esp32/components/lvgl) 8 | 9 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 10 | 11 | project(reppanel_esp32) 12 | -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/file_info.json: -------------------------------------------------------------------------------- 1 | { 2 | "err": 0, 3 | "size": 7623761, 4 | "lastModified": "2020-03-19T14:47:02", 5 | "height": 44.10, 6 | "firstLayerHeight": 0.30, 7 | "layerHeight": 0.15, 8 | "printTime": 4830, 9 | "simulatedTime": 13891, 10 | "filament": [ 11 | 4026.3 12 | ], 13 | "printDuration": 245, 14 | "fileName": "0:/gcodes/CFFFP_v3-solid-virus.gcode", 15 | "generatedBy": "Cura_SteamEngine 4.5.0" 16 | } -------------------------------------------------------------------------------- /main/reppanel_machine.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | 7 | #ifndef LVGL_REPPANEL_MACHINE_H 8 | #define LVGL_REPPANEL_MACHINE_H 9 | 10 | void update_ui_machine(); 11 | void show_reprap_dialog(char *title, char *msg, uint8_t mode, bool show_height_adjust); 12 | void draw_machine(lv_obj_t *parent_screen); 13 | 14 | #endif //LVGL_REPPANEL_MACHINE_H 15 | -------------------------------------------------------------------------------- /main/reppanel_info.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LVGL_REPPANEL_INFO_H 6 | #define LVGL_REPPANEL_INFO_H 7 | 8 | #include 9 | 10 | extern lv_obj_t *ta_wifi_pass; 11 | extern lv_obj_t *ta_ssid; 12 | extern lv_obj_t *ta_printer_addr; 13 | extern lv_obj_t *ta_reprap_pass; 14 | 15 | void draw_info(lv_obj_t *parent_screen); 16 | 17 | #endif //LVGL_REPPANEL_INFO_H 18 | -------------------------------------------------------------------------------- /main/reppanel_jobselect.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LVGL_REPPANEL_JOBSELECT_H 6 | #define LVGL_REPPANEL_JOBSELECT_H 7 | 8 | #include 9 | #include "rrf_objects.h" 10 | 11 | void draw_jobselect(lv_obj_t *parent_screen); 12 | 13 | void update_job_list_ui(); 14 | 15 | void update_file_info_dialog_ui(reprap_model_t *_reprap_model); 16 | 17 | #endif //LVGL_REPPANEL_JOBSELECT_H 18 | -------------------------------------------------------------------------------- /main/rrf_objects.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include "rrf_objects.h" 7 | 8 | reprap_model_t reprap_model; 9 | 10 | /** 11 | * Init an empty reprap variable structure 12 | * @return An empty reprap_model_t structure to be filled by the parser 13 | */ 14 | reprap_model_t init_reprap_model() { 15 | memset(&reprap_model, 0, sizeof(reprap_model_t)); 16 | return reprap_model; 17 | } 18 | -------------------------------------------------------------------------------- /main/main.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | // 5 | 6 | #ifndef REPPANEL_ESP32_MAIN_H 7 | #define REPPANEL_ESP32_MAIN_H 8 | 9 | #include "freertos/FreeRTOS.h" 10 | #include 11 | 12 | // Creates a semaphore to handle concurrent call to lvgl stuff 13 | // If you wish to call *any* lvgl function from other threads/tasks 14 | // you should lock on the very same semaphore! 15 | extern SemaphoreHandle_t xGuiSemaphore; 16 | 17 | #endif //REPPANEL_ESP32_MAIN_H 18 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | RepPanel - Copyright 2020 Wolfgang Christl 2 | 3 | Dependencies: 4 | - esp-idf 4.x: Apache License 2.0 - Espressif Systems 5 | (https://github.com/espressif/esp-idf) 6 | 7 | - littlevgl v6.1.1: MIT licence - Copyright (c) 2016 Gábor Kiss-Vámosi 8 | (https://github.com/littlevgl/lvgl) 9 | 10 | - lv_port_esp32: MIT licence - Copyright (c) 2019 Littlev Graphics Library 11 | (https://github.com/littlevgl/lv_port_esp32) 12 | 13 | - Google Material icons: Apache License 2.0 14 | 15 | - Google Roboto font: Apache License 2.0 16 | (https://fonts.google.com/specimen/Roboto) 17 | -------------------------------------------------------------------------------- /main/esp32_uart.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | // 5 | 6 | #ifndef REPPANEL_ESP32_ESP32_UART_H 7 | #define REPPANEL_ESP32_ESP32_UART_H 8 | 9 | #include "reppanel_request.h" 10 | 11 | #define UART_MAX_READ_TIMEOUT_CNT 5 12 | #define UART_DATA_BUFF_LEN 0 13 | 14 | void init_uart(); 15 | void reppanel_write_uart(char *buffer, int buffer_len); 16 | void esp32_flush_uart(); 17 | bool reppanel_is_uart_connected(); 18 | bool reppanel_read_response(uart_response_buff_t *receive_buff); 19 | 20 | #endif //REPPANEL_ESP32_ESP32_UART_H 21 | -------------------------------------------------------------------------------- /main/reppanel_jobstatus.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_REPPANEL_JOBSTATUS_H 6 | #define REPPANEL_ESP32_REPPANEL_JOBSTATUS_H 7 | 8 | #include 9 | 10 | extern lv_obj_t *label_job_progress_percent; 11 | extern lv_obj_t *label_job_elapsed_time; 12 | extern lv_obj_t *label_job_remaining_time; 13 | extern lv_obj_t *label_job_layer_status; 14 | extern lv_obj_t *label_job_filename; 15 | 16 | void draw_jobstatus(lv_obj_t *parent_screen); 17 | 18 | void update_print_job_status_ui(); 19 | 20 | #endif //REPPANEL_ESP32_REPPANEL_JOBSTATUS_H 21 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | set(COMPONENT_REQUIRES nvs_flash lvgl_touch lvgl_tft lvgl esp_http_client json mdns lvgl_esp32_drivers) 4 | set(COMPONENT_PRIV_REQUIRES) 5 | 6 | file(GLOB_RECURSE INCLUDES "*.h" "lv_drivers/*.h" "lv_examples/*.h" "lvgl/*.h" "./*.h" "custom_themes/lv_theme_rep_panel_dark.h") 7 | file(GLOB_RECURSE SOURCES "*.c" "lv_drivers/*.c" "lv_examples/*.c" "lvgl/*.c" "./*.c" "custom_themes/lv_theme_rep_panel_dark.c" "custom_themes/*.c" "images/*.c" fonts/*.c) 8 | 9 | file(GLOB_RECURSE QOI "../externals/qoi/qoi.h") 10 | 11 | set(COMPONENT_SRCS main.c ${INCLUDES} ${SOURCES} ${QOI}) 12 | 13 | set(COMPONENT_ADD_INCLUDEDIRS ".") 14 | 15 | register_component() 16 | -------------------------------------------------------------------------------- /main/esp32_wifi.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_ESP32_WIFI_H 6 | #define REPPANEL_ESP32_ESP32_WIFI_H 7 | 8 | void find_mdns_service(const char *service_name, const char *proto); 9 | int resolve_mdns_host(const char *host_name, char *result_ip); 10 | 11 | #if ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 3 12 | void wifi_init_sta_4_3(); 13 | #else 14 | void wifi_init_sta(); 15 | #endif 16 | 17 | void reconnect_wifi(); 18 | 19 | void get_connection_info(char txt_buffer[200]); 20 | 21 | void get_avail_wifi_networks(char *aps); 22 | 23 | #endif //REPPANEL_ESP32_ESP32_WIFI_H 24 | -------------------------------------------------------------------------------- /main/reppanel_process.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LVGL_REPPANEL_PROCESS_H 6 | #define LVGL_REPPANEL_PROCESS_H 7 | 8 | #include "esp32_settings.h" 9 | 10 | void draw_process(lv_obj_t *parent_screen); 11 | 12 | void update_heater_status_ui(const int *states, int _num_heaters); 13 | 14 | void update_bed_temps_ui(); 15 | 16 | void update_process_status_ui(); 17 | 18 | void update_header_temp_ui(); 19 | 20 | 21 | extern lv_obj_t *label_bed_temp_active; 22 | extern lv_obj_t *label_bed_temp_standby; 23 | extern lv_obj_t *label_tool_temp_active; 24 | extern lv_obj_t *label_tool_temp_standby; 25 | 26 | #endif //LVGL_REPPANEL_PROCESS_H 27 | -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/macro_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "dir": "0:/macros", 3 | "first": 0, 4 | "files": [ 5 | { 6 | "type": "f", 7 | "name": "01-Test_IR_PD_Homing", 8 | "size": 641, 9 | "date": "2019-03-12T11:49:22" 10 | }, 11 | { 12 | "type": "f", 13 | "name": "02-Test_Fans", 14 | "size": 640, 15 | "date": "2018-05-30T14:58:14" 16 | }, 17 | { 18 | "type": "f", 19 | "name": "03-Test_Heaters", 20 | "size": 1099, 21 | "date": "2018-05-24T15:23:29" 22 | }, 23 | { 24 | "type": "f", 25 | "name": "04-Test_motors", 26 | "size": 2223, 27 | "date": "2019-03-12T11:58:23" 28 | }, 29 | { 30 | "type": "f", 31 | "name": "SETNETWORK", 32 | "size": 145, 33 | "date": "2017-08-14T18:02:12" 34 | } 35 | ], 36 | "next": 0 37 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_1_0/macro_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "dir": "0:/macros/", 3 | "first": 0, 4 | "files": [ 5 | { 6 | "type": "f", 7 | "name": "Unload PLA", 8 | "size": 532, 9 | "date": "2020-04-12T20:18:58" 10 | }, 11 | { 12 | "type": "d", 13 | "name": "Accelleration Tuning", 14 | "size": 0, 15 | "date": "2018-07-25T22:45:58" 16 | }, 17 | { 18 | "type": "d", 19 | "name": "Jerk Tuning", 20 | "size": 0, 21 | "date": "2018-07-25T22:39:22" 22 | }, 23 | { 24 | "type": "d", 25 | "name": "Pressure Advance Tuning", 26 | "size": 0, 27 | "date": "2018-07-26T00:44:30" 28 | }, 29 | { 30 | "type": "d", 31 | "name": "Retraction Tuning", 32 | "size": 0, 33 | "date": "2018-07-26T00:50:50" 34 | } 35 | ], 36 | "next": 0 37 | } -------------------------------------------------------------------------------- /main/reppanel_console.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LVGL_REPPANEL_CONSOLE_H 6 | #define LVGL_REPPANEL_CONSOLE_H 7 | 8 | #include 9 | 10 | #define MAX_CONSOLE_ENTRY_COUNT 16 11 | #define MAX_LEN_COMMAND 32 12 | #define MAX_LEN_RESPONSE 128 13 | 14 | enum console_msg_type { 15 | CONSOLE_TYPE_EMPTY, CONSOLE_TYPE_INFO, CONSOLE_TYPE_WARN, CONSOLE_TYPE_REPPANEL 16 | }; 17 | 18 | void add_console_hist_entry(char *command, enum console_msg_type type); 19 | 20 | void draw_console(lv_obj_t *parent_screen); 21 | 22 | void update_entries_ui(); 23 | 24 | typedef struct { 25 | char command[MAX_LEN_COMMAND]; 26 | // char response[MAX_LEN_RESPONSE]; 27 | enum console_msg_type type; 28 | } console_entry_t; 29 | 30 | extern console_entry_t console_enties[MAX_CONSOLE_ENTRY_COUNT]; 31 | 32 | #endif //LVGL_REPPANEL_CONSOLE_H 33 | -------------------------------------------------------------------------------- /.github/workflows/build_supported_platforms.yml: -------------------------------------------------------------------------------- 1 | name: Build RepPanel for all HW platforms 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build_ER-TFT: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout repo 16 | uses: actions/checkout@v2 17 | with: 18 | submodules: 'recursive' 19 | - name: Setting ER-TFT configuration (HWv1) 20 | run: cp sdkconfig_ERTFT_WIFI_esp_idf_40 sdkconfig 21 | - name: esp-idf build 22 | uses: espressif/esp-idf-ci-action@release-v4.0 23 | 24 | build_HWv2: 25 | 26 | runs-on: ubuntu-latest 27 | 28 | steps: 29 | - name: Checkout repo 30 | uses: actions/checkout@v2 31 | with: 32 | submodules: 'recursive' 33 | - name: Setting ER-TFT configuration (HWv2) 34 | run: cp sdkconfig_HWv2_esp_idf_43 sdkconfig 35 | - name: esp-idf build 36 | uses: espressif/esp-idf-ci-action@release-v4.3 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | 13 | .idea/ 14 | 15 | build/ 16 | 17 | cmake-build-debug/ 18 | 19 | cmake-build-debug-xtensa-2019r2-820/ 20 | 21 | cmake-build-debug-xtensa-2020r1-820/mconf-idf-prefix/tmp/ 22 | 23 | cmake-build-debug-xtensa-2020r1-820/ 24 | 25 | cmake-build-debug-xtensa-2020r2/ 26 | 27 | cmake-build-debug-xtensa-2020r3/ 28 | 29 | cmake-build-release-xtensa-2020r1-820/ 30 | 31 | cmake-build-release-xtensa-2020r2/ 32 | 33 | cmake-build-release-xtensa-2020r3/ 34 | 35 | cmake-build-debug-mingw/ 36 | 37 | cmake-build-release-xtensa/ 38 | 39 | cmake-build-debug-xtensa/ 40 | 41 | cmake-build-debug-mingw-esp-idf-400/ 42 | 43 | cmake-build-debug-mingw-esp-idf-43/ 44 | 45 | cmake-build-esp-idf-404/ 46 | 47 | cmake-build-esp-idf-404-release/ 48 | 49 | cmake-build-esp-idf-404-debug/ 50 | 51 | cmake-build-esp-idf-43-debug/ 52 | -------------------------------------------------------------------------------- /main/esp32_settings.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LVGL_REPPANEL_SETTINGS_H 6 | #define LVGL_REPPANEL_SETTINGS_H 7 | 8 | #define MAX_NUM_TOOLS 5 9 | 10 | #define REPPANEL_NVS "settings" 11 | #define NVS_KEY_WIFI_SSID "ssid" 12 | #define NVS_KEY_WIFI_PASS "wifi_pass" 13 | #define NVS_KEY_REPRAP_ADDR "rep_addr" 14 | #define NVS_KEY_REPRAP_PASS "rep_pass" 15 | 16 | #define MAX_SSID_LEN 32 17 | #define MAX_WIFI_PASS_LEN 64 18 | #define MAX_REP_ADDR_LEN 128 19 | #define MAX_REP_PASS_LEN 64 20 | 21 | extern char wifi_ssid[MAX_SSID_LEN]; 22 | extern char wifi_pass[MAX_REP_PASS_LEN]; 23 | extern char rep_addr[MAX_REP_ADDR_LEN]; 24 | extern char rep_pass[MAX_REP_PASS_LEN]; 25 | extern int temp_unit; // 0=Celsius, 1=Fahrenheit 26 | 27 | void write_settings_to_nvs(); 28 | 29 | void read_settings_nvs(); 30 | 31 | char get_temp_unit(); 32 | 33 | #endif //LVGL_REPPANEL_SETTINGS_H 34 | -------------------------------------------------------------------------------- /main/reppanel_helper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LVGL_REPPANEL_HELPER_H 6 | #define LVGL_REPPANEL_HELPER_H 7 | 8 | #include 9 | #include 10 | 11 | LV_FONT_DECLARE(reppanel_font_roboto_light_36) 12 | LV_FONT_DECLARE(reppanel_font_roboto_bold_22) 13 | LV_FONT_DECLARE(reppanel_font_roboto_regular_22) 14 | 15 | char *get_version_string(); 16 | 17 | char *url_encode(unsigned char *s, char *enc); 18 | 19 | bool ends_with(const char *base, char *str); 20 | 21 | void init_reprap_buffers(); 22 | 23 | lv_obj_t *create_button(lv_obj_t *parent, lv_obj_t *button_pnt, char *text, void *event_handler); 24 | 25 | void get_avail_duets(char *txt_buffer); 26 | 27 | time_t datestr_2unix(const char *input); 28 | 29 | int compare_tree_element_timestamp(const void *a, const void *b); 30 | 31 | void RepPanelLogE(char *tag, char *msg); 32 | 33 | void RepPanelLogW(char *tag, char *msg); 34 | 35 | void RepPanelLogI(char *tag, char *msg); 36 | 37 | void RepPanelLogD(char *tag, char *msg); 38 | 39 | void RepPanelLogV(char *tag, char *msg); 40 | 41 | #endif //LVGL_REPPANEL_HELPER_H 42 | -------------------------------------------------------------------------------- /debug_responses/RRF3_1_0/job.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "job", 3 | "flags": "d99vn", 4 | "result": { 5 | "build": { 6 | "currentObject": 0, 7 | "m486Names": false, 8 | "m486Numbers": false, 9 | "objects": [ 10 | { 11 | "cancelled": false, 12 | "name": "topf_210823.stl", 13 | "x": [ 14 | 56, 15 | 140 16 | ], 17 | "y": [ 18 | 111, 19 | 195 20 | ] 21 | } 22 | ] 23 | }, 24 | "duration": 6027, 25 | "file": { 26 | "filament": [], 27 | "fileName": "0:/gcodes/Johannes/Topf_upside_down.gcode", 28 | "firstLayerHeight": 0.2, 29 | "generatedBy": "ideaMaker 4.1.1.5050, 2021-08-28 10:08:29 UTC+0200", 30 | "height": 170, 31 | "lastModified": "2021-08-28T10:11:18", 32 | "layerHeight": 0.2, 33 | "numLayers": 850, 34 | "printTime": 68234, 35 | "simulatedTime": null, 36 | "size": 27301532 37 | }, 38 | "filePosition": 1531655, 39 | "lastDuration": null, 40 | "lastFileName": null, 41 | "layer": 54, 42 | "layerTime": 23.1, 43 | "pauseDuration": 0, 44 | "rawExtrusion": 14843.6, 45 | "timesLeft": { 46 | "filament": null, 47 | "file": 152354, 48 | "slicer": 62186 49 | }, 50 | "warmUpDuration": 0 51 | } 52 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/example_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "I", 3 | "coords": { 4 | "axesHomed": [ 5 | 0, 6 | 0, 7 | 0 8 | ], 9 | "wpl": 1, 10 | "xyz": [ 11 | 0, 12 | 0, 13 | 0 14 | ], 15 | "machine": [ 16 | 0, 17 | 0, 18 | 0 19 | ], 20 | "extr": [ 21 | 0 22 | ] 23 | }, 24 | "speeds": { 25 | "requested": 0, 26 | "top": 0 27 | }, 28 | "currentTool": -1, 29 | "output": { 30 | "message": "Hello World!" 31 | }, 32 | "params": { 33 | "atxPower": -1, 34 | "fanPercent": [ 35 | 0, 36 | 0, 37 | 0 38 | ], 39 | "speedFactor": 100, 40 | "extrFactors": [ 41 | 100 42 | ], 43 | "babystep": 0 44 | }, 45 | "seq": 0, 46 | "sensors": { 47 | "ProbeValue": 1000, 48 | "fanRPM": [ 49 | -1, 50 | -1, 51 | -1 52 | ] 53 | }, 54 | "temps": { 55 | "bed": { 56 | "current": 22, 57 | "active": 0, 58 | "standby": 0, 59 | "state": 0, 60 | "heater": 0 61 | }, 62 | "current": [ 63 | 22, 64 | 20.7 65 | ], 66 | "state": [ 67 | 0, 68 | 0 69 | ], 70 | "tools": { 71 | "active": [ 72 | [ 73 | 0 74 | ] 75 | ], 76 | "standby": [ 77 | [ 78 | 0 79 | ] 80 | ] 81 | }, 82 | "extra": [] 83 | }, 84 | "time": 3091 85 | } -------------------------------------------------------------------------------- /main/reppanel_request.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_REPPANEL_REQUEST_H 6 | #define REPPANEL_ESP32_REPPANEL_REQUEST_H 7 | 8 | #define MAX_REQ_ADDR_LENGTH (256 + 512) 9 | #define JSON_BUFF_SIZE (1024 * 5) // d2wc settings is > 2800 bytes 10 | #define UART_RESP_BUFF_SIZE (1024 * 5) 11 | 12 | typedef struct { 13 | char buffer[JSON_BUFF_SIZE]; 14 | int buf_pos; 15 | } wifi_response_buff_t; 16 | 17 | typedef struct { 18 | uint8_t buffer[UART_RESP_BUFF_SIZE]; 19 | int buf_pos; 20 | } uart_response_buff_t; 21 | 22 | void request_reprap_status_updates(void *pvParameters); 23 | 24 | void reprap_wifi_download(wifi_response_buff_t *response_buffer, char *file); 25 | 26 | void reprap_wifi_get_config(); 27 | 28 | void reprap_wifi_get_fileinfo(wifi_response_buff_t *resp_data, char *filename); 29 | 30 | void reprap_wifi_get_filelist(wifi_response_buff_t *resp_buffer, char *directory); 31 | 32 | bool reprap_wifi_send_gcode(char *gcode); 33 | 34 | void request_macros(char *folder_path); 35 | 36 | void request_macros_async(char *folder_path); 37 | 38 | void request_jobs(char *folder_path); 39 | 40 | void request_jobs_async(char *folder_path); 41 | 42 | void trigger_request_fileinfo_curr_job(); 43 | 44 | void trigger_request_fileinfo(char *filepath); 45 | 46 | bool reprap_send_gcode(char *gcode_command); 47 | 48 | #endif //REPPANEL_ESP32_REPPANEL_REQUEST_H 49 | -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/message_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "B", 3 | "coords": { 4 | "axesHomed": [ 5 | 1, 6 | 1, 7 | 1 8 | ], 9 | "wpl": 1, 10 | "xyz": [ 11 | 163, 12 | 286, 13 | 5.7 14 | ], 15 | "machine": [ 16 | 163, 17 | 286, 18 | 5.7 19 | ], 20 | "extr": [ 21 | 0 22 | ] 23 | }, 24 | "speeds": { 25 | "requested": 0, 26 | "top": 0 27 | }, 28 | "currentTool": -1, 29 | "output": { 30 | "msgBox": { 31 | "msg": "Adjust height until the nozzle just touches the bed, then press OK", 32 | "title": "Manual bed probing", 33 | "mode": 2, 34 | "seq": 1, 35 | "timeout": 0, 36 | "controls": 4 37 | } 38 | }, 39 | "params": { 40 | "atxPower": -1, 41 | "fanPercent": [ 42 | 0, 43 | 30, 44 | 0 45 | ], 46 | "speedFactor": 100, 47 | "extrFactors": [ 48 | 100 49 | ], 50 | "babystep": 0 51 | }, 52 | "seq": 0, 53 | "sensors": { 54 | "probeValue": 1000, 55 | "fanRPM": [ 56 | -1, 57 | -1, 58 | -1 59 | ] 60 | }, 61 | "temps": { 62 | "bed": { 63 | "current": 20.6, 64 | "active": 0, 65 | "standby": 0, 66 | "state": 0, 67 | "heater": 0 68 | }, 69 | "current": [ 70 | 20.6, 71 | 20.7 72 | ], 73 | "state": [ 74 | 0, 75 | 0 76 | ], 77 | "tools": { 78 | "active": [ 79 | [ 80 | 0 81 | ] 82 | ], 83 | "standby": [ 84 | [ 85 | 0 86 | ] 87 | ] 88 | }, 89 | "extra": [] 90 | }, 91 | "time": 235 92 | } -------------------------------------------------------------------------------- /main/screen_saver.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include 7 | #include "screen_saver.h" 8 | #include "sdkconfig.h" 9 | #include "src/lv_core/lv_disp.h" 10 | #include "src/lv_objx/lv_cont.h" 11 | #define TAG "SCREEN_SAVER" 12 | 13 | bool screen_saver_active = false; 14 | 15 | lv_obj_t *screen_saver; 16 | 17 | 18 | void set_backlight(bool backlight_on) { 19 | if (CONFIG_LVGL_ENABLE_BACKLIGHT_CONTROL) { 20 | 21 | #if (CONFIG_LVGL_BACKLIGHT_ACTIVE_LVL==1) 22 | uint8_t tmp = backlight_on ? 1 : 0; 23 | #else 24 | uint8_t tmp = backlight_on ? 0 : 1; 25 | #endif 26 | gpio_set_level(CONFIG_LVGL_DISP_PIN_BCKL, tmp); 27 | } 28 | } 29 | 30 | void activate_screen_saver() { 31 | if (!screen_saver_active) { 32 | ESP_LOGI(TAG, "Activating screen saver"); 33 | set_backlight(false); 34 | screen_saver = lv_cont_create(lv_layer_top(), NULL); 35 | lv_cont_set_fit(screen_saver, LV_FIT_FILL); 36 | 37 | static lv_style_t style_screensaver; 38 | lv_style_copy(&style_screensaver, &lv_style_plain); 39 | style_screensaver.image.color = LV_COLOR_BLACK; 40 | lv_cont_set_style(screen_saver, LV_CONT_STYLE_MAIN, &style_screensaver); 41 | 42 | screen_saver_active = true; 43 | } 44 | } 45 | 46 | void deactivate_screen_saver() { 47 | if (screen_saver_active) { 48 | ESP_LOGI(TAG, "Deactivating screen saver"); 49 | set_backlight(true); 50 | if (screen_saver) lv_obj_del_async(screen_saver); 51 | screen_saver_active = false; 52 | } 53 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/printing.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "I", 3 | "coords": { 4 | "axesHomed": [ 5 | 0, 6 | 0, 7 | 0 8 | ], 9 | "wpl": 1, 10 | "xyz": [ 11 | 0.000, 12 | 0.000, 13 | 0.000 14 | ], 15 | "machine": [ 16 | 0.000, 17 | 0.000, 18 | 0.000 19 | ], 20 | "extr": [ 21 | -0.3 22 | ] 23 | }, 24 | "speeds": { 25 | "requested": 0.0, 26 | "top": 0.0 27 | }, 28 | "currentTool": 0, 29 | "params": { 30 | "atxPower": -1, 31 | "fanPercent": [ 32 | 0, 33 | 30, 34 | 0 35 | ], 36 | "speedFactor": 100.0, 37 | "extrFactors": [ 38 | 100.0 39 | ], 40 | "babystep": 0.000 41 | }, 42 | "seq": 2, 43 | "sensors": { 44 | "probeValue": 1000, 45 | "fanRPM": [ 46 | -1, 47 | -1, 48 | -1 49 | ] 50 | }, 51 | "temps": { 52 | "bed": { 53 | "current": 20.5, 54 | "active": 0.0, 55 | "standby": 0.0, 56 | "state": 0, 57 | "heater": 0 58 | }, 59 | "current": [ 60 | 20.5, 61 | 20.3 62 | ], 63 | "state": [ 64 | 0, 65 | 0 66 | ], 67 | "tools": { 68 | "active": [ 69 | [ 70 | 0.0 71 | ] 72 | ], 73 | "standby": [ 74 | [ 75 | 0.0 76 | ] 77 | ] 78 | }, 79 | "extra": [] 80 | }, 81 | "time": 8669.0, 82 | "currentLayer": 0, 83 | "currentLayerTime": 0.0, 84 | "extrRaw": [ 85 | 479.9 86 | ], 87 | "fractionPrinted": 0.0, 88 | "filePosition": 0, 89 | "firstLayerDuration": 0.0, 90 | "firstLayerHeight": 0.68, 91 | "printDuration": 0.0, 92 | "warmUpDuration": 0.0, 93 | "timesLeft": { 94 | "file": 0.0, 95 | "filament": 0.0, 96 | "layer": 0.0 97 | } 98 | } -------------------------------------------------------------------------------- /main/duet_status_json.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_DUET_STATUS_JSON_H 6 | #define REPPANEL_ESP32_DUET_STATUS_JSON_H 7 | 8 | #define DUET_STATUS "status" 9 | #define DUET_TEMPS "temps" 10 | #define DUET_TEMPS_BED "bed" 11 | #define DUET_TEMPS_CURRENT "current" 12 | #define DUET_TEMPS_BED_CURRENT "current" 13 | #define DUET_TEMPS_BED_STATE "state" 14 | #define DUET_TEMPS_BED_HEATER "heater" 15 | #define DUET_TOOLS "tools" 16 | #define DUET_TEMPS_TOOLS DUET_TOOLS 17 | #define DUET_MCU_TEMP "mcutemp" 18 | #define DUET_FIRM_NAME "firmwareName" 19 | #define DUET_FIRM_VER "firmwareVersion" 20 | #define DUET_TEMPS_ACTIVE "active" 21 | #define DUET_TEMPS_STANDBY "standby" 22 | #define DUET_ERR "err" 23 | 24 | #define REPRAP_FRAC_PRINTED "fractionPrinted" 25 | #define REPRAP_CURR_LAYER "currentLayer" 26 | #define REPRAP_JOB_DUR "printDuration" 27 | #define REPRAP_TIMES_LEFT "timesLeft" 28 | #define REPRAP_TIMES_LEFT_FILE "file" 29 | #define REPRAP_SIMTIME "simulatedTime" 30 | #define REPRAP_PRINTTIME "printTime" 31 | 32 | #define REPRAP_STATUS_PROCESS_CONFIG 'C' 33 | #define REPRAP_STATUS_IDLE 'I' 34 | #define REPRAP_STATUS_BUSY 'B' 35 | #define REPRAP_STATUS_PRINTING 'P' 36 | #define REPRAP_STATUS_DECELERATING 'D' 37 | #define REPRAP_STATUS_STOPPED 'S' 38 | #define REPRAP_STATUS_RESUMING 'R' 39 | #define REPRAP_STATUS_HALTED 'H' 40 | #define REPRAP_STATUS_FLASHING 'F' 41 | #define REPRAP_STATUS_CHANGINGTOOL 'T' 42 | #define REPRAP_STATUS_SIMULATING 'M' 43 | #define REPRAP_STATUS_OFF 'O' 44 | 45 | #endif //REPPANEL_ESP32_DUET_STATUS_JSON_H 46 | -------------------------------------------------------------------------------- /main/rrf3_object_model_parser.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include "esp32_settings.h" 7 | #include "rrf_objects.h" 8 | 9 | #ifndef REPPANEL_ESP32_RRF3_OBJECT_MODEL_PARSER_H 10 | #define REPPANEL_ESP32_RRF3_OBJECT_MODEL_PARSER_H 11 | 12 | #endif //REPPANEL_ESP32_RRF3_OBJECT_MODEL_PARSER_H 13 | 14 | void reppanel_parse_rr_connect(cJSON *connect_result, reprap_model_t *_reprap_model); 15 | void reppanel_parse_rrf_boards(cJSON *boards_result, cJSON *flags, reprap_model_t *_reprap_model); 16 | void reppanel_parse_rrf_fans(cJSON *fans_result, cJSON *flags, reprap_model_t *_reprap_model); 17 | void reppanel_parse_rrf_heaters(cJSON *heaters_result, int _heater_states[MAX_NUM_TOOLS], cJSON *flags, reprap_model_t *_reprap_model); 18 | void reppanel_parse_rrf_tools(cJSON *tools_result, int _heater_states[MAX_NUM_TOOLS], cJSON *flags, reprap_model_t *_reprap_model); 19 | void reppanel_parse_rrf_job(cJSON *job_result, cJSON *flags, reprap_model_t *_reprap_model); 20 | void reppanel_parse_rrf_move(cJSON *move_result, cJSON *flags, reprap_model_t *_reprap_model); 21 | void reppanel_parse_rrf_state(cJSON *state_result, cJSON *flags, reprap_model_t *_reprap_model); 22 | void reppanel_parse_rrf_network(cJSON *network_result, cJSON *flags, reprap_model_t *_reprap_model); 23 | void reppanel_parse_rrf_sensors(cJSON *sensors_result, cJSON *flags, reprap_model_t *_reprap_model); 24 | void reppanel_parse_rrf_inputs(cJSON *input_result, cJSON *flags, reprap_model_t *_reprap_model); 25 | void reppanel_parse_rrf_global(cJSON *global_result, cJSON *flags, reprap_model_t *_reprap_model); 26 | void reppanel_parse_rrf_directories(cJSON *directories_result, cJSON *flags, reprap_model_t *_reprap_model); 27 | void reppanel_parse_rrf_seqs(cJSON *seqs_result, reprap_model_t *_reprap_model); 28 | void reppanel_parse_rr_fileinfo(char *json_response, reprap_model_t *_reprap_model, int buff_length); 29 | -------------------------------------------------------------------------------- /main/Kconfig: -------------------------------------------------------------------------------- 1 | menu "RepPanel configuration" 2 | 3 | config REPPANEL_RRF2_SUPPORT 4 | bool 5 | prompt "Enable deprecated legacy RRF2 support." 6 | default y 7 | 8 | config REPPANEL_ESP32_WIFI_ENABLED 9 | bool 10 | prompt "Enable WiFi. Connect to your 3D printer via WiFi." 11 | default y 12 | 13 | config REPPANEL_ENABLE_QOI_THUMBNAIL_SUPPORT 14 | bool 15 | prompt "Enable RRF3.4+ Thumbnail support for the QOI file format." 16 | default y 17 | 18 | config REPPANEL_ESP32_CONSOLE_ENABLED 19 | bool 20 | prompt "Enable RepPanel console for sending custom G-Code to the printer. Consumes additional RAM." 21 | default n 22 | 23 | config REPPANEL_ENABLE_LIGHT_CONTROL 24 | bool 25 | prompt "Enable control of a light connected to the Duet via: M42 P2 S1" 26 | default n 27 | 28 | config REPPANEL_MAX_DIRECTORY_PATH_LENGTH 29 | int "Maximum length of a directory path." 30 | range 32 10240 31 | default 160 if REPPANEL_ESP32_WIFI_ENABLED 32 | default 160 33 | 34 | config REPPANEL_MAX_FILENAME_LENGTH 35 | int "Maximum length of a filename." 36 | range 32 512 37 | default 64 if REPPANEL_ESP32_WIFI_ENABLED 38 | default 64 39 | 40 | config REPPANEL_MAX_NUM_ELEM_DIR 41 | int "Maximum number of elements that can be listed within a directory." 42 | range 1 1024 43 | default 16 if REPPANEL_ESP32_WIFI_ENABLED 44 | default 24 45 | 46 | config REPPANEL_REQUEST_TASK_STACK_SIZE 47 | int "Stack size for the task doing the requests to the Duet. 13312 bytes if Wifi is enabled" 48 | range 8704 1000000 49 | default 15360 if REPPANEL_ESP32_WIFI_ENABLED 50 | default 13312 51 | 52 | config REPPANEL_GUI_TASK_STACK_SIZE 53 | int "GUI Task stack size. 9216 bytes if Wifi is enabled" 54 | range 8704 1000000 55 | default 9216 if REPPANEL_ESP32_WIFI_ENABLED 56 | default 9216 57 | 58 | endmenu -------------------------------------------------------------------------------- /main/custom_themes/lv_theme_rep_panel_dark.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LV_THEME_REP_PANEL_DARK_H 6 | #define LV_THEME_REP_PANEL_DARK_H 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | /********************* 13 | * INCLUDES 14 | *********************/ 15 | #include 16 | #include "lv_conf.h" 17 | 18 | #if LV_USE_THEME_REP_PANEL_DARK 19 | 20 | /********************* 21 | * DEFINES 22 | *********************/ 23 | 24 | #define REP_PANEL_DARK LV_COLOR_MAKE(0x12, 0x12, 0x12) 25 | #define REP_PANEL_DARK_ACCENT LV_COLOR_MAKE(0xb9, 0xfa, 0x46) 26 | #define REP_PANEL_DARK_ACCENT_ALT1 LV_COLOR_MAKE(0x4b, 0xb4, 0x5e) 27 | #define REP_PANEL_DARK_ACCENT_ALT2 LV_COLOR_MAKE(0x27, 0x46, 0x46) 28 | #define REP_PANEL_DARK_HIGHLIGHT LV_COLOR_MAKE(0x19, 0xae, 0xff) 29 | #define REP_PANEL_DARK_HIGHLIGHT_DARK LV_COLOR_MAKE(0x0a, 0x51, 0xc4) 30 | #define REP_PANEL_DARK_TEXT LV_COLOR_MAKE(0xe6, 0xe6, 0xe6) 31 | #define REP_PANEL_DARK_ACCENT_GREY LV_COLOR_MAKE(0x20, 0x24, 0x25) 32 | #define REP_PANEL_DARK_RED LV_COLOR_MAKE(0xcc, 0x23, 0x47) 33 | #define REP_PANEL_DARK_DARK_RED LV_COLOR_MAKE(0x63, 0x09, 0x2c) 34 | #define REP_PANEL_DARK_GREEN LV_COLOR_MAKE(0x4b, 0xb4, 0x5e) 35 | 36 | #define REP_PANEL_DARK_ACCENT_STR "#b9fa46" 37 | #define REP_PANEL_DARK_ACCENT_ALT1_STR "#4bb45e" 38 | #define REP_PANEL_DARK_ACCENT_ALT2_STR "#274646" 39 | #define REP_PANEL_DARK_TEXT_STR "#e6e6e6" 40 | 41 | /********************** 42 | * TYPEDEFS 43 | **********************/ 44 | 45 | /********************** 46 | * GLOBAL PROTOTYPES 47 | **********************/ 48 | 49 | /** 50 | * Initialize the material theme 51 | * @param hue [0..360] hue value from HSV color space to define the theme's base color 52 | * @param font pointer to a font (NULL to use the default) 53 | * @return pointer to the initialized theme 54 | */ 55 | lv_theme_t *lv_theme_reppanel_dark_init(uint16_t hue, lv_font_t *font); 56 | 57 | /** 58 | * Get a pointer to the theme 59 | * @return pointer to the theme 60 | */ 61 | lv_theme_t *lv_theme_get_reppanel_light(void); 62 | 63 | /********************** 64 | * MACROS 65 | **********************/ 66 | 67 | #endif 68 | 69 | #ifdef __cplusplus 70 | } /* extern "C" */ 71 | #endif 72 | 73 | #endif /*LV_THEME_REP_PANEL_DARK_H*/ 74 | -------------------------------------------------------------------------------- /debug_responses/RRF3_1_0/state.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "state", 3 | "flags": "d99vn", 4 | "result": { 5 | "atxPower": null, 6 | "beep": null, 7 | "currentTool": 0, 8 | "displayMessage": "", 9 | "gpOut": [], 10 | "laserPwm": null, 11 | "logFile": "", 12 | "logLevel": "off", 13 | "machineMode": "FFF", 14 | "messageBox": { 15 | "axisControls": 0, 16 | "message": "Display Close", 17 | "mode": 1, 18 | "seq": 9, 19 | "timeout": 10000, 20 | "title": "Title" 21 | }, 22 | "msUpTime": 897, 23 | "nextTool": 0, 24 | "powerFailScript": "M913 X0 Y0 G91 M83 G1 Z3 E-5 F1000", 25 | "previousTool": -1, 26 | "restorePoints": [ 27 | { 28 | "coords": [ 29 | 0, 30 | 0, 31 | 0 32 | ], 33 | "extruderPos": 0, 34 | "fanPwm": 0, 35 | "feedRate": 50, 36 | "ioBits": 0, 37 | "laserPwm": null, 38 | "toolNumber": -1 39 | }, 40 | { 41 | "coords": [ 42 | 160.514, 43 | 188.119, 44 | 0.4 45 | ], 46 | "extruderPos": 0, 47 | "fanPwm": 0, 48 | "feedRate": 24.8, 49 | "ioBits": 0, 50 | "laserPwm": null, 51 | "toolNumber": 0 52 | }, 53 | { 54 | "coords": [ 55 | 0, 56 | 0, 57 | 0 58 | ], 59 | "extruderPos": 0, 60 | "fanPwm": 0, 61 | "feedRate": 50, 62 | "ioBits": 0, 63 | "laserPwm": null, 64 | "toolNumber": -1 65 | }, 66 | { 67 | "coords": [ 68 | 0, 69 | 0, 70 | 0 71 | ], 72 | "extruderPos": 0, 73 | "fanPwm": 0, 74 | "feedRate": 50, 75 | "ioBits": 0, 76 | "laserPwm": null, 77 | "toolNumber": -1 78 | }, 79 | { 80 | "coords": [ 81 | 0, 82 | 0, 83 | 0 84 | ], 85 | "extruderPos": 0, 86 | "fanPwm": 0, 87 | "feedRate": 50, 88 | "ioBits": 0, 89 | "laserPwm": null, 90 | "toolNumber": -1 91 | }, 92 | { 93 | "coords": [ 94 | 0, 95 | 0, 96 | 0 97 | ], 98 | "extruderPos": 0, 99 | "fanPwm": 0, 100 | "feedRate": 50, 101 | "ioBits": 0, 102 | "laserPwm": null, 103 | "toolNumber": -1 104 | } 105 | ], 106 | "status": "processing", 107 | "time": "2021-08-28T11:55:21", 108 | "upTime": 8381 109 | } 110 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/reprap_status_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": "I", 3 | "coords": { 4 | "axesHomed": [ 5 | 0, 6 | 0, 7 | 0 8 | ], 9 | "wpl": 1, 10 | "xyz": [ 11 | 0, 12 | 0, 13 | 0 14 | ], 15 | "machine": [ 16 | 0, 17 | 0, 18 | 0 19 | ], 20 | "extr": [ 21 | 0 22 | ] 23 | }, 24 | "speeds": { 25 | "requested": 0, 26 | "top": 0 27 | }, 28 | "currentTool": 0, 29 | "params": { 30 | "atxPower": -1, 31 | "fanPercent": [ 32 | 0, 33 | 30, 34 | 0 35 | ], 36 | "fanNames": [ 37 | "PartCoolingFan", 38 | "HotendFan", 39 | "" 40 | ], 41 | "speedFactor": 100, 42 | "extrFactors": [ 43 | 100 44 | ], 45 | "babystep": 0 46 | }, 47 | "seq": 1, 48 | "sensors": { 49 | "probeValue": 1000, 50 | "fanRPM": [ 51 | -1, 52 | -1, 53 | -1 54 | ] 55 | }, 56 | "temps": { 57 | "bed": { 58 | "current": 19.4, 59 | "active": 0, 60 | "standby": 0, 61 | "state": 0, 62 | "heater": 0 63 | }, 64 | "current": [ 65 | 19.4, 66 | 19.2 67 | ], 68 | "state": [ 69 | 0, 70 | 2 71 | ], 72 | "names": [ 73 | "", 74 | "" 75 | ], 76 | "tools": { 77 | "active": [ 78 | [ 79 | 0 80 | ] 81 | ], 82 | "standby": [ 83 | [ 84 | 0 85 | ] 86 | ] 87 | }, 88 | "extra": [] 89 | }, 90 | "time": 8468, 91 | "coldExtrudeTemp": 160, 92 | "coldRetractTemp": 90, 93 | "compensation": "None", 94 | "controllableFans": 1, 95 | "tempLimit": 290, 96 | "endstops": 4, 97 | "firmwareName": "RepRapFirmware for Duet 2 WiFi/Ethernet", 98 | "firmwareVersion": "3.0", 99 | "geometry": "coreXY", 100 | "axes": 3, 101 | "totalAxes": 3, 102 | "axisNames": "XYZ", 103 | "volumes": 2, 104 | "mountedVolumes": 1, 105 | "mode": "FFF", 106 | "name": "CyberPrint", 107 | "probe": { 108 | "threshold": 500, 109 | "height": 0.7, 110 | "type": 0 111 | }, 112 | "tools": [ 113 | { 114 | "number": 0, 115 | "name": "PrimeExtruder", 116 | "heaters": [ 117 | 1 118 | ], 119 | "drives": [ 120 | 0 121 | ], 122 | "axisMap": [ 123 | [ 124 | 0 125 | ], 126 | [ 127 | 1 128 | ] 129 | ], 130 | "fans": 1, 131 | "filament": "", 132 | "offsets": [ 133 | 0, 134 | 0, 135 | 0 136 | ] 137 | } 138 | ], 139 | "mcutemp": { 140 | "min": 14.8, 141 | "cur": 31.8, 142 | "max": 32.5 143 | }, 144 | "vin": { 145 | "min": 23.9, 146 | "cur": 24.1, 147 | "max": 24.3 148 | } 149 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_1_0/dwc-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": { 3 | "language": "en", 4 | "lastHostname": "cyberprint.local", 5 | "darkTheme": true, 6 | "useBinaryPrefix": true, 7 | "disableAutoComplete": false, 8 | "settingsStorageLocal": false, 9 | "settingsSaveDelay": 2000, 10 | "cacheStorageLocal": true, 11 | "cacheSaveDelay": 4000, 12 | "notifications": { 13 | "errorsPersistent": true, 14 | "timeout": 5000 15 | }, 16 | "webcam": { 17 | "url": "", 18 | "updateInterval": 5000, 19 | "liveUrl": "", 20 | "useFix": false, 21 | "embedded": false, 22 | "rotation": 0, 23 | "flip": "none" 24 | }, 25 | "enabledPlugins": [ 26 | "Height Map" 27 | ], 28 | "plugins": {} 29 | }, 30 | "machine": { 31 | "ajaxRetries": 2, 32 | "updateInterval": 250, 33 | "extendedUpdateEvery": 20, 34 | "fileTransferRetryThreshold": 358400, 35 | "crcUploads": true, 36 | "pingInterval": 2000, 37 | "updateDelay": 0, 38 | "babystepAmount": 0.01, 39 | "displayedExtraTemperatures": [], 40 | "displayedExtruders": [ 41 | 0, 42 | 1 43 | ], 44 | "displayedFans": [ 45 | 0, 46 | 1, 47 | 2 48 | ], 49 | "moveSteps": { 50 | "X": [ 51 | 100, 52 | 50, 53 | 10, 54 | 1, 55 | 0.1 56 | ], 57 | "Y": [ 58 | 100, 59 | 50, 60 | 10, 61 | 1, 62 | 0.1 63 | ], 64 | "Z": [ 65 | 50, 66 | 25, 67 | 5, 68 | 0.5, 69 | 0.05 70 | ], 71 | "default": [ 72 | 100, 73 | 50, 74 | 10, 75 | 1, 76 | 0.1 77 | ] 78 | }, 79 | "moveFeedrate": 6000, 80 | "extruderAmounts": [ 81 | 100, 82 | 50, 83 | 20, 84 | 10, 85 | 5, 86 | 1 87 | ], 88 | "extruderFeedrates": [ 89 | 60, 90 | 30, 91 | 15, 92 | 5, 93 | 1 94 | ], 95 | "temperatures": { 96 | "tool": { 97 | "active": [ 98 | 250, 99 | 235, 100 | 220, 101 | 205, 102 | 195, 103 | 160, 104 | 120, 105 | 100, 106 | 0 107 | ], 108 | "standby": [ 109 | 210, 110 | 180, 111 | 160, 112 | 140, 113 | 0 114 | ] 115 | }, 116 | "bed": { 117 | "active": [ 118 | 110, 119 | 100, 120 | 90, 121 | 65, 122 | 60, 123 | 55, 124 | 53, 125 | 0 126 | ], 127 | "standby": [ 128 | 55, 129 | 40, 130 | 30, 131 | 0 132 | ] 133 | }, 134 | "chamber": [ 135 | 90, 136 | 80, 137 | 70, 138 | 60, 139 | 50, 140 | 40, 141 | 0 142 | ] 143 | }, 144 | "spindleRPM": [ 145 | 10000, 146 | 75000, 147 | 5000, 148 | 2500, 149 | 1000, 150 | 0 151 | ], 152 | "enabledPlugins": [], 153 | "plugins": {} 154 | } 155 | } -------------------------------------------------------------------------------- /main/rrf_objects.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Wolfgang Christl 3 | // Licensed under Apache Licen; Version 2.0 - https//opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef REPPANEL_ESP32_RRF_OBJECTS_H 6 | #define REPPANEL_ESP32_RRF_OBJECTS_H 7 | 8 | #include 9 | #include 10 | #include "reppanel.h" 11 | 12 | #define RRF3_SEQ_BOARDS 1 13 | #define RRF3_SEQ_DIR 2 14 | #define RRF3_SEQ_FANS 4 15 | #define RRF3_SEQ_GLOBAL 16 16 | #define RRF3_SEQ_HEAT 32 17 | #define RRF3_SEQ_INPUTS 64 18 | #define RRF3_SEQ_JOB 128 19 | #define RRF3_SEQ_MOVE 256 20 | #define RRF3_SEQ_NETWORK 512 21 | #define RRF3_SEQ_REPLY 1024 22 | #define RRF3_SEQ_SENSORS 2048 23 | #define RRF3_SEQ_STATE 4096 24 | #define RRF3_SEQ_TOOLS 8192 25 | 26 | #define REPRAP_MAX_DISPLAY_MSG_LEN 128 27 | #define REPRAP_MAX_STATUS_LEN 15 28 | #define REPRAP_MAX_LEN_MSG_TITLE 32 29 | 30 | typedef struct { 31 | uint16_t boards; 32 | uint16_t directories; 33 | uint16_t fans; 34 | uint16_t global; 35 | uint16_t heat ; 36 | uint16_t inputs ; 37 | uint16_t job; 38 | uint16_t move; 39 | uint16_t network; 40 | uint16_t reply ; 41 | uint16_t sensors; 42 | uint16_t state ; 43 | uint16_t tools; 44 | } reprap_seqs_t; 45 | 46 | typedef struct { 47 | uint16_t boards_changed: 1; 48 | uint16_t directories_changed: 1; 49 | uint16_t fans_changed: 1; 50 | uint16_t global_changed: 1; 51 | uint16_t heat_changed: 1; 52 | uint16_t inputs_changed: 1; 53 | uint16_t job_changed: 1; 54 | uint16_t move_changed: 1; 55 | uint16_t network_changed: 1; 56 | uint16_t reply_changed: 1; 57 | uint16_t sensors_changed: 1; 58 | uint16_t state_changed: 1; 59 | uint16_t tools_changed: 1; 60 | } reprap_seqs_changed_t; 61 | // set to 1 indicating the corresponding object model was updated on the duet and the local 62 | // model is out of sync and needs an update. Must be reset to 0 by application when synced again 63 | 64 | typedef struct { 65 | char status[REPRAP_MAX_STATUS_LEN]; 66 | char msg_box_title[REPRAP_MAX_LEN_MSG_TITLE]; 67 | char msg_box_msg[REPRAP_MAX_DISPLAY_MSG_LEN]; 68 | bool show_axis_controls; // true, false 69 | uint8_t mode; 70 | uint16_t timeout; 71 | bool new_msg; // true, false 72 | } reprap_state_t; 73 | 74 | typedef struct { 75 | struct { 76 | uint32_t size; 77 | char fileName[MAX_LEN_FILENAME]; 78 | uint32_t simulatedTime; 79 | uint32_t printTime; 80 | uint16_t numLayers; 81 | float height; 82 | double overall_filament_usage; // [mm] as preported by firmware and slicer 83 | } file; 84 | uint32_t filePosition; 85 | uint32_t duration; 86 | uint32_t lastDuration; 87 | uint16_t layer; 88 | double rawExtrusion; 89 | struct { 90 | uint32_t simulation; 91 | uint32_t slicer; 92 | uint32_t file; 93 | } timesLeft; 94 | } reprap_job_t; 95 | 96 | typedef struct { 97 | uint8_t api_level; 98 | uint8_t num_heaters; 99 | uint8_t num_tools; 100 | reprap_state_t reprap_state; 101 | reprap_job_t reprap_job; 102 | reprap_seqs_t reprap_seqs; 103 | reprap_seqs_changed_t reprap_seqs_changed; 104 | } reprap_model_t; 105 | 106 | extern reprap_model_t reprap_model; 107 | 108 | reprap_model_t init_reprap_model(); 109 | 110 | 111 | #endif //REPPANEL_ESP32_RRF_OBJECTS_H 112 | -------------------------------------------------------------------------------- /main/esp32_settings.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include "esp32_settings.h" 9 | #include "reppanel.h" 10 | 11 | #define TAG "RepPanelSettings" 12 | 13 | char wifi_ssid[MAX_SSID_LEN]; 14 | char wifi_pass[MAX_WIFI_PASS_LEN]; 15 | 16 | char rep_addr[MAX_REP_ADDR_LEN]; 17 | char rep_pass[MAX_REP_PASS_LEN]; 18 | 19 | int temp_unit = 0; // 0=Celsius, 1=Fahrenheit 20 | 21 | char filament_names[MAX_LEN_STR_FILAMENT_LIST] = {"Not set\nNot set"}; 22 | 23 | char get_temp_unit() { 24 | if (temp_unit == 0) { 25 | return 'C'; 26 | } else { 27 | return 'F'; 28 | } 29 | } 30 | 31 | void print_settings() { 32 | ESP_LOGI(TAG, "Wifi SSID: %s", wifi_ssid); 33 | ESP_LOGI(TAG, "Wifi password: %s", wifi_pass); 34 | ESP_LOGI(TAG, "RepRap addr: %s", rep_addr); 35 | ESP_LOGI(TAG, "RepRap password: %s", rep_pass); 36 | } 37 | 38 | void init_settings() { 39 | memccpy(wifi_ssid, "AWifiSSID", 10, MAX_SSID_LEN); 40 | memccpy(wifi_pass, "passwd", 7, MAX_WIFI_PASS_LEN); 41 | memccpy(rep_addr, "http://reprap.local", 20, MAX_REP_ADDR_LEN); 42 | memccpy(rep_pass, "pass", 5, MAX_REP_PASS_LEN); 43 | } 44 | 45 | void write_settings_to_nvs() { 46 | ESP_LOGI(TAG, "Saving settings to NVS"); 47 | nvs_handle my_handle; 48 | ESP_ERROR_CHECK(nvs_open(REPPANEL_NVS, NVS_READWRITE, &my_handle)); 49 | ESP_ERROR_CHECK(nvs_set_str(my_handle, NVS_KEY_WIFI_SSID, wifi_ssid)); 50 | ESP_ERROR_CHECK(nvs_set_str(my_handle, NVS_KEY_WIFI_PASS, wifi_pass)); 51 | ESP_ERROR_CHECK(nvs_set_str(my_handle, NVS_KEY_REPRAP_ADDR, rep_addr)); 52 | ESP_ERROR_CHECK(nvs_set_str(my_handle, NVS_KEY_REPRAP_PASS, rep_pass)); 53 | ESP_ERROR_CHECK(nvs_commit(my_handle)); 54 | nvs_close(my_handle); 55 | print_settings(); 56 | } 57 | 58 | void read_settings_nvs() { 59 | nvs_handle my_handle; 60 | if (nvs_open(REPPANEL_NVS, NVS_READONLY, &my_handle) == ESP_ERR_NVS_NOT_FOUND) { 61 | // First start 62 | nvs_close(my_handle); 63 | init_settings(); 64 | write_settings_to_nvs(); 65 | } else { 66 | ESP_LOGI(TAG, "Reading settings from NVS"); 67 | size_t required_size = 0; 68 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_WIFI_SSID, NULL, &required_size)); 69 | char *tmp_wifi_ssid = malloc(required_size); 70 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_WIFI_SSID, tmp_wifi_ssid, &required_size)); 71 | memccpy(wifi_ssid, tmp_wifi_ssid, required_size, MAX_SSID_LEN); 72 | 73 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_WIFI_PASS, NULL, &required_size)); 74 | char *tmp_wifi_pass = malloc(required_size); 75 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_WIFI_PASS, tmp_wifi_pass, &required_size)); 76 | memccpy(wifi_pass, tmp_wifi_pass, required_size, MAX_WIFI_PASS_LEN); 77 | 78 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_REPRAP_ADDR, NULL, &required_size)); 79 | char *tmp_rep_addr = malloc(required_size); 80 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_REPRAP_ADDR, tmp_rep_addr, &required_size)); 81 | memccpy(rep_addr, tmp_rep_addr, required_size, MAX_REP_ADDR_LEN); 82 | 83 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_REPRAP_PASS, NULL, &required_size)); 84 | char *tmp_rep_pass = malloc(required_size); 85 | ESP_ERROR_CHECK(nvs_get_str(my_handle, NVS_KEY_REPRAP_PASS, tmp_rep_pass, &required_size)); 86 | memccpy(rep_pass, tmp_rep_pass, required_size, MAX_REP_PASS_LEN); 87 | 88 | nvs_close(my_handle); 89 | free(tmp_wifi_pass); 90 | free(tmp_wifi_ssid); 91 | free(tmp_rep_addr); 92 | free(tmp_rep_pass); 93 | print_settings(); 94 | } 95 | } -------------------------------------------------------------------------------- /main/reppanel_img_decoder.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2022 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifdef CONFIG_LVGL_TFT_DISPLAY_MONOCHROME 6 | #include "reppanel_img_decoder.h" 7 | #include "src/lv_draw/lv_img_decoder.h" 8 | #include "../externals/qoi/qoi.h" 9 | 10 | // https://docs.lvgl.io/6.1/overview/image.html?highlight=image%20decoder 11 | 12 | bool is_qoi_image(const uint8_t *data) { 13 | if (data[0] == 'q' && data[1] == 'o' && data[2] == 'i' && data[3] == 'f') { 14 | return true; 15 | } 16 | return false; 17 | } 18 | 19 | /** 20 | * Get info about a QOI image 21 | * @param decoder pointer to the decoder where this function belongs 22 | * @param src can be file name or pointer to a C array 23 | * @param header store the info here 24 | * @return LV_RES_OK: no error; LV_RES_INV: can't get the info 25 | */ 26 | static lv_res_t decoder_info(lv_img_decoder_t *decoder, const void *src, lv_img_header_t *header) { 27 | uint8_t *bytes = (uint8_t *) src; 28 | if(is_qoi_image(bytes) == false) return LV_RES_INV; 29 | 30 | int p = 4; 31 | header->w = qoi_read_32(bytes, &p); 32 | header->h = qoi_read_32(bytes, &p); 33 | unsigned char channels = bytes[p++]; 34 | if (channels == 3) { 35 | header->cf = LV_IMG_CF_RAW; 36 | } else if (channels == 4) { 37 | header->cf = LV_IMG_CF_RAW_ALPHA; 38 | } else { 39 | return LV_RES_INV; 40 | } 41 | return LV_RES_OK; 42 | } 43 | 44 | /** 45 | * Open a QOI image and return the decided image 46 | * @param decoder pointer to the decoder where this function belongs 47 | * @param dsc pointer to a descriptor which describes this decoding session 48 | * @return LV_RES_OK: no error; LV_RES_INV: can't get the info 49 | */ 50 | static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) { 51 | /*Check whether the type `src` is known by the decoder*/ 52 | // if(is_qoi_image(src) == false) return LV_RES_INV; 53 | 54 | qoi_desc *d; 55 | /*Decode and store the image. If `dsc->img_data` is `NULL`, the `read_line` function will be called to get the image data line-by-line*/ 56 | // dsc->img_data = qoi_decode(src, size, d, 0); 57 | 58 | /*Change the color format if required. For PNG usually 'Raw' is fine*/ 59 | dsc->header.cf = LV_IMG_CF_RAW; 60 | 61 | /*Call a built in decoder function if required. It's not required if`my_png_decoder` opened the image in true color format.*/ 62 | lv_res_t res = lv_img_decoder_built_in_open(decoder, dsc); 63 | 64 | return res; 65 | } 66 | 67 | /** 68 | * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. 69 | * Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL) 70 | * @param decoder pointer to the decoder the function associated with 71 | * @param dsc pointer to decoder descriptor 72 | * @param x start x coordinate 73 | * @param y start y coordinate 74 | * @param len number of pixels to decode 75 | * @param buf a buffer to store the decoded pixels 76 | * @return LV_RES_OK: ok; LV_RES_INV: failed 77 | */ 78 | lv_res_t decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, 79 | lv_coord_t y, lv_coord_t len, uint8_t * buf) { 80 | 81 | /*Copy `len` pixels from `x` and `y` coordinates in True color format to `buf` */ 82 | 83 | } 84 | 85 | /** 86 | * Free the allocated resources 87 | * @param decoder pointer to the decoder where this function belongs 88 | * @param dsc pointer to a descriptor which describes this decoding session 89 | */ 90 | static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc) { 91 | /*Free all allocated data*/ 92 | 93 | /*Call the built-in close function if the built-in open/read_line was used*/ 94 | lv_img_decoder_built_in_close(decoder, dsc); 95 | 96 | } 97 | #endif -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/duet_serial.txt: -------------------------------------------------------------------------------- 1 | miniterm.py --echo /dev/ttyACM0 115200 2 | 3 | M111 S1 P3 ; To report paneldue port stuff to USB serial interface 4 | 5 | 6 | M408 S0 7 | {"status":"O","heaters":[21.4,21.3],"active":[0.0,0.0],"standby":[0.0,0.0],"hstat":[0,0],"pos":[0.000,0.000,0.000],"machine":[0.000,0.000,0.000],"sfactor":100.00,"efactor":[100.00],"babystep":0.000,"tool":-1,"probe":"1000","fanPercent":[0.0,0,30,0,-1,-1,-1,-1,-1,-1,-1,-1,-1],"fanRPM":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"homed":[0,0,0],"msgBox.mode":-1} 8 | 9 | M408 S1 10 | {"status":"O","heaters":[21.6,21.3],"active":[0.0,0.0],"standby":[0.0,0.0],"hstat":[0,0],"pos":[0.000,0.000,0.000],"machine":[0.000,0.000,0.000],"sfactor":100.00,"efactor":[100.00],"babystep":0.000,"tool":-1,"probe":"1000","fanPercent":[0.0,0,30,0,-1,-1,-1,-1,-1,-1,-1,-1,-1],"fanRPM":[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1],"homed":[0,0,0],"msgBox.mode":-1,"geometry":"coreXY","axes":3,"totalAxes":3,"axisNames":"XYZ","volumes":2,"numTools":1,"myName":"CyberPrint","firmwareName":"RepRapFirmware for Duet 2 WiFi/Ethernet"} 11 | 12 | M408 S1 13 | {"status":"O","coords":{"axesHomed":[0,0,0],"wpl":1,"xyz":[0.000,0.000,0.000],"machine":[0.000,0.000,0.000],"extr":[0.0]},"speeds":{"requested":0.0,"top":0.0},"currentTool":-1,"params":{"atxPower":-1,"fanPercent":[0,30,0],"speedFactor":100.0,"extrFactors":[100.0],"babystep":0.000},"sensors":{"probeValue":1000,"fanRPM":[-1,-1,-1]},"temps":{"bed":{"current":21.4,"active":0.0,"standby":0.0,"state":0,"heater":0},"current":[21.4,21.2],"state":[0,0],"tools":{"active":[[0.0]],"standby":[[0.0]]},"extra":[]},"time":139.0,"seq":3,"resp":"WiFi module started\nWiFi module is connected to access point XXXX, IP address 192.168.X.X\nError: Bad command:\n"} 14 | 15 | M408 S2 16 | {"status":"O","coords":{"axesHomed":[0,0,0],"wpl":1,"xyz":[0.000,0.000,0.000],"machine":[0.000,0.000,0.000],"extr":[0.0]},"speeds":{"requested":0.0,"top":0.0},"currentTool":-1,"params":{"atxPower":-1,"fanPercent":[0,30,0],"speedFactor":100.0,"extrFactors":[100.0],"babystep":0.000},"sensors":{"probeValue":1000,"fanRPM":[-1,-1,-1]},"temps":{"bed":{"current":21.5,"active":0.0,"standby":0.0,"state":0,"heater":0},"current":[21.5,21.2],"state":[0,0],"tools":{"active":[[0.0]],"standby":[[0.0]]},"extra":[]},"time":348.0,"seq":3,"resp":""} 17 | 18 | M408 S3 19 | {"status":"O","coords":{"axesHomed":[0,0,0],"wpl":1,"xyz":[0.000,0.000,0.000],"machine":[0.000,0.000,0.000],"extr":[0.0]},"speeds":{"requested":0.0,"top":0.0},"currentTool":-1,"params":{"atxPower":-1,"fanPercent":[0,30,0],"fanNames":["PartCoolingFan","HotendFan",""],"speedFactor":100.0,"extrFactors":[100.0],"babystep":0.000},"sensors":{"probeValue":1000,"fanRPM":[-1,-1,-1]},"temps":{"bed":{"current":21.5,"active":0.0,"standby":0.0,"state":0,"heater":0},"current":[21.5,21.2],"state":[0,0],"names":["",""],"tools":{"active":[[0.0]],"standby":[[0.0]]},"extra":[]},"time":385.0,"coldExtrudeTemp":160.0,"coldRetractTemp":90.0,"compensation":"None","controllableFans":1,"tempLimit":290.0,"endstops":4,"firmwareName":"RepRapFirmware for Duet 2 WiFi/Ethernet","firmwareVersion":"3.0","geometry":"coreXY","axes":3,"totalAxes":3,"axisNames":"XYZ","volumes":2,"mountedVolumes":1,"mode":"FFF","name":"CyberPrint","probe":{"threshold":500,"height":0.70,"type":0},"tools":[{"number":0,"name":"PrimeExtruder","heaters":[1],"drives":[0],"axisMap":[[0],[1]],"fans":1,"filament":"","offsets":[0.00,0.00,0.00]}],"mcutemp":{"min":17.3,"cur":25.5,"max":25.7},"vin":{"min":0.2,"cur":1.6,"max":1.7},"seq":3,"resp":""} 20 | 21 | M408 S4 22 | {"status":"O","coords":{"axesHomed":[0,0,0],"wpl":1,"xyz":[0.000,0.000,0.000],"machine":[0.000,0.000,0.000],"extr":[0.0]},"speeds":{"requested":0.0,"top":0.0},"currentTool":-1,"params":{"atxPower":-1,"fanPercent":[0,30,0],"speedFactor":100.0,"extrFactors":[100.0],"babystep":0.000},"sensors":{"probeValue":1000,"fanRPM":[-1,-1,-1]},"temps":{"bed":{"current":21.5,"active":0.0,"standby":0.0,"state":0,"heater":0},"current":[21.5,21.2],"state":[0,0],"tools":{"active":[[0.0]],"standby":[[0.0]]},"extra":[]},"time":416.0,"currentLayer":0,"currentLayerTime":0.0,"extrRaw":[0.0],"fractionPrinted":0.0,"filePosition":0,"firstLayerDuration":0.0,"firstLayerHeight":0.00,"printDuration":0.0,"warmUpDuration":0.0,"timesLeft":{"file":0.0,"filament":0.0,"layer":0.0},"seq":3,"resp":""} 23 | 24 | M408 S5 25 | {"axisMins":[0.00,0.00,0.00],"axisMaxes":[326.00,326.00,311.70],"accelerations":[2000.00,2000.00,20.00,500.00,500.00,500.00,500.00,500.00,500.00,250.00,250.00,300.00],"currents":[1200,1200,1500,0,0,0,0,0,0,0,0,800],"firmwareElectronics":"Duet WiFi 1.02 or later","firmwareName":"RepRapFirmware for Duet 2 WiFi/Ethernet","firmwareVersion":"3.0","dwsVersion":"1.23","firmwareDate":"2020-01-03b3", "sysdir":"0:/sys/","idleCurrentFactor":30.0,"idleTimeout":30.0,"minFeedrates":[16.67,16.67,0.20,15.00,15.00,15.00,15.00,15.00,15.00,2.00,2.00,2.00],"maxFeedrates":[150.00,150.00,60.00,100.00,100.00,100.00,100.00,100.00,100.00,20.00,20.00,30.00]} 26 | 27 | -------------------------------------------------------------------------------- /main/reppanel_helper.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "esp32_settings.h" 12 | #include "reppanel.h" 13 | #ifdef CONFIG_REPPANEL_ESP32_CONSOLE_ENABLED 14 | #include "reppanel_console.h" 15 | #endif 16 | 17 | char html5[256] = {0}; 18 | bool encoding_inited = false; 19 | lv_obj_t *cont_msg; 20 | 21 | char *get_version_string() { 22 | static char version_str[12]; 23 | sprintf(version_str, "%i.%i.%i", VERSION_MAJOR, VERSION_MINOR, VERSION_HOTFIX); 24 | return version_str; 25 | } 26 | 27 | void url_encoder_rfc_tables_init() { 28 | int i; 29 | for (i = 0; i < 256; i++) { 30 | html5[i] = isalnum (i) || i == '*' || i == '-' || i == '.' || i == '&' || i == '=' || i == '#' || i == '?' || 31 | i == ':' || i == '@' || i == '_' ? i : (i == ' ') ? '+' : 0; 32 | } 33 | encoding_inited = true; 34 | } 35 | 36 | /** 37 | * Some basic URL encoding thanks to alian from Stack Overflow 38 | * @param table 39 | * @param s 40 | * @param enc 41 | * @return 42 | */ 43 | char *url_encode(unsigned char *s, char *enc) { 44 | if (!encoding_inited) url_encoder_rfc_tables_init(); 45 | for (; *s; s++) { 46 | if (html5[*s]) sprintf(enc, "%c", html5[*s]); 47 | else sprintf(enc, "%%%02X", *s); 48 | while (*++enc); 49 | } 50 | return (enc); 51 | } 52 | 53 | bool ends_with(const char *base, char *str) { 54 | int blen = strlen(base); 55 | int slen = strlen(str); 56 | return (blen >= slen) && (0 == strcmp(base + blen - slen, str)); 57 | } 58 | 59 | void init_reprap_buffers() { 60 | for (int i = 0; i < MAX_NUM_TOOLS; i++) { 61 | reprap_extruder_amounts[i] = -1; 62 | reprap_extruder_feedrates[i] = -1; 63 | reprap_chamber_temp_buff[i] = -1; 64 | } 65 | for (int i = 0; i < MAX_NUM_ELEM_DIR; i++) { 66 | reprap_dir_elem[i].type = TREE_EMPTY_ELEM; 67 | } 68 | #ifdef CONFIG_REPPANEL_ESP32_CONSOLE_ENABLED 69 | for (int i = 0; i < MAX_CONSOLE_ENTRY_COUNT; i++) { 70 | console_enties[i] = (console_entry_t) {"", CONSOLE_TYPE_EMPTY}; 71 | } 72 | #endif 73 | 74 | reprap_tool_poss_temps.temps_active[0] = -1; 75 | memset(&reprap_axes, 0, sizeof (reprap_axes_t)); 76 | double bed_temps_hardcoded[] = {0, 30, 53, 60, 80, 100, 105, 110, -1}; // max len 15, last must be <0 77 | double tool_temps_hardcoded[] = {0, 160, 180, 185, 190, 200, 210, 250, 265, 280, 78 | -1}; // max len 15, last must be <0 79 | memcpy(reprap_bed_poss_temps.temps_standby, bed_temps_hardcoded, sizeof(bed_temps_hardcoded)); 80 | memcpy(reprap_bed_poss_temps.temps_active, bed_temps_hardcoded, sizeof(bed_temps_hardcoded)); 81 | memcpy(reprap_tool_poss_temps.temps_standby, tool_temps_hardcoded, sizeof(tool_temps_hardcoded)); 82 | // memcpy(reprap_tool_poss_temps.temps_active, tool_temps_hardcoded, sizeof(tool_temps_hardcoded)); 83 | } 84 | 85 | lv_obj_t *create_button(lv_obj_t *parent, lv_obj_t *button_pnt, char *text, void *event_handler) { 86 | lv_obj_t *label; 87 | button_pnt = lv_btn_create(parent, NULL); 88 | lv_btn_set_fit(button_pnt, LV_FIT_TIGHT); 89 | lv_obj_set_event_cb(button_pnt, event_handler); 90 | lv_obj_align(button_pnt, parent, LV_ALIGN_CENTER, 0, 0); 91 | label = lv_label_create(button_pnt, NULL); 92 | lv_label_set_text(label, text); 93 | return button_pnt; 94 | } 95 | 96 | time_t datestr_2unix(const char *input) { 97 | struct tm info; 98 | if (sscanf(input, "%d-%d-%dT%d:%d:%d", &info.tm_year, &info.tm_mon, &info.tm_mday, &info.tm_hour, &info.tm_min, 99 | &info.tm_sec) != 6) { 100 | return -1; 101 | } else { 102 | info.tm_year = info.tm_year - 1900; 103 | info.tm_mon = info.tm_mon - 1; 104 | info.tm_isdst = -1; 105 | return mktime(&info); 106 | } 107 | } 108 | 109 | /** 110 | * Compare function for qsort. Compares file_tree_elem_t structures by modification date/time stamp. Most recent element 111 | * is first in order (highest number first) 112 | * @param a type file_tree_elem_t 113 | * @param b type file_tree_elem_t 114 | * @return see qsort docs 115 | */ 116 | int compare_tree_element_timestamp(const void *a, const void *b) { 117 | file_tree_elem_t *tree_elemA = (file_tree_elem_t *) a; 118 | file_tree_elem_t *tree_elemB = (file_tree_elem_t *) b; 119 | if (tree_elemA->time_stamp - tree_elemB->time_stamp < 0) 120 | return 1; 121 | if (tree_elemA->time_stamp - tree_elemB->time_stamp > 0) 122 | return -1; 123 | return 0; 124 | } 125 | 126 | void RepPanelLogE(char *tag, char *msg) { 127 | ESP_LOGE(tag, "%s", msg); 128 | } 129 | 130 | void RepPanelLogW(char *tag, char *msg) { 131 | ESP_LOGW(tag, "%s", msg); 132 | } 133 | 134 | void RepPanelLogI(char *tag, char *msg) { 135 | ESP_LOGI(tag, "%s", msg); 136 | } 137 | 138 | void RepPanelLogD(char *tag, char *msg) { 139 | ESP_LOGD(tag, "%s", msg); 140 | } 141 | 142 | void RepPanelLogV(char *tag, char *msg) { 143 | ESP_LOGV(tag, "%s", msg); 144 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_1_0/d99fn.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "", 3 | "flags": "d99fn", 4 | "result": { 5 | "boards": [ 6 | { 7 | "mcuTemp": { 8 | "current": 41.2 9 | }, 10 | "vIn": { 11 | "current": 24 12 | } 13 | } 14 | ], 15 | "fans": [ 16 | { 17 | "actualValue": 0.9, 18 | "requestedValue": 0.9, 19 | "rpm": -1 20 | }, 21 | { 22 | "actualValue": 0.5, 23 | "requestedValue": 0.3, 24 | "rpm": -1 25 | } 26 | ], 27 | "heat": { 28 | "heaters": [ 29 | { 30 | "active": 53, 31 | "current": 53.2, 32 | "standby": 0, 33 | "state": "active" 34 | }, 35 | { 36 | "active": 205, 37 | "current": 204.9, 38 | "standby": 195, 39 | "state": "active" 40 | } 41 | ] 42 | }, 43 | "inputs": [ 44 | { 45 | "feedRate": 50, 46 | "lineNumber": 42, 47 | "state": "idle" 48 | }, 49 | { 50 | "feedRate": 50, 51 | "lineNumber": 0, 52 | "state": "idle" 53 | }, 54 | { 55 | "feedRate": 45, 56 | "lineNumber": 107615, 57 | "state": "waiting" 58 | }, 59 | { 60 | "feedRate": 50, 61 | "lineNumber": 0, 62 | "state": "idle" 63 | }, 64 | { 65 | "feedRate": 50, 66 | "lineNumber": 0, 67 | "state": "idle" 68 | }, 69 | { 70 | "feedRate": 50, 71 | "lineNumber": 0, 72 | "state": "idle" 73 | }, 74 | { 75 | "feedRate": 50, 76 | "lineNumber": 17, 77 | "state": "idle" 78 | }, 79 | { 80 | "feedRate": 50, 81 | "lineNumber": 0, 82 | "state": "idle" 83 | }, 84 | null, 85 | { 86 | "feedRate": 50, 87 | "lineNumber": 0, 88 | "state": "idle" 89 | }, 90 | null, 91 | { 92 | "feedRate": 50, 93 | "lineNumber": 0, 94 | "state": "idle" 95 | } 96 | ], 97 | "job": { 98 | "build": { 99 | "currentObject": -1 100 | }, 101 | "duration": 6047, 102 | "filePosition": 1535722, 103 | "layer": 54, 104 | "layerTime": 42.7, 105 | "pauseDuration": 0, 106 | "rawExtrusion": 14906.5, 107 | "timesLeft": { 108 | "filament": null, 109 | "file": 55524, 110 | "slicer": 62166 111 | }, 112 | "warmUpDuration": 0 113 | }, 114 | "move": { 115 | "axes": [ 116 | { 117 | "machinePosition": 91.2, 118 | "userPosition": 82.514 119 | }, 120 | { 121 | "machinePosition": 182.119, 122 | "userPosition": 179.119 123 | }, 124 | { 125 | "machinePosition": 10.78, 126 | "userPosition": 10.8 127 | } 128 | ], 129 | "currentMove": { 130 | "acceleration": 713.5, 131 | "deceleration": 713.5, 132 | "laserPwm": null, 133 | "requestedSpeed": 45, 134 | "topSpeed": 45 135 | }, 136 | "extruders": [ 137 | { 138 | "position": 13927.4, 139 | "rawPosition": 14906.5 140 | } 141 | ], 142 | "virtualEPos": 0 143 | }, 144 | "sensors": { 145 | "analog": [ 146 | { 147 | "lastReading": 53.2 148 | }, 149 | { 150 | "lastReading": 204.9 151 | } 152 | ], 153 | "endstops": [ 154 | { 155 | "triggered": false 156 | }, 157 | { 158 | "triggered": false 159 | }, 160 | { 161 | "triggered": false 162 | } 163 | ], 164 | "filamentMonitors": [], 165 | "gpIn": [], 166 | "probes": [ 167 | { 168 | "value": [ 169 | 1000 170 | ] 171 | } 172 | ] 173 | }, 174 | "seqs": { 175 | "boards": 0, 176 | "directories": 0, 177 | "fans": 4, 178 | "global": 0, 179 | "heat": 10, 180 | "inputs": 48, 181 | "job": 153, 182 | "move": 102, 183 | "network": 7, 184 | "reply": 44, 185 | "scanner": 1, 186 | "sensors": 3, 187 | "spindles": 0, 188 | "state": 15, 189 | "tools": 9, 190 | "volChanges": [ 191 | 5, 192 | 0 193 | ], 194 | "volumes": 226 195 | }, 196 | "spindles": [ 197 | { 198 | "current": 0, 199 | "state": "unconfigured" 200 | }, 201 | { 202 | "current": 0, 203 | "state": "unconfigured" 204 | }, 205 | { 206 | "current": 0, 207 | "state": "unconfigured" 208 | }, 209 | { 210 | "current": 0, 211 | "state": "unconfigured" 212 | } 213 | ], 214 | "state": { 215 | "atxPower": null, 216 | "currentTool": 0, 217 | "gpOut": [], 218 | "laserPwm": null, 219 | "msUpTime": 32, 220 | "nextTool": 0, 221 | "previousTool": -1, 222 | "status": "processing", 223 | "time": "2021-08-28T11:55:40", 224 | "upTime": 8401 225 | }, 226 | "tools": [ 227 | { 228 | "active": [ 229 | 205 230 | ], 231 | "standby": [ 232 | 195 233 | ], 234 | "state": "active" 235 | } 236 | ] 237 | } 238 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_0_0/dwc2_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": { 3 | "language": "en", 4 | "lastHostname": "192.168.10.13", 5 | "darkTheme": true, 6 | "useBinaryPrefix": true, 7 | "disableAutoComplete": false, 8 | "settingsStorageLocal": false, 9 | "settingsSaveDelay": 2000, 10 | "cacheStorageLocal": true, 11 | "cacheSaveDelay": 4000, 12 | "notifications": { 13 | "errorsPersistent": true, 14 | "timeout": 5000 15 | }, 16 | "webcam": { 17 | "url": "", 18 | "updateInterval": 5000, 19 | "useFix": false, 20 | "embedded": false, 21 | "rotation": 0, 22 | "flip": "none" 23 | } 24 | }, 25 | "machine": { 26 | "ajaxRetries": 2, 27 | "updateInterval": 250, 28 | "extendedUpdateEvery": 20, 29 | "fileTransferRetryThreshold": 358400, 30 | "crcUploads": true, 31 | "pingInterval": 2000, 32 | "babystepAmount": 0.05, 33 | "codes": [ 34 | "G0 X150 Y150 F1000", 35 | "G0 X150 Y150 F10000", 36 | "G0 X158 Y158 F60000", 37 | "G1 S2 X-10", 38 | "G1 S2 X-10 F100", 39 | "G1 S2 X-10 F300", 40 | "G1 S2 X-10 F50", 41 | "G1 S2 X0 F100", 42 | "G1 S2 X10 F100", 43 | "G1 S2 X10 F300", 44 | "G1 S2 X10 F3000", 45 | "G1 S2 X100 F1000", 46 | "G1 S2 X150 F1000", 47 | "G1 S2 X20 F100", 48 | "G1 S2 X20 F300", 49 | "G1 S2 Y-10 F300", 50 | "G1 S2 Y10", 51 | "G1 S2 Y10 F300", 52 | "G1 S2 Z-1", 53 | "G1 S2 Z-10", 54 | "G1 S2 Z-5", 55 | "G1 S2 Z0", 56 | "G1 S2 Z0.5", 57 | "G1 S2 Z1", 58 | "G1 S2 Z10", 59 | "G1 S2 Z2", 60 | "G1 X10 F100", 61 | "G1 X10 F1000", 62 | "G1 X10 Y10 Z0 F100", 63 | "G1 X10 Y10 Z1 F100", 64 | "G1 X10 Y200 F3000", 65 | "G1 X10 Y320 F1000", 66 | "G1 X100 Y10 F6000", 67 | "G1 X100 Y100 F1000", 68 | "G1 X100 Y100 F300", 69 | "G1 X100 Y100 F3000", 70 | "G1 X150 Y150 F1000", 71 | "G1 X150 Y150 F5000", 72 | "G1 X150 Y150 F6000", 73 | "G1 X150 Y180 F6000", 74 | "G1 X158 Y315 F1000", 75 | "G1 X158 Y320 F1000", 76 | "G1 X200 Y200 F3000", 77 | "G1 X200 Y200 F600", 78 | "G1 X300 Y300 F10000", 79 | "G1 X320 F1000", 80 | "G1 X320 F900", 81 | "G1 X320 Y10 F1000", 82 | "G1 X326 Y0 F1000", 83 | "G1 X50 Y50 F10000", 84 | "G1 Y320 F1000", 85 | "G1 Z0 F100", 86 | "G1 Z0 F10000", 87 | "G1 Z0 F3000", 88 | "G1 Z0 F41000", 89 | "G1 Z0 F500", 90 | "G1 Z0 F6000", 91 | "G1 Z1 F100", 92 | "G1 Z10 F100", 93 | "G1 Z10 F300", 94 | "G1 Z10 F600", 95 | "G1 Z10 F6000", 96 | "G1 Z100 F300", 97 | "G1 Z100 F500", 98 | "G1 Z15 F100", 99 | "G1 Z150 F1000", 100 | "G1 Z2 F100", 101 | "G1 Z25 F10000", 102 | "G1 Z3 F100", 103 | "G1 Z3 F500", 104 | "G1 Z3 F600", 105 | "G1 Z3 X10 Y10 F100", 106 | "G1 Z30 F100", 107 | "G1 Z30 F3000", 108 | "G1 Z5 F100", 109 | "G1 Z5 F1000", 110 | "G1 Z5 F500", 111 | "G1 Z5 F700", 112 | "G1 Z50 F800", 113 | "G1 Z8 F1000", 114 | "G91", 115 | "M0", 116 | "M1", 117 | "M122", 118 | "M303", 119 | "M303 H1 S240", 120 | "M307 H0", 121 | "M307 H1", 122 | "M500", 123 | "M572 D0 S0.7", 124 | "M84" 125 | ], 126 | "displayedExtraTemperatures": [], 127 | "displayedExtruders": [ 128 | 0, 129 | 1 130 | ], 131 | "displayedFans": [ 132 | -1 133 | ], 134 | "moveSteps": { 135 | "X": [ 136 | 100, 137 | 50, 138 | 10, 139 | 1, 140 | 0.1 141 | ], 142 | "Y": [ 143 | 100, 144 | 50, 145 | 10, 146 | 1, 147 | 0.1 148 | ], 149 | "Z": [ 150 | 50, 151 | 25, 152 | 5, 153 | 0.5, 154 | 0.05 155 | ], 156 | "default": [ 157 | 100, 158 | 50, 159 | 10, 160 | 1, 161 | 0.1 162 | ] 163 | }, 164 | "moveFeedrate": 6000, 165 | "extruderAmounts": [ 166 | 100, 167 | 50, 168 | 20, 169 | 10, 170 | 5, 171 | 1 172 | ], 173 | "extruderFeedrates": [ 174 | 60, 175 | 30, 176 | 15, 177 | 5, 178 | 1 179 | ], 180 | "temperatures": { 181 | "tool": { 182 | "active": [ 183 | 250, 184 | 235, 185 | 220, 186 | 210, 187 | 205, 188 | 195, 189 | 160, 190 | 120, 191 | 100, 192 | 0 193 | ], 194 | "standby": [ 195 | 210, 196 | 180, 197 | 160, 198 | 140, 199 | 0 200 | ] 201 | }, 202 | "bed": { 203 | "active": [ 204 | 110, 205 | 100, 206 | 90, 207 | 70, 208 | 65, 209 | 60, 210 | 0 211 | ], 212 | "standby": [ 213 | 40, 214 | 30, 215 | 0 216 | ] 217 | }, 218 | "chamber": [ 219 | 90, 220 | 80, 221 | 70, 222 | 60, 223 | 50, 224 | 40, 225 | 0 226 | ] 227 | }, 228 | "spindleRPM": [ 229 | 10000, 230 | 75000, 231 | 5000, 232 | 2500, 233 | 1000, 234 | 0 235 | ] 236 | } 237 | } -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | // 3 | // Copyright (c) 2020 Wolfgang Christl 4 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "freertos/FreeRTOS.h" 13 | #include "freertos/task.h" 14 | #include "esp_freertos_hooks.h" 15 | #include "freertos/semphr.h" 16 | #include "esp_system.h" 17 | 18 | /* Littlevgl specific */ 19 | #include "lvgl/lvgl.h" 20 | #include "lvgl_driver.h" 21 | #include "reppanel.h" 22 | #include "esp32_wifi.h" 23 | #include "reppanel_request.h" 24 | #include "esp32_uart.h" 25 | #include "rrf_objects.h" 26 | #include "screen_saver.h" 27 | 28 | #ifdef CONFIG_REPPANEL_ENABLE_QOI_THUMBNAIL_SUPPORT 29 | #define QOI_IMPLEMENTATION 30 | #define QOI_NO_STDIO 31 | #include "../externals/qoi/qoi.h" 32 | #endif 33 | 34 | #ifdef CONFIG_LVGL_TFT_DISPLAY_MONOCHROME 35 | #include "lv_theme_mono.h" 36 | #endif 37 | #define TAG "Main" 38 | 39 | SemaphoreHandle_t xGuiSemaphore; 40 | double reprap_chamber_temp_buff[NUM_TEMPS_BUFF] = {0}; 41 | int reprap_chamber_temp_curr_pos = 0; 42 | double reprap_babysteps_amount = 0.05; 43 | double reprap_move_feedrate = 6000; 44 | double reprap_mcu_temp = 0; 45 | char reprap_firmware_name[32]; 46 | char reprap_firmware_version[5]; 47 | 48 | static void IRAM_ATTR lv_tick_task(void *arg); 49 | 50 | _Noreturn void guiTask(); 51 | 52 | /********************** 53 | * APPLICATION MAIN 54 | **********************/ 55 | void app_main() { 56 | //If you want to use a task to create the graphic, you NEED to create a Pinned task 57 | //Otherwise there can be problem such as memory corruption and so on 58 | xTaskCreatePinnedToCore(guiTask, "gui", CONFIG_REPPANEL_GUI_TASK_STACK_SIZE, NULL, 0, NULL, 1); 59 | 60 | TaskHandle_t printer_status_task_handle = NULL; 61 | xTaskCreate(request_reprap_status_updates, "Printer Status Update Task", CONFIG_REPPANEL_REQUEST_TASK_STACK_SIZE, NULL, 62 | tskIDLE_PRIORITY, &printer_status_task_handle); 63 | configASSERT(printer_status_task_handle); 64 | } 65 | 66 | static void IRAM_ATTR lv_tick_task(void *arg) { 67 | (void) arg; 68 | lv_tick_inc(portTICK_RATE_MS); 69 | } 70 | 71 | _Noreturn void guiTask() { 72 | /* Inspect our own high water mark on entering the task. */ 73 | // UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL ); 74 | xGuiSemaphore = xSemaphoreCreateMutex(); 75 | lv_init(); 76 | lvgl_driver_init(); 77 | 78 | static lv_color_t buf1[DISP_BUF_SIZE]; 79 | static lv_color_t buf2[DISP_BUF_SIZE]; 80 | static lv_disp_buf_t disp_buf; 81 | lv_disp_buf_init(&disp_buf, buf1, buf2, DISP_BUF_SIZE); 82 | 83 | lv_disp_drv_t disp_drv; 84 | lv_disp_drv_init(&disp_drv); 85 | disp_drv.flush_cb = disp_driver_flush; 86 | #ifdef CONFIG_LVGL_TFT_DISPLAY_MONOCHROME 87 | disp_drv.rounder_cb = disp_driver_rounder; 88 | disp_drv.set_px_cb = disp_driver_set_px; 89 | #endif 90 | 91 | disp_drv.buffer = &disp_buf; 92 | lv_disp_t *lcd_display = lv_disp_drv_register(&disp_drv); 93 | 94 | #if defined CONFIG_LVGL_TFT_DISPLAY_MONOCHROME 95 | lv_theme_mono_init(0, NULL); 96 | lv_theme_set_current( lv_theme_get_mono() ); 97 | #endif 98 | 99 | #if CONFIG_LVGL_TOUCH_CONTROLLER != TOUCH_CONTROLLER_NONE 100 | lv_indev_drv_t indev_drv; 101 | lv_indev_drv_init(&indev_drv); 102 | indev_drv.read_cb = touch_driver_read; 103 | indev_drv.type = LV_INDEV_TYPE_POINTER; 104 | lv_indev_drv_register(&indev_drv); 105 | #endif 106 | 107 | const esp_timer_create_args_t periodic_timer_args = { 108 | .callback = &lv_tick_task, 109 | /* name is optional, but may help identify the timer when debugging */ 110 | .name = "periodic_gui" 111 | }; 112 | esp_timer_handle_t periodic_timer; 113 | ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &periodic_timer)); 114 | //On ESP32 it's better to create a periodic task instead of esp_register_freertos_tick_hook 115 | ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, 10 * 1000)); //10ms (expressed as microseconds) 116 | 117 | 118 | init_reprap_buffers(); 119 | 120 | //Initialize NVS 121 | esp_err_t ret = nvs_flash_init(); 122 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { 123 | ESP_ERROR_CHECK(nvs_flash_erase()); 124 | ret = nvs_flash_init(); 125 | } 126 | ESP_ERROR_CHECK(ret); 127 | init_reprap_model(); 128 | read_settings_nvs(); 129 | rep_panel_ui_create(); 130 | #if defined(CONFIG_REPPANEL_ESP32_WIFI_ENABLED) 131 | #if ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 3 132 | wifi_init_sta_4_3(); 133 | #else 134 | wifi_init_sta(); 135 | #endif 136 | #endif 137 | init_uart(); 138 | 139 | // int c = 0; 140 | // lv_mem_monitor_t m; 141 | while (1) { 142 | vTaskDelay(1); 143 | 144 | // lv_mem_monitor(&m); 145 | // UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL); 146 | // if (c%50) { 147 | // ESP_LOGI(TAG, "%i free bytes in GUI, %i%% used, %i high mark of GUI Task", m.free_size, m.used_pct, 148 | // uxHighWaterMark); 149 | // c = 0; 150 | // } else { c++; } 151 | 152 | //Try to lock the semaphore, if success, call lvgl stuff 153 | if (xSemaphoreTake(xGuiSemaphore, (TickType_t) 10) == pdTRUE) { 154 | lv_task_handler(); 155 | // handle screen saver stuff 156 | if (lv_disp_get_inactive_time(lcd_display) > (CONFIG_REPPANEL_SCREEN_SAVER_TIMEOUT * 1000)) { 157 | activate_screen_saver(); 158 | } else { 159 | deactivate_screen_saver(); 160 | } 161 | xSemaphoreGive(xGuiSemaphore); 162 | } 163 | } 164 | // This task should NEVER return 165 | vTaskDelete(NULL); 166 | } 167 | -------------------------------------------------------------------------------- /main/reppanel_macros.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include "reppanel.h" 9 | #include "reppanel_request.h" 10 | 11 | #define TAG "Macros" 12 | 13 | #define MACRO_ROOT_DIR "0:/macros" 14 | #define MACRO_EMPTY "" 15 | #define BACK_TXT "Back" 16 | 17 | lv_obj_t *macro_list; 18 | lv_obj_t *msg_box3; 19 | lv_obj_t *preloader; 20 | file_tree_elem_t *edit_macro; 21 | char parent_dir_macros[MAX_LEN_DIRNAME + 1]; 22 | 23 | static void exe_macro_file_handler(lv_obj_t *obj, lv_event_t event) { 24 | if (event == LV_EVENT_VALUE_CHANGED) { 25 | if (strcmp(lv_mbox_get_active_btn_text(msg_box3), "Yes") == 0) { 26 | ESP_LOGI(TAG, "Running file %s", lv_list_get_btn_text(obj)); 27 | char tmp_txt[strlen(edit_macro->dir) + strlen(edit_macro->name) + 10]; 28 | sprintf(tmp_txt, "M98 P\"%s/%s\"", edit_macro->dir, edit_macro->name); 29 | reprap_send_gcode(tmp_txt); 30 | lv_obj_del_async(msg_box3); 31 | } else { 32 | lv_obj_del_async(msg_box3); 33 | } 34 | } 35 | } 36 | 37 | static void macro_clicked_event_handler(lv_obj_t *obj, lv_event_t event) { 38 | if (event == LV_EVENT_CLICKED) { 39 | int selected_indx = lv_list_get_btn_index(macro_list, obj); 40 | // check if back button exists 41 | if (strcmp(reprap_dir_elem[0].dir, MACRO_ROOT_DIR) != 0) { 42 | if (selected_indx == 0) { 43 | // back button was pressed 44 | ESP_LOGI(TAG, "Going back to parent %s", parent_dir_macros); 45 | if (!preloader) 46 | preloader = lv_preload_create(lv_layer_top(), NULL); 47 | lv_obj_set_size(preloader, 75, 75); 48 | lv_obj_align_origo(preloader, lv_layer_top(), LV_ALIGN_CENTER, 0, 0); 49 | request_macros(parent_dir_macros); 50 | return; 51 | } else { 52 | // no back button pressed 53 | // decrease index to match with reprap_macros array indexing 54 | selected_indx--; 55 | } 56 | } 57 | edit_macro = &reprap_dir_elem[selected_indx]; 58 | if (edit_macro == NULL) 59 | return; 60 | if (reprap_dir_elem[selected_indx].type == TREE_FILE_ELEM) { 61 | static const char *btns[] = {"Yes", "No", ""}; 62 | msg_box3 = lv_mbox_create(lv_layer_top(), NULL); 63 | char msg[100]; 64 | sprintf(msg, "Do you want to execute %s?", edit_macro->name); 65 | lv_mbox_set_text(msg_box3, msg); 66 | lv_mbox_add_btns(msg_box3, btns); 67 | lv_obj_set_event_cb(msg_box3, exe_macro_file_handler); 68 | lv_obj_set_width(msg_box3, lv_disp_get_hor_res(NULL) - 20); 69 | lv_obj_align(msg_box3, lv_layer_top(), LV_ALIGN_CENTER, 0, 0); 70 | } else if (reprap_dir_elem[selected_indx].type == TREE_FOLDER_ELEM) { 71 | ESP_LOGI(TAG, "Clicked folder %s (index %i)", edit_macro->name, selected_indx); 72 | if (!preloader) 73 | preloader = lv_preload_create(lv_layer_top(), NULL); 74 | lv_obj_set_size(preloader, 75, 75); 75 | lv_obj_align_origo(preloader, lv_layer_top(), LV_ALIGN_CENTER, 0, 0); 76 | static char tmp_txt[MAX_LEN_DIRNAME + MAX_LEN_FILENAME + 1]; 77 | sprintf(tmp_txt, "%s/%s", reprap_dir_elem[selected_indx].dir, edit_macro->name); 78 | request_macros(tmp_txt); 79 | } 80 | } 81 | } 82 | 83 | void update_macro_list_ui() { 84 | if (visible_screen != REPPANEL_MACROS_SCREEN) return; 85 | lv_obj_del(preloader); 86 | if (macro_list) { 87 | lv_list_clean(macro_list); 88 | ESP_LOGI(TAG, "Cleaned Macro List"); 89 | } else { 90 | return; 91 | } 92 | 93 | // Add back button in case we are not in root directory 94 | if (strcmp(reprap_dir_elem[0].dir, MACRO_ROOT_DIR) != 0) { 95 | lv_obj_t *back_btn; 96 | back_btn = lv_list_add_btn(macro_list, LV_SYMBOL_LEFT, BACK_TXT); 97 | lv_obj_set_event_cb(back_btn, macro_clicked_event_handler); 98 | // update parent dir 99 | strcpy(parent_dir_macros, reprap_dir_elem[0].dir); 100 | char *pch; 101 | pch = strrchr(parent_dir_macros, '/'); 102 | parent_dir_macros[pch - parent_dir_macros] = '\0'; 103 | } else { 104 | strcpy(parent_dir_macros, MACRO_EMPTY); 105 | } 106 | // count number of elements 107 | uint8_t cnt = 0; 108 | for (int i = 0; reprap_dir_elem[i].type != TREE_EMPTY_ELEM && i < MAX_NUM_ELEM_DIR; i++) { 109 | cnt++; 110 | } 111 | // sort by modification date 112 | qsort(reprap_dir_elem, cnt, sizeof(file_tree_elem_t), compare_tree_element_timestamp); 113 | for (int i = 0; reprap_dir_elem[i].type != TREE_EMPTY_ELEM && i < MAX_NUM_ELEM_DIR; i++) { 114 | lv_obj_t *list_btn; 115 | if (reprap_dir_elem[i].type == TREE_FOLDER_ELEM) 116 | list_btn = lv_list_add_btn(macro_list, LV_SYMBOL_DIRECTORY, reprap_dir_elem[i].name); 117 | else 118 | list_btn = lv_list_add_btn(macro_list, LV_SYMBOL_FILE, reprap_dir_elem[i].name); 119 | lv_obj_set_event_cb(list_btn, macro_clicked_event_handler); 120 | } 121 | } 122 | 123 | void draw_macro(lv_obj_t *parent_screen) { 124 | // strcpy(parent_dir_macros, MACRO_EMPTY); 125 | lv_obj_t *macro_container = lv_cont_create(parent_screen, NULL); 126 | lv_cont_set_layout(macro_container, LV_LAYOUT_COL_M); 127 | lv_cont_set_fit(macro_container, LV_FIT_FILL); 128 | 129 | preloader = lv_preload_create(macro_container, NULL); 130 | lv_obj_set_size(preloader, 75, 75); 131 | 132 | macro_list = lv_list_create(macro_container, NULL); 133 | lv_obj_set_size(macro_list, LV_HOR_RES - 10, lv_disp_get_ver_res(NULL) - (lv_obj_get_height(cont_header) + 5)); 134 | 135 | request_macros(MACRO_ROOT_DIR); 136 | } -------------------------------------------------------------------------------- /debug_responses/RRF3_1_0/move.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "move", 3 | "flags": "d99vn", 4 | "result": { 5 | "axes": [ 6 | { 7 | "acceleration": 3500, 8 | "babystep": 0, 9 | "current": 1100, 10 | "drivers": [ 11 | "0" 12 | ], 13 | "homed": true, 14 | "jerk": 1060, 15 | "letter": "X", 16 | "machinePosition": 62.988, 17 | "max": 326, 18 | "maxProbed": false, 19 | "microstepping": { 20 | "interpolated": true, 21 | "value": 16 22 | }, 23 | "min": 0, 24 | "minProbed": false, 25 | "speed": 18000, 26 | "stepsPerMm": 100, 27 | "userPosition": 124.749, 28 | "visible": true, 29 | "workplaceOffsets": [ 30 | 0, 31 | 0, 32 | 0, 33 | 0, 34 | 0, 35 | 0, 36 | 0, 37 | 0, 38 | 0 39 | ] 40 | }, 41 | { 42 | "acceleration": 3500, 43 | "babystep": 0, 44 | "current": 1100, 45 | "drivers": [ 46 | "1" 47 | ], 48 | "homed": true, 49 | "jerk": 1060, 50 | "letter": "Y", 51 | "machinePosition": 150.324, 52 | "max": 326, 53 | "maxProbed": false, 54 | "microstepping": { 55 | "interpolated": true, 56 | "value": 16 57 | }, 58 | "min": 0, 59 | "minProbed": false, 60 | "speed": 18000, 61 | "stepsPerMm": 100, 62 | "userPosition": 175.476, 63 | "visible": true, 64 | "workplaceOffsets": [ 65 | 0, 66 | 0, 67 | 0, 68 | 0, 69 | 0, 70 | 0, 71 | 0, 72 | 0, 73 | 0 74 | ] 75 | }, 76 | { 77 | "acceleration": 250, 78 | "babystep": -0.02, 79 | "current": 1400, 80 | "drivers": [ 81 | "2" 82 | ], 83 | "homed": true, 84 | "jerk": 20, 85 | "letter": "Z", 86 | "machinePosition": 10.78, 87 | "max": 311.57, 88 | "maxProbed": true, 89 | "microstepping": { 90 | "interpolated": true, 91 | "value": 16 92 | }, 93 | "min": 0, 94 | "minProbed": false, 95 | "speed": 3600, 96 | "stepsPerMm": 400, 97 | "userPosition": 10.8, 98 | "visible": true, 99 | "workplaceOffsets": [ 100 | 0, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, 106 | 0, 107 | 0, 108 | 0 109 | ] 110 | } 111 | ], 112 | "calibration": { 113 | "final": { 114 | "deviation": 0, 115 | "mean": 0 116 | }, 117 | "initial": { 118 | "deviation": 0, 119 | "mean": 0 120 | }, 121 | "numFactors": 0 122 | }, 123 | "compensation": { 124 | "fadeHeight": null, 125 | "file": "0:/sys/heightmap.csv", 126 | "meshDeviation": { 127 | "deviation": 0, 128 | "mean": 0 129 | }, 130 | "probeGrid": { 131 | "axes": [ 132 | "X", 133 | "Y" 134 | ], 135 | "maxs": [ 136 | 276, 137 | 276 138 | ], 139 | "mins": [ 140 | 50, 141 | 50 142 | ], 143 | "radius": -1, 144 | "spacings": [ 145 | 22.6, 146 | 22.6 147 | ] 148 | }, 149 | "skew": { 150 | "compensateXY": true, 151 | "tanXY": 0, 152 | "tanXZ": 0, 153 | "tanYZ": 0 154 | }, 155 | "type": "mesh" 156 | }, 157 | "currentMove": { 158 | "acceleration": 713.6, 159 | "deceleration": 713.6, 160 | "laserPwm": null, 161 | "requestedSpeed": 40, 162 | "topSpeed": 40 163 | }, 164 | "extruders": [ 165 | { 166 | "acceleration": 3500, 167 | "current": 800, 168 | "driver": "3", 169 | "factor": 0.93, 170 | "filament": "PLA", 171 | "jerk": 1260, 172 | "microstepping": { 173 | "interpolated": true, 174 | "value": 16 175 | }, 176 | "nonlinear": { 177 | "a": 0, 178 | "b": 0, 179 | "upperLimit": 0.2 180 | }, 181 | "position": 13871.3, 182 | "pressureAdvance": 0.4, 183 | "rawPosition": 14844.1, 184 | "speed": 5000, 185 | "stepsPerMm": 415 186 | } 187 | ], 188 | "idle": { 189 | "factor": 0.3, 190 | "timeout": 30 191 | }, 192 | "kinematics": { 193 | "forwardMatrix": [ 194 | [ 195 | 0.5, 196 | 0.5, 197 | 0 198 | ], 199 | [ 200 | 0.5, 201 | -0.5, 202 | 0 203 | ], 204 | [ 205 | 0, 206 | 0, 207 | 1 208 | ] 209 | ], 210 | "inverseMatrix": [ 211 | [ 212 | 0.5, 213 | 0.5, 214 | 0 215 | ], 216 | [ 217 | 0.5, 218 | -0.5, 219 | 0 220 | ], 221 | [ 222 | 0, 223 | 0, 224 | 1 225 | ] 226 | ], 227 | "name": "coreXY", 228 | "tiltCorrection": { 229 | "correctionFactor": 1, 230 | "lastCorrections": [ 231 | 0, 232 | 0, 233 | 0 234 | ], 235 | "maxCorrection": 1, 236 | "screwPitch": 0.5, 237 | "screwX": [ 238 | 163, 239 | 20, 240 | 306 241 | ], 242 | "screwY": [ 243 | 306, 244 | 20, 245 | 20 246 | ] 247 | } 248 | }, 249 | "printingAcceleration": 3300, 250 | "queue": [ 251 | { 252 | "gracePeriod": 0.01, 253 | "length": 40 254 | }, 255 | { 256 | "gracePeriod": 0.01, 257 | "length": 3 258 | } 259 | ], 260 | "shaping": { 261 | "damping": 0.2, 262 | "frequency": 40, 263 | "minimumAcceleration": 10, 264 | "type": "none" 265 | }, 266 | "speedFactor": 1, 267 | "travelAcceleration": 3500, 268 | "virtualEPos": 0, 269 | "workplaceNumber": 0 270 | } 271 | } -------------------------------------------------------------------------------- /main/reppanel.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifndef LVGL_REPPANEL_H 6 | #define LVGL_REPPANEL_H 7 | 8 | #include 9 | 10 | #include "reppanel_helper.h" 11 | #include "esp32_settings.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #define MAX_PREPANEL_TEMP_LEN 8 18 | 19 | #define BTN_BED_TMP_ACTIVE 0 20 | #define BTN_BED_TMP_STANDBY 1 21 | #define BTN_TOOL_TMP_ACTIVE 2 22 | #define BTN_TOOL_TMP_STANDBY 3 23 | 24 | #define REPPANEL_NO_CONNECTION 0 25 | #define REPPANEL_WIFI_CONNECTED 1 26 | #define REPPANEL_WIFI_CONNECTED_DUET_DISCONNECTED 2 27 | #define REPPANEL_WIFI_DISCONNECTED 3 28 | #define REPPANEL_WIFI_RECONNECTING 4 29 | #define REPPANEL_UART_CONNECTED 5 30 | 31 | #define VERSION_MAJOR 1 32 | #define VERSION_MINOR 4 33 | #define VERSION_HOTFIX 0 34 | 35 | #define NUM_TEMPS_BUFF 15 36 | #define MAX_FILA_NAME_LEN 32 37 | #define MAX_TOOL_NAME_LEN 12 38 | #define MAX_LEN_STR_FILAMENT_LIST (MAX_FILA_NAME_LEN * 32) 39 | #define MAX_NUM_ELEM_DIR CONFIG_REPPANEL_MAX_NUM_ELEM_DIR // Max number of elements per directory that can be listed 40 | #define REPPANEL_RRF_MAX_AXES 5 41 | 42 | #define MAX_LEN_FILENAME CONFIG_REPPANEL_MAX_FILENAME_LENGTH 43 | #define MAX_LEN_DIRNAME CONFIG_REPPANEL_MAX_DIRECTORY_PATH_LENGTH 44 | 45 | #define TREE_EMPTY_ELEM (-1) 46 | 47 | #define TREE_FOLDER_ELEM 0 48 | #define TREE_FILE_ELEM 1 49 | 50 | // Used to prevent updating elements on a screen that does not exist anymore. 51 | #define REPPANEL_PROCESS_SCREEN 0 52 | #define REPPANEL_JOBSELECT_SCREEN 1 53 | #define REPPANEL_JOBSTATUS_SCREEN 2 54 | #define REPPANEL_MACHINE_SCREEN 3 55 | #define REPPANEL_MACROS_SCREEN 4 56 | #define REPPANEL_OTHER_SCREEN 128 57 | // Used to prevent updating elements on a screen that does not exist anymore. 58 | extern uint8_t visible_screen; 59 | 60 | extern int rp_conn_stat; // REPPANEL_NO_CONNECTION, ... etc. 61 | 62 | extern lv_obj_t *process_scr; // screen for the process settings 63 | extern lv_obj_t *mainmenu_scr; // screen for the main_menu 64 | extern lv_obj_t *cont_header; 65 | 66 | extern lv_obj_t *label_status; 67 | extern lv_obj_t *label_chamber_temp; 68 | extern lv_obj_t *label_bed_temp; 69 | extern lv_obj_t *label_tool_temp; 70 | // extern lv_obj_t *label_progress_percent; 71 | extern lv_obj_t *main_menu_button; 72 | extern lv_obj_t *console_button; 73 | extern lv_obj_t *label_extruder_name; 74 | 75 | extern lv_obj_t *button_tool_filament; 76 | extern lv_obj_t *ddlist_selected_filament; 77 | extern lv_obj_t *label_connection_status; 78 | 79 | 80 | extern int reprap_chamber_temp_curr_pos; 81 | extern double reprap_chamber_temp_buff[NUM_TEMPS_BUFF]; 82 | 83 | // predefined by d2wc config. Temps the heaters can be set to 84 | extern double reprap_babysteps_amount; 85 | extern double reprap_extruder_amounts[NUM_TEMPS_BUFF]; 86 | extern double reprap_extruder_feedrates[NUM_TEMPS_BUFF]; 87 | extern double reprap_move_feedrate; 88 | extern double reprap_mcu_temp; 89 | extern float reprap_job_percent; 90 | extern double reprap_job_first_layer_height; 91 | extern double reprap_job_layer_height; 92 | extern char reprap_firmware_name[32]; 93 | extern char reprap_firmware_version[5]; 94 | 95 | typedef struct { 96 | double axes[REPPANEL_RRF_MAX_AXES]; // machine pos - X,Y,Z,A,B 97 | bool homed[REPPANEL_RRF_MAX_AXES]; 98 | char letter[REPPANEL_RRF_MAX_AXES]; 99 | double min[REPPANEL_RRF_MAX_AXES]; 100 | double max[REPPANEL_RRF_MAX_AXES]; 101 | double babystep[REPPANEL_RRF_MAX_AXES]; 102 | } reprap_axes_t; 103 | 104 | typedef struct { 105 | bool power; 106 | int16_t fan; 107 | } reprap_params_t; 108 | 109 | typedef struct { 110 | int number; 111 | char name[MAX_TOOL_NAME_LEN]; 112 | int fans; 113 | char filament[MAX_FILA_NAME_LEN]; 114 | int heater_indx; // only support one heater per tool for now 115 | double temp_buff[NUM_TEMPS_BUFF]; // Temp buffer contains temperature history of heaters 116 | int temp_hist_curr_pos; // Pointers to current position within the temp buffer 117 | double active_temp; 118 | double standby_temp; 119 | } reprap_tool_t; 120 | 121 | typedef struct { 122 | double temp_buff[NUM_TEMPS_BUFF]; // Temp buffer contains temperature history of heater 123 | int temp_hist_curr_pos; // Pointers to current position within the temp buffer 124 | int heater_indx; 125 | double active_temp; 126 | double standby_temp; 127 | } reprap_bed_t; 128 | 129 | typedef struct { 130 | double temps_standby[NUM_TEMPS_BUFF]; 131 | double temps_active[NUM_TEMPS_BUFF]; 132 | } reprap_tool_poss_temps_t; 133 | 134 | typedef struct { 135 | double temps_standby[NUM_TEMPS_BUFF]; 136 | double temps_active[NUM_TEMPS_BUFF]; 137 | } reprap_bed_poss_temps_t; 138 | 139 | typedef struct { 140 | char name[MAX_LEN_FILENAME]; // name of the files 141 | char dir[MAX_LEN_DIRNAME]; // current directory 142 | time_t time_stamp; // unix timestamp indicating last change/upload of element 143 | int type; // TREE_FOLDER_ELEM, TREE_FILE_ELEM, TREE_EMPTY_ELEM -> last element 144 | } file_tree_elem_t; 145 | 146 | extern file_tree_elem_t reprap_dir_elem[MAX_NUM_ELEM_DIR]; // Array used for buffering directory listings like macros/jobs 147 | 148 | // pos 0 is bed temp, rest are tool heaters 149 | enum {HEATER_OFF, HEATER_STDBY, HEATER_ACTIVE, HEATER_FAULT}; 150 | extern int heater_states[MAX_NUM_TOOLS]; // 0=off, 1=standby, 2=active, 3=fault - Storage for incoming data 151 | //extern int num_heaters; // max is MAX_NUM_TOOLS 152 | //extern int num_tools; // max is MAX_NUM_TOOLS 153 | extern int current_visible_tool_indx; // current indx of tool where temp data is displayed on process screen 154 | 155 | extern reprap_axes_t reprap_axes; 156 | extern reprap_params_t reprap_params; 157 | extern reprap_tool_t reprap_tools[MAX_NUM_TOOLS]; 158 | extern reprap_bed_t reprap_bed; 159 | extern reprap_tool_poss_temps_t reprap_tool_poss_temps; 160 | extern reprap_bed_poss_temps_t reprap_bed_poss_temps; 161 | 162 | extern char filament_names[MAX_LEN_STR_FILAMENT_LIST]; 163 | 164 | extern bool job_paused; 165 | extern bool job_running; 166 | extern int seq_num_msgbox; 167 | 168 | void rep_panel_ui_create(); 169 | 170 | void update_rep_panel_conn_status(); 171 | 172 | void display_jobstatus(); 173 | 174 | #ifdef __cplusplus 175 | } /* extern "C" */ 176 | #endif 177 | 178 | #endif //LVGL_REPPANEL_H 179 | -------------------------------------------------------------------------------- /main/esp32_uart.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | // 5 | 6 | #include 7 | #include "driver/gpio.h" 8 | #include 9 | #include 10 | #include 11 | 12 | #include "esp32_uart.h" 13 | #include "reppanel.h" 14 | 15 | #define TAG "ESP_UART" 16 | 17 | #define UART_READ_TIMEOUT 30 // ms 18 | #define UART_RESP_TIMEOUT 15000000 // us [1s] 19 | #define MAX_NUM_TIMEOUTS 1 // max number of timeouts to tolerate till we switch to WiFi 20 | 21 | const int uart_num = UART_NUM_2; 22 | bool uart_inited = false; 23 | static int timeout_cnt = 0; 24 | 25 | void init_uart() { 26 | ESP_LOGI(TAG, "Initing UART%i ...", uart_num); 27 | uart_config_t uart_config = { 28 | .baud_rate = 57600, 29 | .data_bits = UART_DATA_8_BITS, 30 | .parity = UART_PARITY_DISABLE, 31 | .stop_bits = UART_STOP_BITS_1, 32 | .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, 33 | }; 34 | ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config)); 35 | ESP_ERROR_CHECK(uart_set_pin(uart_num, GPIO_NUM_17, GPIO_NUM_16, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); 36 | // Setup UART buffered IO with event queue 37 | const int uart_buffer_size = UART_DATA_BUFF_LEN; 38 | // Install UART driver using an event queue here 39 | ESP_ERROR_CHECK(uart_driver_install(uart_num, 1024 * 3, uart_buffer_size, 10, NULL, 0)); 40 | ESP_LOGI(TAG, "UART%i init done", uart_num); 41 | uart_inited = true; 42 | } 43 | 44 | bool reppanel_is_uart_connected() { 45 | if (!uart_inited) { 46 | ESP_LOGW(TAG, "Uart not inited - skipping connection check"); 47 | return false; 48 | } 49 | 50 | char comm[] = {"M408 S0\r\n"}; 51 | if (uart_write_bytes(uart_num, (const char *) comm, strlen(comm)) != strlen(comm)) { 52 | ESP_LOGW(TAG, "Duet connection check - Could not push all bytes to write buffer!"); 53 | return false; 54 | } 55 | int length = 0; 56 | uart_wait_tx_done(uart_num, UART_READ_TIMEOUT / portTICK_RATE_MS); 57 | ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, (size_t *) &length)); 58 | uint8_t data = 0; 59 | while (length > 0 && data != '\n') { 60 | uart_read_bytes(uart_num, &data, 1, 20 / portTICK_RATE_MS); 61 | length++; 62 | } 63 | uart_flush(uart_num); 64 | ESP_LOGI(TAG, "Checked for connected UART- received %i bytes", length); 65 | return (length > 0); 66 | } 67 | 68 | void esp32_flush_uart() { 69 | if (uart_inited) { 70 | uart_flush(uart_num); 71 | } 72 | } 73 | 74 | void reppanel_write_uart(char *buffer, int buffer_len) { 75 | if (uart_inited) { 76 | if (uart_write_bytes(uart_num, (const char *) buffer, buffer_len) != buffer_len) 77 | ESP_LOGW(TAG, "Could not push all bytes to write buffer!"); 78 | uart_write_bytes(uart_num, "\r\n", 2); 79 | uart_wait_tx_done(uart_num, UART_READ_TIMEOUT / portTICK_RATE_MS); 80 | } 81 | } 82 | 83 | /** 84 | * Read from UART - Timeout not really working! 85 | * @param receive_buff 86 | * @return -1 on error 87 | */ 88 | int reppanel_read_uart(uart_response_buff_t *receive_buff) { 89 | if (uart_inited) { 90 | int length = 0; 91 | ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, (size_t *) &length)); 92 | if (length <= (UART_RESP_BUFF_SIZE-receive_buff->buf_pos)) 93 | length = uart_read_bytes(uart_num, &receive_buff->buffer[receive_buff->buf_pos], length, 94 | UART_READ_TIMEOUT / portTICK_RATE_MS); 95 | else { 96 | ESP_LOGE(TAG, "UART response too big for buffer %i !", length); 97 | return -1; 98 | } 99 | receive_buff->buf_pos += length; 100 | if (length > 0) ESP_LOGD(TAG, "Received %i", length); 101 | return length; 102 | } else { 103 | ESP_LOGW(TAG, "UART not inited - skipping read UART"); 104 | return -1; 105 | } 106 | } 107 | 108 | void read_timeout() { 109 | timeout_cnt++; 110 | ESP_LOGW(TAG, "Read timeout"); 111 | if (timeout_cnt >= MAX_NUM_TIMEOUTS) { 112 | ESP_LOGW(TAG, "Detected %i timeouts on UART. Switching to WiFi", timeout_cnt); 113 | rp_conn_stat = REPPANEL_WIFI_CONNECTED_DUET_DISCONNECTED; 114 | timeout_cnt = 0; 115 | } 116 | } 117 | 118 | /** 119 | * Read a response from Duet from UART and write it to the provided buffer 120 | * @param receive_buff Receiving buffer 121 | * @return False in case of read timeout or not inited UART or overflow, True in case of valid response 122 | */ 123 | bool reppanel_read_response(uart_response_buff_t *receive_buff) { 124 | if (!uart_inited) { 125 | ESP_LOGW(TAG, "Can not read response - Wait for UART init first"); 126 | return false; 127 | } 128 | memset(receive_buff, 0, sizeof(uart_response_buff_t)); 129 | receive_buff->buf_pos = 0; 130 | 131 | struct timeval tv_now; 132 | gettimeofday(&tv_now, NULL); 133 | int64_t start_time_us = (int64_t) tv_now.tv_sec * 1000000L + (int64_t) tv_now.tv_usec; 134 | 135 | // get complete response 136 | bool response_incomplete = true; 137 | do { 138 | if (reppanel_read_uart(receive_buff) == -1) return false; 139 | if (receive_buff->buf_pos >= UART_RESP_BUFF_SIZE) { 140 | ESP_LOGE(TAG, "UART response buffer with receive_buff->buf_pos/%i bytes overflowed", UART_RESP_BUFF_SIZE); 141 | } 142 | gettimeofday(&tv_now, NULL); 143 | int64_t current_time_us = (int64_t) tv_now.tv_sec * 1000000L + (int64_t) tv_now.tv_usec; 144 | if (current_time_us - start_time_us > UART_RESP_TIMEOUT) { 145 | read_timeout(); 146 | ESP_LOGW(TAG, "UART_REPS_TIMEOUT - waited %i milliseconds", (int) (UART_RESP_TIMEOUT/1e3)); 147 | return false; 148 | } 149 | 150 | if (receive_buff->buf_pos > 0) { 151 | if (receive_buff->buffer[receive_buff->buf_pos - 1] == '\n') { 152 | response_incomplete = false; 153 | } 154 | } 155 | } while(response_incomplete && receive_buff->buf_pos < UART_RESP_BUFF_SIZE); 156 | 157 | if (receive_buff->buffer[receive_buff->buf_pos - 1] == '\n') { 158 | ESP_LOGD(TAG, "Found new line char at %i", receive_buff->buf_pos - 1); 159 | } 160 | timeout_cnt = 0; 161 | ESP_LOGD(TAG, "---> Response complete with %i bytes", receive_buff->buf_pos); 162 | receive_buff->buffer[receive_buff->buf_pos - 1] = '\0'; // replace new line with string end char to parse JSON 163 | ESP_LOGD(TAG, "%s", receive_buff->buffer); 164 | return true; 165 | } 166 | -------------------------------------------------------------------------------- /main/reppanel_console.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #ifdef CONFIG_REPPANEL_ESP32_CONSOLE_ENABLED 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "reppanel_console.h" 12 | #include "reppanel.h" 13 | #include "reppanel_request.h" 14 | 15 | 16 | lv_obj_t *ta_command; 17 | lv_obj_t *user_comm_cont; 18 | lv_obj_t *comm_page; 19 | lv_obj_t *console_page; 20 | lv_obj_t *kb; 21 | 22 | console_entry_t console_enties[MAX_CONSOLE_ENTRY_COUNT]; 23 | static int num_console_entries = 0; 24 | static int pos_newest_entry = -1; 25 | 26 | void send_user_command() { 27 | if (strlen(lv_ta_get_text(ta_command)) > 0) { 28 | char txt[strlen(lv_ta_get_text(ta_command))]; 29 | strcpy(txt, lv_ta_get_text(ta_command)); 30 | printf("Sending command %s\n", txt); 31 | reprap_send_gcode(txt); 32 | } 33 | } 34 | 35 | static void kb_event_cb(lv_obj_t *event_kb, lv_event_t event) { 36 | /* Just call the regular event handler */ 37 | lv_kb_def_event_cb(event_kb, event); 38 | if (event == LV_EVENT_CANCEL) { 39 | lv_obj_del(kb); 40 | kb = NULL; 41 | } else if (event == LV_EVENT_APPLY) { 42 | send_user_command(); 43 | } 44 | } 45 | 46 | static void ta_event_handler(lv_obj_t *obj, lv_event_t event) { 47 | if (event == LV_EVENT_CLICKED) { 48 | if (kb != NULL) lv_obj_del(kb); 49 | kb = lv_kb_create(user_comm_cont, NULL); 50 | lv_obj_set_pos(kb, 5, 90); 51 | lv_obj_set_event_cb(kb, 52 | kb_event_cb); /* Setting a custom event handler stops the keyboard from closing automatically */ 53 | lv_obj_set_size(kb, LV_HOR_RES - 35, 140); 54 | lv_kb_set_ta(kb, ta_command); 55 | } 56 | } 57 | 58 | static void send_gcode_event_handler(lv_obj_t *obj, lv_event_t event) { 59 | if (event == LV_EVENT_CLICKED) { 60 | send_user_command(); 61 | } 62 | } 63 | 64 | void add_entry_to_ui(char *command, char *response, enum console_msg_type type) { 65 | lv_obj_t *c1 = lv_cont_create(comm_page, NULL); 66 | 67 | static lv_style_t entry_style_info; 68 | lv_style_copy(&entry_style_info, lv_cont_get_style(c1, LV_CONT_STYLE_MAIN)); 69 | entry_style_info.body.main_color = REP_PANEL_DARK_ACCENT; 70 | entry_style_info.body.grad_color = REP_PANEL_DARK_ACCENT_ALT1; 71 | entry_style_info.body.padding.inner = LV_DPI / 100; 72 | static lv_style_t entry_style_warn; 73 | lv_style_copy(&entry_style_warn, &entry_style_info); 74 | entry_style_warn.body.main_color = REP_PANEL_DARK_RED; 75 | entry_style_warn.body.grad_color = REP_PANEL_DARK_DARK_RED; 76 | static lv_style_t entry_style_reppanel; 77 | lv_style_copy(&entry_style_reppanel, &entry_style_info); 78 | entry_style_reppanel.body.main_color = REP_PANEL_DARK_HIGHLIGHT; 79 | entry_style_reppanel.body.grad_color = REP_PANEL_DARK_HIGHLIGHT_DARK; 80 | switch (type) { 81 | default: 82 | case CONSOLE_TYPE_INFO: 83 | lv_cont_set_style(c1, LV_CONT_STYLE_MAIN, &entry_style_info); 84 | break; 85 | case CONSOLE_TYPE_WARN: 86 | lv_cont_set_style(c1, LV_CONT_STYLE_MAIN, &entry_style_warn); 87 | break; 88 | case CONSOLE_TYPE_REPPANEL: 89 | lv_cont_set_style(c1, LV_CONT_STYLE_MAIN, &entry_style_reppanel); 90 | break; 91 | } 92 | lv_cont_set_fit2(c1, LV_FIT_FILL, LV_FIT_TIGHT); 93 | lv_cont_set_layout(c1, LV_LAYOUT_COL_L); 94 | lv_obj_t *l1 = lv_label_create(c1, NULL); 95 | static lv_style_t l1_style; 96 | lv_style_copy(&l1_style, lv_label_get_style(l1, LV_LABEL_STYLE_MAIN)); 97 | l1_style.text.font = &reppanel_font_roboto_bold_16; 98 | l1_style.text.color = REP_PANEL_DARK; 99 | lv_label_set_style(l1, LV_LABEL_STYLE_MAIN, &l1_style); 100 | lv_label_set_text(l1, command); 101 | if (response != NULL && strlen(response) > 0) { 102 | lv_obj_t *l11 = lv_label_create(c1, NULL); 103 | static lv_style_t l11_style; 104 | lv_style_copy(&l11_style, lv_label_get_style(l11, LV_LABEL_STYLE_MAIN)); 105 | l11_style.text.font = &lv_font_roboto_16; 106 | l11_style.text.color = REP_PANEL_DARK; 107 | lv_label_set_style(l11, LV_LABEL_STYLE_MAIN, &l11_style); 108 | 109 | lv_label_set_text(l11, response); 110 | } 111 | } 112 | 113 | /** 114 | * Refresh console history. Must run on UI thread. 115 | * @param enties 116 | */ 117 | void update_entries_ui() { 118 | if (comm_page) { 119 | lv_page_clean(comm_page); 120 | // get newest entry in buffer 121 | console_entry_t *entry; 122 | int indx = pos_newest_entry; 123 | entry = &console_enties[indx]; 124 | for (int i = 0; i < num_console_entries; i++) { 125 | if (strlen(entry->command) > 0) { 126 | add_entry_to_ui(entry->command, NULL, entry->type); 127 | entry--; 128 | indx--; 129 | if (indx < 0) { 130 | indx = MAX_CONSOLE_ENTRY_COUNT - 1; 131 | entry = &console_enties[indx]; 132 | } 133 | } 134 | 135 | } 136 | } 137 | } 138 | 139 | /** 140 | * Add a new console history command. Update UI via update_entries_ui() 141 | * @param command 142 | * @param response 143 | * @param type For example CONSOLE_TYPE_WARN | CONSOLE_TYPE_REPPANEL 144 | */ 145 | void add_console_hist_entry(char *command, enum console_msg_type type) { 146 | if ((MAX_CONSOLE_ENTRY_COUNT - 1) > pos_newest_entry) { 147 | pos_newest_entry++; 148 | num_console_entries++; 149 | } else 150 | pos_newest_entry = 0; 151 | console_entry_t e = {.command = "", .type = type}; 152 | strlcpy(e.command, command, sizeof(e.command)); 153 | console_enties[pos_newest_entry] = e; 154 | } 155 | 156 | void draw_console(lv_obj_t *parent_screen) { 157 | console_page = lv_page_create(parent_screen, NULL); 158 | lv_obj_set_size(console_page, lv_disp_get_hor_res(NULL), 159 | lv_disp_get_ver_res(NULL) - (lv_obj_get_height(cont_header) + 5)); 160 | lv_obj_align(console_page, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); 161 | lv_page_set_scrl_layout(console_page, LV_LAYOUT_COL_L); 162 | 163 | user_comm_cont = lv_cont_create(console_page, NULL); 164 | lv_cont_set_fit(user_comm_cont, LV_FIT_TIGHT); 165 | lv_cont_set_layout(user_comm_cont, LV_LAYOUT_COL_M); 166 | 167 | lv_obj_t *user_comm_enter_cont = lv_cont_create(user_comm_cont, NULL); 168 | lv_cont_set_fit(user_comm_enter_cont, LV_FIT_TIGHT); 169 | lv_cont_set_layout(user_comm_enter_cont, LV_LAYOUT_ROW_M); 170 | 171 | ta_command = lv_ta_create(user_comm_enter_cont, NULL); 172 | lv_ta_set_cursor_type(ta_command, LV_CURSOR_LINE); 173 | lv_ta_set_one_line(ta_command, true); 174 | lv_obj_set_event_cb(ta_command, ta_event_handler); 175 | lv_ta_set_text(ta_command, "G28"); 176 | 177 | static lv_obj_t *btn_send_gcode; 178 | create_button(user_comm_enter_cont, btn_send_gcode, LV_SYMBOL_UPLOAD" Send", send_gcode_event_handler); 179 | 180 | lv_obj_set_size(ta_command, lv_disp_get_hor_res(NULL) - 180, 30); 181 | 182 | comm_page = lv_page_create(console_page, NULL); 183 | lv_obj_set_size(comm_page, lv_disp_get_hor_res(NULL) - 30, 184 | lv_disp_get_ver_res(NULL) - (lv_obj_get_height(cont_header) + 80)); 185 | lv_page_set_scrl_layout(comm_page, LV_LAYOUT_COL_L); 186 | 187 | update_entries_ui(); 188 | } 189 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RepPanel 2 | 3 | ## New Version HWv2 available 4 | [Check out the new version RepPanel HWv2 for RepRap-based 3D Printers! Improved performance with ready to flash hardware from your local supplier.](https://reppanel.com) 5 | 6 | ## Older HWv1 version 7 | A simple user interface for Duet/RepRap based 3D printers. Optimized for 3.5" touch 8 | panels controlled via SPI & I²C using an ESP32. 9 | 10 | Supports wireless connection or wired via UART/PanelDue port. 11 | 12 | An open source alternative to the PanelDue. 13 | - Cheap (~18€ display + 7€ ESP32) 14 | - Beautifully dark 15 | - Compact and easy to use 16 | - Support for most operations required to set up a 3D print 17 | - Wireless connection - portable with power bar 18 | - PanelDue-port/UART connection 19 | 20 | The all-in-one module is currently not available but you can give me an idea on how much interest there is. The module will be ready to use and thinner than a DIY solution. It includes a custom board, display and more capable ESP32 (more storage for directory listings etc.). I would try to get the price somewhere ~50-60€ + shipping from Germany. Click the link above and enter your email to get notified when a module becomes available. Thanks! 21 | 22 | ![RepPanel main menu](wiki/RepPanel_Main.png) 23 | 24 | ## Features 25 | Since RepPanel boots in ~1 second you can start setting up your printer in no time and with no additional hardware. 26 | No need to get the laptop and log in to DuetWebControl. No need to get mad over using WebControl in your smartphones 27 | browser. 28 | 29 | - Start, Stop, Pause & Resume print jobs based of Duets SD card 30 | - Simulate print jobs 31 | - Delete print jobs 32 | - Run macros (no dictionary support yet) 33 | - Home X, Y, Z or All axis 34 | - Set extruder fan speed 35 | - Load/Unload filament per tool 36 | - Set bed temperatures 37 | - Set tool temperatures 38 | - Monitor temperatures 39 | - Monitor print job: 40 | - Percent complete 41 | - Duration 42 | - Elapsed time (based of simulation, otherwise from file) 43 | - Job name 44 | - Current layer 45 | - Run manual and automated bed leveling 46 | - Automatic reconnection 47 | - Low latency 48 | - Screen Saver feature 49 | - Support for RRF 3.4+ Object Model 50 | 51 | 52 | [![First release of RepPanel](https://img.youtube.com/vi/FfghWz1Lrw4/0.jpg)](https://youtu.be/FfghWz1Lrw4) 53 | [![First test of RepPanel](https://img.youtube.com/vi/39FKTUVjrxc/0.jpg)](https://www.youtube.com/watch?v=39FKTUVjrxc) 54 | 55 | ## What this project is not 56 | A full replacement for the DuetWebControl interface. 57 | 58 | ## Supported Hardware/Software 59 | The RepPanel project is based on the [LVGL port for the ESP32](https://github.com/lvgl/lv_port_esp32/tree/c1f43bfb090df293059ab52baabbdbdd8df00712). 60 | In theory this means all displays and touch controllers supported by the **lv_port_esp32** project are also supported 61 | by RepPanel. 62 | 63 | ### Tested Hardware 64 | The listed hardware below is tested and pre-compiled images are available under GitHub releases. 65 | 66 | #### Hardware v1 (HWv1) platform 67 | - ESP32 DevKit without external RAM 68 | - [ER-TFTM035-6 display with capacitive touch screen, 4-Wire SPI, No font chip required](https://www.buydisplay.com/lcd-3-5-inch-320x480-tft-display-module-optl-touch-screen-w-breakout-board) 69 | 70 | 71 | **Beware:** There are numerous version of the ER-TFT035-6. You must choose the one with the SPI interface. Do not get the arduino shield version (no SPI config). The version with the screen breakout board is sufficient.** 72 | Other display modules with a resolution of 480x320 should also work as long as they are supported by `lv_port_esp32` 73 | As of now RepPanel is optimized for 3.5" displays with a resolution of 480x320 pixels. The display is connected via SPI. 74 | 75 | #### Hardware v2 (HWv2) platform 76 | - coming soon 77 | 78 | ### Differences between HWv1 & HWv2 79 | coming soon 80 | 81 | **Tested Firmware** 82 | - Duet2 WiFi running RepRap Firmware v3.0, v3.1, v3.2, v3.3 and corresponding Duet2WebControl 83 | - Duet3D + SBC is not supported via Wifi - only via the PanelDue serial port (wired connection) 84 | 85 | ## Installation 86 | Use ready made images or compile yourself. 87 | 88 | ### Compile yourself 89 | 90 | #### Set up ESP-IDF 91 | 92 | [Follow instructions](https://docs.espressif.com/projects/esp-idf/en/v4.0/get-started/index.html#step-1-install-prerequisites) on offical Espressif site. 93 | ESP-IDF v4.0 is officially supported. ESP-IDF v4.3 is officially supported for the HWv2 electronics platform. 94 | 95 | #### Clone Project 96 | 97 | ```bash 98 | git clone --recurse-submodules https://github.com/seeul8er/RepPanel_ESP32 99 | ``` 100 | LVGL v7 is not supported. Last tested release of `lv_port_esp32` is commit `a76a3d5d9225d0cfb92c896b6b0f1867b62aa2b6`. 101 | The project is linked against a fork to keep the legacy support and be able to fix bugs. 102 | 103 | #### Configure Project 104 | 105 | From its root run: 106 | ```bash 107 | idf.py menuconfig 108 | ``` 109 | Under ``Component configuration`` you can change the supported TFT and Touchcontroller configuration and RepPanel 110 | specific settings. 111 | 112 | **See [Custom LVGL port for the ESP32](https://github.com/seeul8er/lv_port_esp32/tree/c1f43bfb090df293059ab52baabbdbdd8df00712) for further and more detailed instructions.** 113 | 114 | #### Compile & Flash 115 | ```bash 116 | idf.py build 117 | idf.py -p (YOUR PORT) flash 118 | ``` 119 | **See [LVGL port for the ESP32](https://github.com/lvgl/lv_port_esp32/tree/c1f43bfb090df293059ab52baabbdbdd8df00712) for further and more detailed instructions.** 120 | 121 | ### Use ready made images 122 | Ready made images are only available for selected hardware combinations! Please compile the project by yourself in 123 | case you use different hardware or want a different pin connection layout 124 | 125 | Check out [releases](https://github.com/seeul8er/RepPanel_ESP32/releases) for compiled binaries. 126 | 127 | ### Wiring ER-TFTM035-6 to the ESP32 DevKit (HWv1) 128 | 129 | **Beware:** The available development boards have different pin configurations. Some have GND & 3.3V at the bottom. Others at the top. 130 | 131 | Pin configuration of ready made images: 132 | | **Pin Number ESP32 ** | **Pin Number ER-TFTM035-6** | **Function** | **Description** | 133 | |:--------------:|:--:|:------------: |:-------------------------: | 134 | | VCC 3.3V | 2 | Power supply | Match TFT voltage with ESP32 pin | 135 | | GND | 1 | GND | Ground | 136 | | GPIO 13 | 27 | MOSI | Data line to TFT | 137 | | GPIO 14 | 24 | SCL | SPI CLK for TFT | 138 | | GPIO 15 | 23 | Slave Select | SPI | 139 | | GPIO 22 | 30 | SCL | I²C - touch | 140 | | GPIO 21 | 31 | SDA | I²C - touch | 141 | | GPIO 4 | 21 | Reset | TFT related | 142 | | GPIO 2 | 25 | Data | TFT related | 143 | | GPIO 27 | 29 | Backlight | Turn on/off TFT backlight | 144 | | GPIO 17 | - | UART TX | Connect to RX PanelDue port | 145 | | GPIO 16 | - | UART RX | Connect to TX PanelDue port | 146 | 147 | ## Screenshots 148 | ![RepPanel with case](wiki/RepPanel_with_case.png) 149 | ![RepPanel print job status](wiki/RepPanel_JobStatus.png) 150 | ![RepPanel process menu](wiki/RepPanel_Process.png) 151 | ![RepPanel console](wiki/RepPanel_Console.png) 152 | ![RepPanel start print dialog](wiki/RepPanel_Job.png) 153 | 154 | ## For Developers 155 | [Check out the simulator project.](https://github.com/seeul8er/RepPanel_sim) Simulates the RepPanel GUI on Desktop computers for more efficient testing and implementation. 156 | 157 | Use the provided for of lvgl for ESP32. This one contains the supported version of LVGL with some additional config options regarding the screen saver timeout. It is the only one maintained for RepPanel. 158 | 159 | **Custom changes to lv_conf.h** 160 | Copy file content of `main/lv_conf_back.h` over to `externals/lv_port_esp32/components/lvgl/lv_conf.h`. 161 | Or simply add: 162 | - Set `LV_USE_USER_DATA 1` 163 | - Set `LV_MEM_SIZE (17U * 1024U)` to free up unused RAM 164 | - Add `#define LV_USE_THEME_REP_PANEL_DARK 1` 165 | - `CONFIG_LVGL_FONT_ROBOTO16` & `CONFIG_LVGL_FONT_ROBOTO22` must be activated 166 | - Add 167 | ```C 168 | #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(reppanel_font_roboto_bold_16) \ 169 | LV_FONT_DECLARE(reppanel_font_roboto_bold_18) \ 170 | LV_FONT_DECLARE(reppanel_font_roboto_bold_24) \ 171 | LV_FONT_DECLARE(reppanel_font_roboto_regular_26) \ 172 | LV_FONT_DECLARE(reppanel_font_roboto_light_26) \ 173 | LV_FONT_DECLARE(reppanel_font_roboto_thin_numeric_160) \ 174 | LV_FONT_DECLARE(reppanel_font_roboto_regular_percent_40) 175 | ``` 176 | 177 | **Compilation options for different hardware platforms** 178 | - esp-idf 4.0.x for ER-TFTM035-6 and other ILI9488 based displays (later esp-idf versions cause rendering artifacts) 179 | - esp-idf 4.0.x or 4.3.x for ST7796s based displays 180 | 181 | ## Known Limitations 182 | - Multiple tools supported but not tested 183 | - Auto swap from UART to WiFi connection might take up to 10s 184 | - Entries per directory listing limited to 24 for jobs and macros for ESP32 modules without external RAM 185 | - Directory path limited to 160 characters for ESP32 modules without external RAM 186 | - Filament listing (all filament names separated by one character) limited to 1014 187 | - No support for Duet3 + SBC via Wifi because of a different API 188 | - Workaround: Use wired UART/PanelDue connection 189 | - Can not list all files within a directory in case DuetWebControl API requires multiple requests per listing 190 | - Workaround: Delete files to reduce file count to make all files fit within one response 191 | -------------------------------------------------------------------------------- /main/fonts/reppanel_font_roboto_regular_percent_40.c: -------------------------------------------------------------------------------- 1 | #include "lvgl/lvgl.h" 2 | 3 | /******************************************************************************* 4 | * Size: 40 px 5 | * Bpp: 4 6 | * Opts: 7 | ******************************************************************************/ 8 | 9 | #ifndef REPPANEL_FONT_ROBOTO_REGULAR_PERCENT_40 10 | #define REPPANEL_FONT_ROBOTO_REGULAR_PERCENT_40 1 11 | #endif 12 | 13 | #if REPPANEL_FONT_ROBOTO_REGULAR_PERCENT_40 14 | 15 | /*----------------- 16 | * BITMAPS 17 | *----------------*/ 18 | 19 | /*Store the image of the glyphs*/ 20 | static LV_ATTRIBUTE_LARGE_CONST const uint8_t gylph_bitmap[] = { 21 | /* U+25 "%" */ 22 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x69, 0xac, 23 | 0xde, 0xff, 0xff, 0xfe, 0xdc, 0xb9, 0x74, 0x20, 24 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 25 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 26 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 27 | 0x0, 0x0, 0x0, 0x1, 0x48, 0xcf, 0xff, 0xff, 28 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 29 | 0xd9, 0x51, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 30 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 31 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 32 | 0x0, 0x0, 0x0, 0x26, 0xbf, 0xff, 0xff, 0xff, 33 | 0xfd, 0xb9, 0x87, 0x77, 0x89, 0xbd, 0xff, 0xff, 34 | 0xff, 0xff, 0xc7, 0x20, 0x0, 0x0, 0x0, 0x0, 35 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 36 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 37 | 0x0, 0x0, 0x0, 0x49, 0xef, 0xff, 0xff, 0xfc, 38 | 0x73, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x6b, 39 | 0xff, 0xff, 0xff, 0xfa, 0x40, 0x0, 0x0, 0x0, 40 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x58, 0xa8, 41 | 0x52, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 42 | 0x0, 0x0, 0x0, 0x28, 0xdf, 0xff, 0xff, 0xe9, 43 | 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 44 | 0x38, 0xdf, 0xff, 0xff, 0xe9, 0x30, 0x0, 0x0, 45 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0xae, 0xff, 46 | 0xff, 0xfb, 0x61, 0x0, 0x0, 0x0, 0x0, 0x0, 47 | 0x0, 0x0, 0x0, 0x4, 0x9f, 0xff, 0xff, 0xfc, 48 | 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 49 | 0x0, 0x5b, 0xff, 0xff, 0xff, 0xa5, 0x0, 0x0, 50 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0xef, 0xff, 51 | 0xff, 0xd8, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 52 | 0x0, 0x0, 0x0, 0x0, 0x49, 0xff, 0xff, 0xff, 53 | 0xc6, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 54 | 0x0, 0x5, 0xaf, 0xff, 0xff, 0xfa, 0x50, 0x0, 55 | 0x0, 0x0, 0x0, 0x0, 0x3, 0x9d, 0xff, 0xff, 56 | 0xfd, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 57 | 0x0, 0x0, 0x0, 0x0, 0x3, 0x9e, 0xff, 0xff, 58 | 0xfd, 0x82, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 59 | 0x0, 0x1, 0x7c, 0xff, 0xff, 0xff, 0xa4, 0x0, 60 | 0x0, 0x0, 0x0, 0x0, 0x38, 0xdf, 0xff, 0xff, 61 | 0xe9, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 62 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xbf, 0xff, 63 | 0xff, 0xfd, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 64 | 0x0, 0x2, 0x7c, 0xff, 0xff, 0xff, 0xc7, 0x20, 65 | 0x0, 0x0, 0x0, 0x2, 0x8c, 0xff, 0xff, 0xfe, 66 | 0xa4, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 67 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0xae, 68 | 0xff, 0xff, 0xff, 0xeb, 0x85, 0x31, 0x10, 0x1, 69 | 0x24, 0x6a, 0xdf, 0xff, 0xff, 0xff, 0xb6, 0x10, 70 | 0x0, 0x0, 0x0, 0x27, 0xcf, 0xff, 0xff, 0xea, 71 | 0x51, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 72 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 73 | 0x49, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 74 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xeb, 0x62, 0x0, 75 | 0x0, 0x0, 0x2, 0x6c, 0xff, 0xff, 0xff, 0xb6, 76 | 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 77 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 78 | 0x0, 0x1, 0x37, 0xac, 0xef, 0xff, 0xff, 0xff, 79 | 0xff, 0xff, 0xff, 0xfd, 0xb8, 0x41, 0x0, 0x0, 80 | 0x0, 0x0, 0x16, 0xbf, 0xff, 0xff, 0xfc, 0x62, 81 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 82 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 83 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x34, 0x55, 84 | 0x55, 0x55, 0x43, 0x10, 0x0, 0x0, 0x0, 0x0, 85 | 0x0, 0x1, 0x5a, 0xef, 0xff, 0xff, 0xc7, 0x20, 86 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 87 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 88 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 89 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 90 | 0x0, 0x15, 0xae, 0xff, 0xff, 0xfd, 0x82, 0x0, 91 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 92 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 93 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 94 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 95 | 0x0, 0x49, 0xef, 0xff, 0xff, 0xd8, 0x30, 0x0, 96 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 97 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 98 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 99 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 100 | 0x4, 0x9e, 0xff, 0xff, 0xfd, 0x94, 0x0, 0x0, 101 | 0x0, 0x0, 0x0, 0x1, 0x34, 0x55, 0x66, 0x55, 102 | 0x43, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 103 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 104 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 105 | 0x38, 0xdf, 0xff, 0xff, 0xea, 0x40, 0x0, 0x0, 106 | 0x0, 0x14, 0x7b, 0xdf, 0xff, 0xff, 0xff, 0xff, 107 | 0xff, 0xff, 0xfe, 0xc9, 0x52, 0x0, 0x0, 0x0, 108 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 109 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 110 | 0x8d, 0xff, 0xff, 0xfe, 0xa5, 0x10, 0x0, 0x0, 111 | 0x15, 0xae, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 112 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x62, 0x0, 113 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 114 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x27, 115 | 0xcf, 0xff, 0xff, 0xeb, 0x61, 0x0, 0x0, 0x1, 116 | 0x5a, 0xff, 0xff, 0xff, 0xfe, 0xb7, 0x42, 0x10, 117 | 0x1, 0x23, 0x69, 0xdf, 0xff, 0xff, 0xff, 0xc7, 118 | 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 119 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x7c, 120 | 0xff, 0xff, 0xff, 0xb6, 0x10, 0x0, 0x0, 0x1, 121 | 0x7c, 0xff, 0xff, 0xff, 0xd7, 0x20, 0x0, 0x0, 122 | 0x0, 0x0, 0x0, 0x1, 0x6b, 0xff, 0xff, 0xff, 123 | 0xe8, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 124 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26, 0xbf, 125 | 0xff, 0xff, 0xfc, 0x72, 0x0, 0x0, 0x0, 0x0, 126 | 0x5a, 0xff, 0xff, 0xff, 0xc6, 0x10, 0x0, 0x0, 127 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x5a, 0xff, 0xff, 128 | 0xff, 0xc7, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 129 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x5b, 0xff, 130 | 0xff, 0xff, 0xc7, 0x20, 0x0, 0x0, 0x0, 0x0, 131 | 0x16, 0xcf, 0xff, 0xff, 0xf9, 0x40, 0x0, 0x0, 132 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x8d, 0xff, 133 | 0xff, 0xfd, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 134 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0xae, 0xff, 135 | 0xff, 0xfd, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 136 | 0x1, 0x6c, 0xff, 0xff, 0xfe, 0x94, 0x0, 0x0, 137 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x27, 0xdf, 138 | 0xff, 0xff, 0xe9, 0x30, 0x0, 0x0, 0x0, 0x0, 139 | 0x0, 0x0, 0x0, 0x0, 0x1, 0x4a, 0xef, 0xff, 140 | 0xff, 0xd9, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 141 | 0x0, 0x6, 0xbf, 0xff, 0xff, 0xfa, 0x50, 0x0, 142 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x8e, 143 | 0xff, 0xff, 0xfd, 0x83, 0x0, 0x0, 0x0, 0x0, 144 | 0x0, 0x0, 0x0, 0x0, 0x4, 0x9e, 0xff, 0xff, 145 | 0xfe, 0x94, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 146 | 0x0, 0x0, 0x49, 0xef, 0xff, 0xff, 0xd8, 0x30, 147 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x6c, 148 | 0xff, 0xff, 0xff, 0xb6, 0x10, 0x0, 0x0, 0x0, 149 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x9d, 0xff, 150 | 0xea, 0x41, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 151 | 0x0, 0x0, 0x0, 0x49, 0xef, 0xff, 0xff, 0xfb, 152 | 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0xae, 153 | 0xff, 0xff, 0xff, 0xc6, 0x10, 0x0, 0x0, 0x0, 154 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 155 | 0x32, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 156 | 0x0, 0x0, 0x0, 0x0, 0x26, 0xcf, 0xff, 0xff, 157 | 0xff, 0xfd, 0xa9, 0x87, 0x77, 0x89, 0xce, 0xff, 158 | 0xff, 0xff, 0xfd, 0x83, 0x0, 0x0, 0x0, 0x0, 159 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 160 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 161 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x49, 0xdf, 162 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 163 | 0xff, 0xfd, 0xa6, 0x20, 0x0, 0x0, 0x0, 0x0, 164 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 165 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 166 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 167 | 0x24, 0x79, 0xbc, 0xde, 0xff, 0xff, 0xfe, 0xdb, 168 | 0xa8, 0x52, 0x10, 0x0, 0x0, 0x0, 0x0 169 | }; 170 | 171 | 172 | /*--------------------- 173 | * GLYPH DESCRIPTION 174 | *--------------------*/ 175 | 176 | static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { 177 | {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, 178 | {.bitmap_index = 0, .adv_w = 469, .box_w = 81, .box_h = 29, .ofs_x = 1, .ofs_y = 0} 179 | }; 180 | 181 | /*--------------------- 182 | * CHARACTER MAPPING 183 | *--------------------*/ 184 | 185 | 186 | 187 | /*Collect the unicode lists and glyph_id offsets*/ 188 | static const lv_font_fmt_txt_cmap_t cmaps[] = 189 | { 190 | { 191 | .range_start = 37, .range_length = 1, .glyph_id_start = 1, 192 | .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY 193 | } 194 | }; 195 | 196 | 197 | 198 | /*-------------------- 199 | * ALL CUSTOM DATA 200 | *--------------------*/ 201 | 202 | /*Store all the custom data of the font*/ 203 | static lv_font_fmt_txt_dsc_t font_dsc = { 204 | .glyph_bitmap = gylph_bitmap, 205 | .glyph_dsc = glyph_dsc, 206 | .cmaps = cmaps, 207 | .kern_dsc = NULL, 208 | .kern_scale = 0, 209 | .cmap_num = 1, 210 | .bpp = 4, 211 | .kern_classes = 0, 212 | .bitmap_format = 0 213 | }; 214 | 215 | 216 | /*----------------- 217 | * PUBLIC FONT 218 | *----------------*/ 219 | 220 | /*Initialize a public general font descriptor*/ 221 | lv_font_t reppanel_font_roboto_regular_percent_40 = { 222 | .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ 223 | .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ 224 | .line_height = 29, /*The maximum line height required by the font*/ 225 | .base_line = 0, /*Baseline measured from the bottom of the line*/ 226 | #if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) 227 | .subpx = LV_FONT_SUBPX_HOR, 228 | #endif 229 | .dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ 230 | }; 231 | 232 | #endif /*#if REPPANEL_FONT_ROBOTO_REGULAR_PERCENT_40*/ 233 | 234 | -------------------------------------------------------------------------------- /main/reppanel_jobselect.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "reppanel.h" 11 | #include "reppanel_request.h" 12 | #include "rrf_objects.h" 13 | 14 | #define TAG "JobSelect" 15 | #define CANCEL_BTN_TXT "#ffffff Cancel#" 16 | #define DELETE_BTN_TXT "#c43145 "LV_SYMBOL_TRASH" Delete#" 17 | #define SIM_BTN_TXT LV_SYMBOL_EYE_OPEN" Simulate" 18 | #define PRINT_BTN_TXT REP_PANEL_DARK_ACCENT_STR " " LV_SYMBOL_PLAY" Print#" 19 | 20 | #define JOBS_ROOT_DIR "0:/gcodes" 21 | #define JOBS_EMPTY "" 22 | #define BACK_TXT "Back" 23 | 24 | lv_obj_t *jobs_list; 25 | lv_obj_t *msg_box1; // file info msg box 26 | lv_obj_t *msg_box2; // delete confirmation message box 27 | lv_obj_t *msg_box3; // print confirmation message box 28 | lv_obj_t *preloader; 29 | 30 | char parent_dir_jobs[MAX_LEN_DIRNAME + 1]; 31 | file_tree_elem_t *edit_job; 32 | 33 | void send_print_command() { 34 | ESP_LOGI(TAG, "Printing %s", edit_job->name); 35 | char tmp_txt[strlen(edit_job->dir) + strlen(edit_job->name) + 10]; 36 | sprintf(tmp_txt, "M32 \"%s/%s\"", edit_job->dir, edit_job->name); 37 | reprap_send_gcode(tmp_txt); 38 | } 39 | 40 | static void print_file_handler(lv_obj_t *obj, lv_event_t event) { 41 | if (event == LV_EVENT_VALUE_CHANGED) { 42 | if (strcmp(lv_mbox_get_active_btn_text(msg_box3), "Yes") == 0) { 43 | send_print_command(); 44 | lv_obj_del_async(msg_box3); 45 | display_jobstatus(); 46 | } else { 47 | lv_obj_del_async(msg_box3); 48 | } 49 | } 50 | } 51 | 52 | static void delete_file_handler(lv_obj_t *obj, lv_event_t event) { 53 | if (event == LV_EVENT_VALUE_CHANGED) { 54 | if (strcmp(lv_mbox_get_active_btn_text(msg_box2), "Yes") == 0) { 55 | ESP_LOGI(TAG, "Deleting %s", edit_job->name); 56 | char tmp_txt[strlen(edit_job->dir) + strlen(edit_job->name) + 10]; 57 | sprintf(tmp_txt, "M30 \"%s/%s\"", edit_job->dir, edit_job->name); 58 | reprap_send_gcode(tmp_txt); 59 | lv_obj_del_async(msg_box2); 60 | lv_obj_del_async(msg_box1); 61 | request_jobs(edit_job->dir); 62 | } else { 63 | lv_obj_del_async(msg_box2); 64 | } 65 | } 66 | } 67 | 68 | static void job_action_handler(lv_obj_t *obj, lv_event_t event) { 69 | if (event == LV_EVENT_VALUE_CHANGED) { 70 | if (strcmp(lv_mbox_get_active_btn_text(msg_box1), CANCEL_BTN_TXT) == 0) { 71 | ESP_LOGI(TAG, "Close window. No action"); 72 | lv_obj_del_async(msg_box1); 73 | } else if (strcmp(lv_mbox_get_active_btn_text(msg_box1), DELETE_BTN_TXT) == 0) { 74 | static const char *btns[] = {"Yes", "No", ""}; 75 | msg_box2 = lv_mbox_create(lv_layer_top(), NULL); 76 | lv_mbox_set_text(msg_box2, "Do you really want to delete this file?"); 77 | lv_mbox_add_btns(msg_box2, btns); 78 | lv_obj_set_event_cb(msg_box2, delete_file_handler); 79 | lv_obj_set_width(msg_box2, lv_disp_get_hor_res(NULL) - 20); 80 | lv_obj_align(msg_box2, lv_layer_top(), LV_ALIGN_CENTER, 0, 0); 81 | } else if (strcmp(lv_mbox_get_active_btn_text(msg_box1), PRINT_BTN_TXT) == 0) { 82 | send_print_command(); 83 | lv_obj_del_async(msg_box1); 84 | display_jobstatus(); 85 | } else if (strcmp(lv_mbox_get_active_btn_text(msg_box1), SIM_BTN_TXT) == 0) { 86 | ESP_LOGI(TAG, "Simulate %s", edit_job->name); 87 | char tmp_txt[strlen(edit_job->dir) + strlen(edit_job->name) + 10]; 88 | sprintf(tmp_txt, "M37 P\"%s/%s\"", edit_job->dir, edit_job->name); 89 | reprap_send_gcode(tmp_txt); 90 | lv_obj_del_async(msg_box1); 91 | display_jobstatus(); 92 | } 93 | } 94 | } 95 | 96 | void update_file_info_dialog_ui(reprap_model_t *_reprap_model) { 97 | if (!msg_box1) return; 98 | int print_time_h = (int) (_reprap_model->reprap_job.file.printTime / (60 * 60)); 99 | int print_time_min = (int) ((_reprap_model->reprap_job.file.printTime - (print_time_h * 60 * 60)) / 60); 100 | 101 | int sim_time_h = 0, sim_time_min = 0; 102 | ESP_LOGI(TAG, "Simulated time %i", _reprap_model->reprap_job.file.simulatedTime); 103 | if (_reprap_model->reprap_job.file.simulatedTime > 0) { 104 | sim_time_h = (int) (_reprap_model->reprap_job.file.simulatedTime / (60 * 60)); 105 | sim_time_min = (int) ((_reprap_model->reprap_job.file.simulatedTime - (sim_time_h * 60 * 60)) / 60); 106 | } 107 | static char mbox_txt[128]; 108 | sprintf(mbox_txt, "Print time: %ih %imin\n" 109 | "Simulated time: %ih %imin\n" 110 | "Height: %.2fmm\n" 111 | "Filament usage: %.2fmm", 112 | print_time_h, print_time_min, sim_time_h, sim_time_min, _reprap_model->reprap_job.file.height, 113 | _reprap_model->reprap_job.file.overall_filament_usage); 114 | ESP_LOGI(TAG, "Updating file info dialog"); 115 | lv_mbox_set_text(msg_box1, mbox_txt); 116 | } 117 | 118 | static void job_clicked_event_handler(lv_obj_t *obj, lv_event_t event) { 119 | int selected_indx = lv_list_get_btn_index(jobs_list, obj); 120 | // check if back button exists 121 | if (strcmp(reprap_dir_elem[0].dir, JOBS_ROOT_DIR) != 0) { 122 | if (selected_indx == 0 && event == LV_EVENT_SHORT_CLICKED) { 123 | // back button was pressed 124 | ESP_LOGI(TAG, "Going back to parent %s", parent_dir_jobs); 125 | if (!preloader) 126 | preloader = lv_preload_create(lv_layer_top(), NULL); 127 | lv_obj_set_size(preloader, 75, 75); 128 | lv_obj_align_origo(preloader, lv_layer_top(), LV_ALIGN_CENTER, 0, 0); 129 | request_jobs(parent_dir_jobs); 130 | return; 131 | } else if (selected_indx != 0) { 132 | // no back button pressed 133 | // decrease index to match with reprap_macros array indexing 134 | selected_indx--; 135 | } 136 | } 137 | edit_job = &reprap_dir_elem[selected_indx]; 138 | if (event == LV_EVENT_SHORT_CLICKED) { 139 | if (reprap_dir_elem[selected_indx].type == TREE_FILE_ELEM) { 140 | static const char *btns[] = {"Yes", "No", ""}; 141 | msg_box3 = lv_mbox_create(lv_layer_top(), NULL); 142 | char msg[strlen(edit_job->name) + 23]; 143 | sprintf(msg, "Do you want to print %s?", edit_job->name); 144 | lv_mbox_set_text(msg_box3, msg); 145 | lv_mbox_add_btns(msg_box3, btns); 146 | lv_obj_set_event_cb(msg_box3, print_file_handler); 147 | lv_obj_set_width(msg_box3, lv_disp_get_hor_res(NULL) - 20); 148 | lv_obj_align(msg_box3, lv_layer_top(), LV_ALIGN_CENTER, 0, 0); 149 | } else if (reprap_dir_elem[selected_indx].type == TREE_FOLDER_ELEM) { 150 | ESP_LOGI(TAG, "Clicked folder %s (index %i)", edit_job->name, selected_indx); 151 | if (!preloader) 152 | preloader = lv_preload_create(lv_layer_top(), NULL); 153 | lv_obj_set_size(preloader, 75, 75); 154 | lv_obj_align_origo(preloader, lv_layer_top(), LV_ALIGN_CENTER, 0, 0); 155 | static char tmp_txt_job_path[MAX_LEN_DIRNAME + MAX_LEN_FILENAME + 1]; 156 | sprintf(tmp_txt_job_path, "%s/%s", reprap_dir_elem[selected_indx].dir, edit_job->name); 157 | request_jobs(tmp_txt_job_path); 158 | } else { 159 | ESP_LOGW(TAG, "Selected unknown file tree element -> Index: %i - Type: %i - Name: %s - Dir: %s", selected_indx, 160 | reprap_dir_elem[selected_indx].type, reprap_dir_elem[selected_indx].name, reprap_dir_elem[selected_indx].dir); 161 | } 162 | } else if (event == LV_EVENT_LONG_PRESSED && reprap_dir_elem[selected_indx].type == TREE_FILE_ELEM) { // file info dialog 163 | // request file info 164 | char tmp_txt[strlen(edit_job->dir) + strlen(edit_job->name) + 2]; 165 | sprintf(tmp_txt, "%s/%s", edit_job->dir, edit_job->name); 166 | trigger_request_fileinfo(tmp_txt); 167 | // build UI 168 | static const char *btns[] = {SIM_BTN_TXT, PRINT_BTN_TXT, DELETE_BTN_TXT, CANCEL_BTN_TXT, ""}; 169 | msg_box1 = lv_mbox_create(lv_layer_top(), NULL); 170 | lv_mbox_set_text(msg_box1, "Loading Job Information..."); 171 | lv_mbox_add_btns(msg_box1, btns); 172 | lv_mbox_set_recolor(msg_box1, true); 173 | lv_obj_set_width(msg_box1, lv_disp_get_hor_res(NULL) - 15); 174 | lv_obj_set_event_cb(msg_box1, job_action_handler); 175 | lv_obj_align(msg_box1, lv_layer_top(), LV_ALIGN_IN_TOP_MID, 0, 50); 176 | } 177 | } 178 | 179 | void update_job_list_ui() { 180 | if (visible_screen != REPPANEL_JOBSELECT_SCREEN) return; 181 | lv_obj_del(preloader); 182 | if (jobs_list) { 183 | lv_list_clean(jobs_list); 184 | } else { 185 | return; 186 | } 187 | 188 | // Add back button in case we are not in root directory 189 | if (strcmp(reprap_dir_elem[0].dir, JOBS_ROOT_DIR) != 0) { 190 | lv_obj_t *back_btn; 191 | back_btn = lv_list_add_btn(jobs_list, LV_SYMBOL_LEFT, BACK_TXT); 192 | lv_obj_set_event_cb(back_btn, job_clicked_event_handler); 193 | // update parent dir 194 | strcpy(parent_dir_jobs, reprap_dir_elem[0].dir); 195 | char *pch; 196 | pch = strrchr(parent_dir_jobs, '/'); 197 | parent_dir_jobs[pch - parent_dir_jobs] = '\0'; 198 | } else { 199 | strcpy(parent_dir_jobs, JOBS_EMPTY); 200 | } 201 | // count number of elements 202 | uint8_t cnt = 0; 203 | for (int i = 0; reprap_dir_elem[i].type != TREE_EMPTY_ELEM && i < MAX_NUM_ELEM_DIR; i++) { 204 | cnt++; 205 | } 206 | // sort by modification date 207 | qsort(reprap_dir_elem, cnt, sizeof(file_tree_elem_t), compare_tree_element_timestamp); 208 | for (int i = 0; reprap_dir_elem[i].type != TREE_EMPTY_ELEM && i < MAX_NUM_ELEM_DIR; i++) { 209 | lv_obj_t *list_btn; 210 | if (reprap_dir_elem[i].type == TREE_FOLDER_ELEM) 211 | list_btn = lv_list_add_btn(jobs_list, LV_SYMBOL_DIRECTORY, reprap_dir_elem[i].name); 212 | else 213 | list_btn = lv_list_add_btn(jobs_list, LV_SYMBOL_FILE, reprap_dir_elem[i].name); 214 | lv_obj_set_event_cb(list_btn, job_clicked_event_handler); 215 | } 216 | } 217 | 218 | 219 | void draw_jobselect(lv_obj_t *parent_screen) { 220 | lv_obj_t *jobs_container = lv_cont_create(parent_screen, NULL); 221 | lv_cont_set_layout(jobs_container, LV_LAYOUT_COL_M); 222 | lv_cont_set_fit(jobs_container, LV_FIT_FILL); 223 | 224 | preloader = lv_preload_create(jobs_container, NULL); 225 | lv_obj_set_size(preloader, 75, 75); 226 | 227 | jobs_list = lv_list_create(jobs_container, NULL); 228 | lv_obj_set_size(jobs_list, LV_HOR_RES - 10, lv_disp_get_ver_res(NULL) - (lv_obj_get_height(cont_header) + 5)); 229 | 230 | request_jobs(JOBS_ROOT_DIR); 231 | } -------------------------------------------------------------------------------- /main/reppanel_info.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "reppanel_info.h" 11 | #include "reppanel.h" 12 | #include "esp32_wifi.h" 13 | 14 | #define TAG "RepPanelInfo" 15 | 16 | lv_obj_t *info_page; 17 | lv_obj_t *ta_wifi_pass; 18 | lv_obj_t *ta_ssid; 19 | lv_obj_t *ta_printer_addr; 20 | lv_obj_t *ta_reprap_pass; 21 | static lv_obj_t *cont_overlay, *cont_overlay_duet_addr; 22 | static lv_obj_t *ddl_ssid, *ddl_duets; 23 | 24 | static lv_obj_t *kb; 25 | 26 | static void save_reppanel_settings_event(lv_obj_t *obj, lv_event_t event) { 27 | if (event == LV_EVENT_CLICKED) { 28 | ESP_LOGI(TAG, "Saving settings\n"); 29 | const char *ssid = lv_ta_get_text(ta_ssid); 30 | strlcpy(wifi_ssid, ssid, sizeof(wifi_ssid)); 31 | const char *tmp_wifi_pass = lv_ta_get_text(ta_wifi_pass); 32 | strlcpy(wifi_pass, tmp_wifi_pass, sizeof(wifi_pass)); 33 | 34 | const char *tmp_rep_addr = lv_ta_get_text(ta_printer_addr); 35 | if (strncmp(tmp_rep_addr, "http://", strlen("http")) == 0 || 36 | strncmp(tmp_rep_addr, "https://", strlen("https")) == 0) { 37 | strlcpy(rep_addr, tmp_rep_addr, sizeof(rep_addr)); 38 | } else { 39 | char temp_addr[128]; 40 | sprintf(temp_addr, "http://%s", tmp_rep_addr); 41 | strlcpy(rep_addr, temp_addr, sizeof(rep_addr)); 42 | } 43 | const char *tmp_rep_pass = lv_ta_get_text(ta_reprap_pass); 44 | strlcpy(rep_pass, tmp_rep_pass, sizeof(rep_pass)); 45 | write_settings_to_nvs(); 46 | reconnect_wifi(); 47 | } 48 | } 49 | 50 | static void kb_event_cb(lv_obj_t *event_kb, lv_event_t event) { 51 | /* Just call the regular event handler */ 52 | lv_kb_def_event_cb(event_kb, event); 53 | if (event == LV_EVENT_CANCEL) { 54 | lv_obj_del(kb); 55 | kb = NULL; 56 | } 57 | } 58 | 59 | static void ta_event_cb(lv_obj_t *ta, lv_event_t event) { 60 | if (event == LV_EVENT_CLICKED) { 61 | /* Focus on the clicked text area */ 62 | if (kb == NULL) { 63 | kb = lv_kb_create(info_page, NULL); 64 | lv_obj_set_pos(kb, 0, 0); 65 | lv_obj_set_size(kb, LV_HOR_RES - 30, 120); 66 | lv_kb_set_cursor_manage(kb, true); /* Automatically show/hide cursors on text areas */ 67 | lv_kb_set_ta(kb, ta); 68 | lv_obj_set_event_cb(kb, kb_event_cb); 69 | } else { 70 | lv_kb_set_ta(kb, ta); 71 | } 72 | } else if (event == LV_EVENT_INSERT) { 73 | const char *str = lv_event_get_data(); 74 | if (str[0] == '\n') { 75 | printf("Ready\n"); 76 | } 77 | } 78 | } 79 | 80 | static void set_ssid_event(lv_obj_t *obj, lv_event_t event) { 81 | if (event == LV_EVENT_CLICKED) { 82 | char buf[33]; 83 | lv_ddlist_get_selected_str(ddl_ssid, buf, sizeof(buf)); 84 | lv_ta_set_text(ta_ssid, buf); 85 | lv_obj_del(cont_overlay); 86 | } 87 | } 88 | 89 | static void cancel_ssid_event(lv_obj_t *obj, lv_event_t event) { 90 | if (event == LV_EVENT_CLICKED) { 91 | lv_obj_del(cont_overlay); 92 | } 93 | } 94 | 95 | static void scan_wifi_event(lv_obj_t *obj, lv_event_t event) { 96 | if (event == LV_EVENT_CLICKED) { 97 | char ssids[256]; 98 | ssids[0] = '\0'; 99 | get_avail_wifi_networks(ssids); 100 | 101 | cont_overlay = lv_cont_create(lv_layer_top(), NULL); 102 | static lv_style_t somestyle; 103 | lv_style_copy(&somestyle, lv_cont_get_style(cont_overlay, LV_CONT_STYLE_MAIN)); 104 | somestyle.body.border.width = 1; 105 | somestyle.body.border.color = REP_PANEL_DARK_ACCENT; 106 | somestyle.body.padding.left = LV_DPI / 6; 107 | somestyle.body.padding.right = LV_DPI / 6; 108 | somestyle.body.padding.top = LV_DPI / 12; 109 | somestyle.body.padding.bottom = LV_DPI / 12; 110 | somestyle.body.padding.inner = LV_DPI / 9; 111 | lv_cont_set_style(cont_overlay, LV_CONT_STYLE_MAIN, &somestyle); 112 | 113 | lv_cont_set_fit(cont_overlay, LV_FIT_TIGHT); 114 | lv_cont_set_layout(cont_overlay, LV_LAYOUT_PRETTY); 115 | lv_obj_align_origo(cont_overlay, NULL, LV_ALIGN_CENTER, 0, -100); 116 | 117 | lv_obj_t *l = lv_label_create(cont_overlay, NULL); 118 | lv_label_set_text(l, "Select SSID"); 119 | ddl_ssid = lv_ddlist_create(cont_overlay, NULL); 120 | lv_ddlist_set_sb_mode(ddl_ssid, LV_SB_MODE_AUTO); 121 | lv_ddlist_set_fix_height(ddl_ssid, LV_HOR_RES - 350); 122 | lv_ddlist_set_align(ddl_ssid, LV_LABEL_ALIGN_LEFT); 123 | lv_ddlist_set_options(ddl_ssid, ssids); 124 | static lv_obj_t *ok_buttn; 125 | create_button(cont_overlay, ok_buttn, "OK", set_ssid_event); 126 | static lv_obj_t *cancel_buttn; 127 | create_button(cont_overlay, cancel_buttn, "Cancel", cancel_ssid_event); 128 | } 129 | } 130 | 131 | static void set_duet_addr_event(lv_obj_t *obj, lv_event_t event) { 132 | if (event == LV_EVENT_CLICKED) { 133 | char buf[64]; 134 | lv_ddlist_get_selected_str(ddl_duets, buf, sizeof(buf)); 135 | lv_ta_set_text(ta_printer_addr, buf); 136 | lv_obj_del(cont_overlay_duet_addr); 137 | } 138 | } 139 | 140 | static void cancel_duet_addr_event(lv_obj_t *obj, lv_event_t event) { 141 | if (event == LV_EVENT_CLICKED) { 142 | lv_obj_del(cont_overlay_duet_addr); 143 | } 144 | } 145 | 146 | static void scan_duet_event(lv_obj_t *obj, lv_event_t event) { 147 | if (event == LV_EVENT_CLICKED) { 148 | char duets[128]; 149 | get_avail_duets(duets); 150 | 151 | cont_overlay_duet_addr = lv_cont_create(lv_layer_top(), NULL); 152 | static lv_style_t somestyle; 153 | lv_style_copy(&somestyle, lv_cont_get_style(cont_overlay_duet_addr, LV_CONT_STYLE_MAIN)); 154 | somestyle.body.border.width = 1; 155 | somestyle.body.border.color = REP_PANEL_DARK_ACCENT; 156 | somestyle.body.padding.left = LV_DPI / 6; 157 | somestyle.body.padding.right = LV_DPI / 6; 158 | somestyle.body.padding.top = LV_DPI / 12; 159 | somestyle.body.padding.bottom = LV_DPI / 12; 160 | somestyle.body.padding.inner = LV_DPI / 9; 161 | lv_cont_set_style(cont_overlay_duet_addr, LV_CONT_STYLE_MAIN, &somestyle); 162 | 163 | lv_cont_set_fit(cont_overlay_duet_addr, LV_FIT_TIGHT); 164 | lv_cont_set_layout(cont_overlay_duet_addr, LV_LAYOUT_PRETTY); 165 | lv_obj_align_origo(cont_overlay_duet_addr, NULL, LV_ALIGN_CENTER, 0, -100); 166 | 167 | lv_obj_t *l = lv_label_create(cont_overlay_duet_addr, NULL); 168 | lv_label_set_text(l, "Select Duet"); 169 | ddl_duets = lv_ddlist_create(cont_overlay_duet_addr, NULL); 170 | lv_ddlist_set_sb_mode(ddl_duets, LV_SB_MODE_AUTO); 171 | lv_ddlist_set_fix_height(ddl_duets, LV_HOR_RES - 350); 172 | lv_ddlist_set_align(ddl_duets, LV_LABEL_ALIGN_LEFT); 173 | lv_ddlist_set_options(ddl_duets, duets); 174 | static lv_obj_t *ok_buttn; 175 | create_button(cont_overlay_duet_addr, ok_buttn, "OK", set_duet_addr_event); 176 | static lv_obj_t *cancel_buttn; 177 | create_button(cont_overlay_duet_addr, cancel_buttn, "Cancel", cancel_duet_addr_event); 178 | } 179 | } 180 | 181 | void draw_info(lv_obj_t *parent_screen) { 182 | read_settings_nvs(); 183 | 184 | info_page = lv_page_create(parent_screen, NULL); 185 | lv_obj_set_size(info_page, lv_disp_get_hor_res(NULL), 186 | lv_disp_get_ver_res(NULL) - (lv_obj_get_height(cont_header) + 5)); 187 | lv_page_set_scrl_fit2(info_page, LV_FIT_TIGHT, LV_FIT_FILL); 188 | lv_page_set_scrl_layout(info_page, LV_LAYOUT_COL_L); 189 | 190 | lv_obj_t *label_about = lv_label_create(info_page, NULL); 191 | lv_label_set_recolor(label_about, true); 192 | lv_label_set_text_fmt(label_about, "%s RepPanel for ESP32# - v%s", REP_PANEL_DARK_ACCENT_ALT1_STR, 193 | get_version_string()); 194 | 195 | lv_obj_t *ssid_cnt = lv_cont_create(info_page, NULL); 196 | lv_cont_set_layout(ssid_cnt, LV_LAYOUT_ROW_M); 197 | lv_cont_set_fit(ssid_cnt, LV_FIT_TIGHT); 198 | lv_obj_t *label_ssid = lv_label_create(ssid_cnt, NULL); 199 | lv_label_set_text(label_ssid, "WiFi SSID:"); 200 | 201 | ta_ssid = lv_ta_create(ssid_cnt, NULL); 202 | lv_ta_set_pwd_mode(ta_ssid, false); 203 | lv_ta_set_cursor_type(ta_ssid, LV_CURSOR_LINE | LV_CURSOR_HIDDEN); 204 | lv_obj_set_width(ta_ssid, LV_HOR_RES - 250); 205 | lv_obj_set_height(ta_ssid, 25); 206 | lv_ta_set_text(ta_ssid, (const char *) wifi_ssid); 207 | lv_obj_set_event_cb(ta_ssid, ta_event_cb); 208 | lv_ta_set_one_line(ta_ssid, true); 209 | 210 | static lv_obj_t *scan_wifi_btn; 211 | create_button(ssid_cnt, scan_wifi_btn, LV_SYMBOL_REFRESH, scan_wifi_event); 212 | 213 | lv_obj_t *wifi_pass_cnt = lv_cont_create(info_page, ssid_cnt); 214 | lv_obj_t *label_wifi_pass = lv_label_create(wifi_pass_cnt, NULL); 215 | lv_label_set_text(label_wifi_pass, "WiFi password:"); 216 | 217 | ta_wifi_pass = lv_ta_create(wifi_pass_cnt, NULL); 218 | lv_ta_set_text(ta_wifi_pass, (const char *) wifi_pass); 219 | lv_ta_set_pwd_mode(ta_wifi_pass, true); 220 | lv_ta_set_one_line(ta_wifi_pass, true); 221 | lv_obj_set_width(ta_wifi_pass, LV_HOR_RES - 250); 222 | lv_obj_set_pos(ta_wifi_pass, 0, 0); 223 | lv_obj_set_event_cb(ta_wifi_pass, ta_event_cb); 224 | lv_ta_set_one_line(ta_wifi_pass, true); 225 | 226 | lv_obj_t *printer_addr_cnt = lv_cont_create(info_page, ssid_cnt); 227 | lv_obj_t *label_printer_addr = lv_label_create(printer_addr_cnt, NULL); 228 | lv_label_set_text(label_printer_addr, "Printer address:"); 229 | 230 | ta_printer_addr = lv_ta_create(printer_addr_cnt, NULL); 231 | lv_ta_set_pwd_mode(ta_printer_addr, false); 232 | lv_ta_set_cursor_type(ta_printer_addr, LV_CURSOR_LINE | LV_CURSOR_HIDDEN); 233 | lv_obj_set_width(ta_printer_addr, LV_HOR_RES - 300); 234 | lv_obj_set_height(ta_printer_addr, 25); 235 | lv_ta_set_text(ta_printer_addr, (const char *) rep_addr); 236 | lv_obj_set_event_cb(ta_printer_addr, ta_event_cb); 237 | lv_ta_set_one_line(ta_ssid, true); 238 | 239 | static lv_obj_t *scan_duet_btn; 240 | create_button(printer_addr_cnt, scan_duet_btn, LV_SYMBOL_REFRESH, scan_duet_event); 241 | 242 | lv_obj_t *reprap_pass_cnt = lv_cont_create(info_page, ssid_cnt); 243 | lv_obj_t *label_reprap_pass = lv_label_create(reprap_pass_cnt, NULL); 244 | lv_label_set_text(label_reprap_pass, "RepRap password:"); 245 | 246 | ta_reprap_pass = lv_ta_create(reprap_pass_cnt, NULL); 247 | lv_ta_set_text(ta_reprap_pass, (const char *) rep_pass); 248 | lv_ta_set_pwd_mode(ta_reprap_pass, true); 249 | lv_ta_set_one_line(ta_reprap_pass, true); 250 | lv_obj_set_width(ta_reprap_pass, LV_HOR_RES - 260); 251 | lv_obj_set_pos(ta_reprap_pass, 0, 0); 252 | lv_obj_set_event_cb(ta_reprap_pass, ta_event_cb); 253 | lv_ta_set_one_line(ta_reprap_pass, true); 254 | 255 | // label_sig_strength = lv_label_create(info_page, NULL); 256 | // lv_label_set_recolor(label_sig_strength, true); 257 | // lv_label_set_long_mode(label_sig_strength, LV_LABEL_LONG_BREAK); 258 | // lv_label_set_text_fmt(label_sig_strength, "RepRap signal: %s-124dBm# RepPanel signal: %s-125dBm#", 259 | // REP_PANEL_DARK_ACCENT_ALT2_STR, REP_PANEL_DARK_ACCENT_ALT2_STR); 260 | static lv_obj_t *save_bnt; 261 | create_button(info_page, save_bnt, "Save", save_reppanel_settings_event); 262 | 263 | 264 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "{}" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright {yyyy} {name of copyright owner} 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /main/esp32_wifi.c: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Wolfgang Christl 3 | // Licensed under Apache License, Version 2.0 - https://opensource.org/licenses/Apache-2.0 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "main.h" 11 | #include 12 | #include 13 | 14 | #include "esp32_settings.h" 15 | #include "reppanel.h" 16 | #include "rrf_objects.h" 17 | 18 | #define TAG "ESP32WiFi" 19 | #define MAXIMUM_RETRY_WIFI 5 20 | #define WIFI_CONNECTED_BIT BIT0 21 | #define WIFI_FAIL_BIT BIT1 22 | #define DEFAULT_SCAN_LIST_SIZE 10 23 | 24 | static EventGroupHandle_t s_wifi_event_group; 25 | static int s_retry_num = 0; 26 | 27 | int resolve_mdns_host(const char *host_name, char *result_ip) { 28 | ESP_LOGI(TAG, "Query A: %s", host_name); 29 | #if ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 3 30 | struct esp_ip4_addr addr; 31 | #else 32 | struct ip4_addr addr; 33 | #endif 34 | 35 | addr.addr = 0; 36 | esp_err_t err = mdns_query_a(host_name, 2000, &addr); 37 | if (err) { 38 | if (err == ESP_ERR_NOT_FOUND) { 39 | ESP_LOGI(TAG, "Host was not found!"); 40 | return 0; 41 | } 42 | ESP_LOGI(TAG, "Query failed: %s", esp_err_to_name(err)); 43 | return 0; 44 | } 45 | ESP_LOGI(TAG, IPSTR, IP2STR(&addr)); 46 | sprintf(result_ip, "http://"IPSTR, IP2STR(&addr)); 47 | return 1; 48 | } 49 | 50 | void mdns_print_results(mdns_result_t *results) { 51 | const char *if_str[] = {"STA", "AP", "ETH", "MAX"}; 52 | const char *ip_protocol_str[] = {"V4", "V6", "MAX"}; 53 | mdns_result_t *r = results; 54 | mdns_ip_addr_t *a = NULL; 55 | int i = 1, t; 56 | while (r) { 57 | printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]); 58 | if (r->instance_name) { 59 | printf(" PTR : %s\n", r->instance_name); 60 | } 61 | if (r->hostname) { 62 | printf(" SRV : %s.local:%u\n", r->hostname, r->port); 63 | } 64 | if (r->txt_count) { 65 | printf(" TXT : [%u] ", r->txt_count); 66 | for (t = 0; t < r->txt_count; t++) { 67 | printf("%s=%s; ", r->txt[t].key, r->txt[t].value); 68 | } 69 | printf("\n"); 70 | } 71 | a = r->addr; 72 | while (a) { 73 | if (a->addr.type == IPADDR_TYPE_V6) { 74 | printf(" AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6)); 75 | } else { 76 | printf(" A : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4))); 77 | } 78 | a = a->next; 79 | } 80 | r = r->next; 81 | } 82 | } 83 | 84 | void find_mdns_service(const char *service_name, const char *proto) { 85 | ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto); 86 | mdns_result_t *results = NULL; 87 | esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); 88 | if (err) { 89 | ESP_LOGE(TAG, "Query failed: %s", esp_err_to_name(err)); 90 | return; 91 | } 92 | if (!results) { 93 | ESP_LOGW(TAG, "No results found!"); 94 | return; 95 | } 96 | mdns_print_results(results); 97 | mdns_query_results_free(results); 98 | } 99 | 100 | static void start_mdns_service() { 101 | //initialize mDNS service 102 | esp_err_t err = mdns_init(); 103 | if (err) { 104 | ESP_LOGE(TAG, "MDNS Init failed: %d", err); 105 | return; 106 | } 107 | //set hostname 108 | ESP_ERROR_CHECK(mdns_hostname_set("RepPanel")); 109 | //set default instance 110 | char tmp[20]; 111 | sprintf(tmp, "RepPanel %s", get_version_string()); 112 | ESP_ERROR_CHECK(mdns_instance_name_set(tmp)); 113 | } 114 | 115 | static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { 116 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { 117 | esp_wifi_connect(); 118 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { 119 | if (s_retry_num < MAXIMUM_RETRY_WIFI) { 120 | if (rp_conn_stat != REPPANEL_UART_CONNECTED) 121 | rp_conn_stat = REPPANEL_WIFI_RECONNECTING; 122 | esp_wifi_connect(); 123 | xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT); 124 | s_retry_num++; 125 | ESP_LOGI(TAG, "Retry to connect to the AP"); 126 | } else { 127 | xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); 128 | } 129 | if (rp_conn_stat != REPPANEL_UART_CONNECTED) 130 | rp_conn_stat = REPPANEL_WIFI_DISCONNECTED; 131 | ESP_LOGI(TAG, "Connect to the AP fail"); 132 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { 133 | ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; 134 | ESP_LOGI(TAG, "got ip: "IPSTR, IP2STR(&event->ip_info.ip)); 135 | s_retry_num = 0; 136 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); 137 | if (rp_conn_stat != REPPANEL_UART_CONNECTED) 138 | rp_conn_stat = REPPANEL_WIFI_CONNECTED_DUET_DISCONNECTED; 139 | } 140 | if (xSemaphoreTake(xGuiSemaphore, (TickType_t) 10) == pdTRUE) { 141 | update_rep_panel_conn_status(); 142 | xSemaphoreGive(xGuiSemaphore); 143 | } 144 | } 145 | 146 | #if ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION_MINOR == 3 147 | void wifi_init_sta_4_3() { 148 | s_wifi_event_group = xEventGroupCreate(); 149 | ESP_ERROR_CHECK(esp_netif_init()); 150 | 151 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 152 | esp_netif_create_default_wifi_sta(); 153 | 154 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 155 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 156 | 157 | esp_event_handler_instance_t instance_any_id; 158 | esp_event_handler_instance_t instance_got_ip; 159 | ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, 160 | ESP_EVENT_ANY_ID, 161 | &wifi_event_handler, 162 | NULL, 163 | &instance_any_id)); 164 | ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, 165 | IP_EVENT_STA_GOT_IP, 166 | &wifi_event_handler, 167 | NULL, 168 | &instance_got_ip)); 169 | 170 | wifi_config_t wifi_config = { 171 | .sta = { 172 | .ssid = "", 173 | .password = "", 174 | .threshold.authmode = WIFI_AUTH_WPA2_PSK, 175 | 176 | .pmf_cfg = { 177 | .capable = true, 178 | .required = false 179 | }, 180 | }, 181 | }; 182 | memcpy(wifi_config.sta.ssid, wifi_ssid, MAX_SSID_LEN); 183 | memcpy(wifi_config.sta.password, wifi_pass, MAX_WIFI_PASS_LEN); 184 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); 185 | ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); 186 | ESP_ERROR_CHECK(esp_wifi_start() ); 187 | 188 | ESP_LOGI(TAG, "wifi_init_sta finished."); 189 | start_mdns_service(); 190 | } 191 | #else 192 | void wifi_init_sta() { 193 | s_wifi_event_group = xEventGroupCreate(); 194 | tcpip_adapter_init(); 195 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 196 | 197 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 198 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 199 | 200 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); 201 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL)); 202 | 203 | wifi_config_t wifi_config; 204 | memset(&wifi_config, 0, sizeof(wifi_config)); 205 | memcpy(wifi_config.sta.ssid, wifi_ssid, MAX_SSID_LEN); 206 | memcpy(wifi_config.sta.password, wifi_pass, MAX_WIFI_PASS_LEN); 207 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); 208 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); 209 | ESP_ERROR_CHECK(esp_wifi_start()); 210 | 211 | ESP_LOGI(TAG, "wifi_init_sta finished."); 212 | start_mdns_service(); 213 | } 214 | #endif 215 | 216 | /** 217 | * Call only when GUI semaphore is taken 218 | */ 219 | void reconnect_wifi() { 220 | rp_conn_stat = REPPANEL_WIFI_RECONNECTING; 221 | update_rep_panel_conn_status(); 222 | esp_wifi_disconnect(); 223 | ESP_LOGI(TAG, "Reconnecting to %s with password %s", wifi_ssid, wifi_pass); 224 | wifi_config_t wifi_config; 225 | memset(&wifi_config, 0, sizeof(wifi_config)); 226 | memcpy(wifi_config.sta.ssid, wifi_ssid, MAX_SSID_LEN); 227 | memcpy(wifi_config.sta.password, wifi_pass, MAX_WIFI_PASS_LEN); 228 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); 229 | esp_wifi_connect(); 230 | } 231 | 232 | void get_connection_info(char txt_buffer[200]) { 233 | wifi_ap_record_t ap_info; 234 | switch (rp_conn_stat) { 235 | default: 236 | case REPPANEL_WIFI_DISCONNECTED: 237 | case REPPANEL_NO_CONNECTION: 238 | strcpy(txt_buffer, "Not connected to network or UART"); 239 | break; 240 | case REPPANEL_UART_CONNECTED: 241 | sprintf(txt_buffer, "Connected via UART\nRRF API-Level %i", reprap_model.api_level); 242 | break; 243 | case REPPANEL_WIFI_CONNECTED_DUET_DISCONNECTED: 244 | memset(&ap_info, 0, sizeof(ap_info)); 245 | ESP_ERROR_CHECK(esp_wifi_sta_get_ap_info(&ap_info)); 246 | sprintf(txt_buffer, "Connected to %s\nSignal: %ddBm\nNo response from printer!", ap_info.ssid, 247 | ap_info.rssi); 248 | break; 249 | case REPPANEL_WIFI_CONNECTED: 250 | memset(&ap_info, 0, sizeof(ap_info)); 251 | ESP_ERROR_CHECK(esp_wifi_sta_get_ap_info(&ap_info)); 252 | sprintf(txt_buffer, "Connected to %s\nSignal: %ddBm\nRRF API-Level %i", ap_info.ssid, ap_info.rssi, reprap_model.api_level); 253 | break; 254 | case REPPANEL_WIFI_RECONNECTING: 255 | strcpy(txt_buffer, "Reconnecting"); 256 | } 257 | } 258 | 259 | /** 260 | * Scan for available WiFi networks. Returns a list of SSIDs separated by a line brake 261 | * @param aps Filled with SSIDs separated by line brake 262 | */ 263 | void get_avail_wifi_networks(char *aps) { 264 | uint16_t number = DEFAULT_SCAN_LIST_SIZE; 265 | wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE]; 266 | uint16_t ap_count = 0; 267 | memset(ap_info, 0, sizeof(ap_info)); 268 | 269 | wifi_scan_config_t scan_config; 270 | memset(&scan_config, 0, sizeof(scan_config)); 271 | scan_config.channel = 0; 272 | scan_config.scan_type = WIFI_SCAN_TYPE_ACTIVE; 273 | esp_err_t err = esp_wifi_scan_start(&scan_config, true); 274 | while (err != ESP_OK) { 275 | ESP_LOGW(TAG, "Error scanning for WiFi: %s", esp_err_to_name(err)); 276 | err = esp_wifi_scan_start(&scan_config, true); 277 | } 278 | ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info)); 279 | ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count)); 280 | ESP_LOGI(TAG, "Total APs scanned = %u", ap_count); 281 | if (ap_count > 0) { 282 | sprintf(aps, "%s", ap_info[0].ssid); 283 | } 284 | for (int i = 1; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++) { 285 | char tmp[50]; 286 | sprintf(tmp, "\n%s", ap_info[i].ssid); 287 | strcat(aps, tmp); 288 | } 289 | } 290 | 291 | /** 292 | * Scan for available mDNS devices. Format list so that it can be used by a ddlist. 293 | * @param txt_buffer Elements separated by new line character 294 | */ 295 | void get_avail_duets(char *txt_buffer) { 296 | txt_buffer[0] = '\0'; 297 | mdns_result_t *results = NULL; 298 | esp_err_t err = mdns_query_ptr("_http", "_tcp", 2000, 20, &results); 299 | if (err) { 300 | ESP_LOGE("mDNS Scanner", "Query failed: %s", esp_err_to_name(err)); 301 | return; 302 | } 303 | if (!results) { 304 | ESP_LOGW("mDNS Scanner", "No results found!"); 305 | return; 306 | } else { 307 | mdns_result_t *r = results; 308 | while (r) { 309 | if (r->hostname) { 310 | char tmp[32]; tmp[0] = '\0'; 311 | sprintf(tmp, "%s.local\n", &r->hostname[0]); 312 | strcat(txt_buffer, tmp); 313 | } 314 | r = r->next; 315 | } 316 | txt_buffer[strlen(txt_buffer) - 1] = '\0'; // remove new line 317 | ESP_LOGI(TAG, "Found: %s", txt_buffer); 318 | mdns_query_results_free(results); 319 | } 320 | } -------------------------------------------------------------------------------- /main/images/arrowgoleft.c: -------------------------------------------------------------------------------- 1 | #include "lvgl/lvgl.h" 2 | 3 | #ifndef LV_ATTRIBUTE_MEM_ALIGN 4 | #define LV_ATTRIBUTE_MEM_ALIGN 5 | #endif 6 | 7 | #ifndef LV_ATTRIBUTE_IMG_ARROWGOLEFT 8 | #define LV_ATTRIBUTE_IMG_ARROWGOLEFT 9 | #endif 10 | 11 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_ARROWGOLEFT uint8_t arrowgoleft_map[] = { 12 | #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 13 | /*Pixel format: Red: 3 bit, Green: 3 bit, Blue: 2 bit*/ 14 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0x00, 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 18 | 0x00, 0x00, 0x00, 0x00, 0x9c, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 19 | 0x00, 0x00, 0x00, 0xfc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 20 | 0x00, 0x00, 0xfc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 21 | 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 22 | 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 24 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 26 | 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 27 | 0x00, 0x00, 0xfc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 28 | 0x00, 0x00, 0x00, 0xfc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 29 | 0x00, 0x00, 0x00, 0x00, 0x9c, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0xbc, 0xbc, 0x00, 34 | #endif 35 | #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0 36 | /*Pixel format: Red: 5 bit, Green: 6 bit, Blue: 5 bit*/ 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x96, 38 | 0xe0, 0x9e, 0x20, 0xa7, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xae, 0xe0, 0x9e, 40 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 42 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xaf, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 44 | 0xe0, 0x9e, 0x00, 0x9f, 0x20, 0x97, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x87, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 46 | 0x00, 0x9f, 0x00, 0x9f, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 48 | 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 0x00, 0x00, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 57 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x9f, 66 | 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x87, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 68 | 0x00, 0x9f, 0x00, 0x9f, 0x00, 0x00, 69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xaf, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 70 | 0xe0, 0x9e, 0x00, 0x9f, 0x20, 0x97, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 72 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xae, 0xe0, 0x9e, 74 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x97, 76 | 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x00, 77 | #endif 78 | #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0 79 | /*Pixel format: Red: 5 bit, Green: 6 bit, Blue: 5 bit BUT the 2 bytes are swapped*/ 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0xe0, 0x9e, 0xe0, 0xa7, 0x20, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xa0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x60, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x97, 0x20, 84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x9f, 0x00, 0x00, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 | 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 | 0x00, 0x00, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 | 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x9f, 0x00, 0x00, 0x00, 96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9f, 0x00, 0x97, 0x20, 97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x60, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 98 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xa0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 99 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x20, 0x9e, 0xe0, 0x9e, 0xe0, 0x00, 0x00, 100 | #endif 101 | #if LV_COLOR_DEPTH == 32 102 | /*Pixel format: Fix 0xFF: 8 bit, Red: 8 bit, Green: 8 bit, Blue: 8 bit*/ 103 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdb, 0x92, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xe3, 0x9e, 0xff, 0x00, 0x00, 0x00, 0xff, 104 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xd5, 0xaa, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9b, 0xff, 105 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xcc, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 106 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xaa, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xe4, 0x94, 0xff, 107 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xdf, 0x95, 0xff, 0x00, 0x00, 0x00, 0xff, 108 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xdd, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9b, 0xff, 0x00, 0xe2, 0x9d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 109 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 110 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdd, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xe0, 0x9b, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 111 | 0x00, 0x00, 0x00, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 112 | 0x00, 0xde, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xe1, 0x98, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 113 | 0x00, 0xde, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xe1, 0x98, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 114 | 0x00, 0x00, 0x00, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 115 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdd, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xe0, 0x9b, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 116 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 117 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xdd, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9b, 0xff, 0x00, 0xe2, 0x9d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 118 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xdf, 0x95, 0xff, 0x00, 0x00, 0x00, 0xff, 119 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xaa, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xe4, 0x94, 0xff, 120 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xcc, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 121 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xd5, 0xaa, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9b, 0xff, 122 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xe3, 0x8e, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x98, 0xff, 0x00, 0x00, 0x00, 0xff, 123 | #endif 124 | }; 125 | 126 | const lv_img_dsc_t arrowgoleft = { 127 | .header.always_zero = 0, 128 | .header.w = 12, 129 | .header.h = 20, 130 | .data_size = 240 * LV_COLOR_SIZE / 8, 131 | .header.cf = LV_IMG_CF_TRUE_COLOR, 132 | .data = arrowgoleft_map, 133 | }; 134 | -------------------------------------------------------------------------------- /main/images/arrowgoright.c: -------------------------------------------------------------------------------- 1 | #include "lvgl/lvgl.h" 2 | 3 | #ifndef LV_ATTRIBUTE_MEM_ALIGN 4 | #define LV_ATTRIBUTE_MEM_ALIGN 5 | #endif 6 | 7 | #ifndef LV_ATTRIBUTE_IMG_ARROWGORIGHT 8 | #define LV_ATTRIBUTE_IMG_ARROWGORIGHT 9 | #endif 10 | 11 | const LV_ATTRIBUTE_MEM_ALIGN LV_ATTRIBUTE_IMG_ARROWGORIGHT uint8_t arrowgoright_map[] = { 12 | #if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 13 | /*Pixel format: Red: 3 bit, Green: 3 bit, Blue: 2 bit*/ 14 | 0x00, 0xbc, 0xbc, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 15 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 17 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 18 | 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x98, 0x00, 0x00, 0x00, 0x00, 19 | 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x9c, 0x00, 0x00, 0x00, 20 | 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xfc, 0x00, 0x00, 21 | 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 26 | 0x00, 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 27 | 0x00, 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xfc, 0x00, 0x00, 28 | 0x00, 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x9c, 0x00, 0x00, 0x00, 29 | 0x00, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x98, 0x00, 0x00, 0x00, 0x00, 30 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0xbc, 0xbc, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | #endif 35 | #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0 36 | /*Pixel format: Red: 5 bit, Green: 6 bit, Blue: 5 bit*/ 37 | 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0x20, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x60, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0xa7, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 | 0x00, 0x00, 0xe0, 0xa6, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x86, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x87, 48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 50 | 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xa6, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 52 | 0xe0, 0x9e, 0x00, 0x00, 0x00, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 54 | 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 56 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 58 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 60 | 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xa6, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 62 | 0xe0, 0x9e, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 64 | 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0xe0, 0x9e, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x87, 66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 67 | 0x00, 0x00, 0xe0, 0xa6, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x86, 0x00, 0x00, 68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | 0x00, 0xa7, 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 71 | 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x60, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 73 | 0x00, 0x9f, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 75 | 0x00, 0x00, 0xe0, 0x9e, 0xe0, 0x9e, 0x20, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 | #endif 78 | #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP != 0 79 | /*Pixel format: Red: 5 bit, Green: 6 bit, Blue: 5 bit BUT the 2 bytes are swapped*/ 80 | 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x97, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 83 | 0xa7, 0x00, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 84 | 0x00, 0x00, 0xa6, 0xe0, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x87, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00, 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x00, 0x00, 89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x00, 0x00, 92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00, 93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x9e, 0xe0, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x87, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0xa6, 0xe0, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 96 | 0xa7, 0x00, 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 97 | 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 98 | 0x9f, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x9e, 0xe0, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 99 | 0x00, 0x00, 0x9e, 0xe0, 0x9e, 0xe0, 0x97, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 100 | #endif 101 | #if LV_COLOR_DEPTH == 32 102 | /*Pixel format: Fix 0xFF: 8 bit, Red: 8 bit, Green: 8 bit, Blue: 8 bit*/ 103 | 0x00, 0x00, 0x00, 0xff, 0x00, 0xdc, 0x9a, 0xff, 0x00, 0xdd, 0x99, 0xff, 0x00, 0xe3, 0x8e, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 104 | 0x00, 0xdf, 0x9b, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 105 | 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xcc, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 106 | 0x00, 0xdf, 0x9f, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0xbf, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 107 | 0x00, 0x00, 0x00, 0xff, 0x00, 0xdb, 0x9e, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xbf, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 108 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdc, 0x97, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xff, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 109 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdb, 0x9b, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 110 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdc, 0x9e, 0xff, 0x00, 0xde, 0x9b, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 111 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdc, 0x9c, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdd, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 112 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x99, 0xff, 113 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x99, 0xff, 114 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdc, 0x9c, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdd, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 115 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdc, 0x9e, 0xff, 0x00, 0xde, 0x9b, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 116 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdb, 0x9b, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 117 | 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xdc, 0x97, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdd, 0x9a, 0xff, 0x00, 0xff, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 118 | 0x00, 0x00, 0x00, 0xff, 0x00, 0xdb, 0x9e, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xbf, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 119 | 0x00, 0xdf, 0x9f, 0xff, 0x00, 0xdf, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x99, 0xff, 0x00, 0xbf, 0x80, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 120 | 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xcc, 0x99, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 121 | 0x00, 0xdf, 0x9b, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xdf, 0x9f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 122 | 0x00, 0x00, 0x00, 0xff, 0x00, 0xde, 0x98, 0xff, 0x00, 0xde, 0x9a, 0xff, 0x00, 0xe3, 0x8e, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 123 | #endif 124 | }; 125 | 126 | const lv_img_dsc_t arrowgoright = { 127 | .header.always_zero = 0, 128 | .header.w = 12, 129 | .header.h = 20, 130 | .data_size = 240 * LV_COLOR_SIZE / 8, 131 | .header.cf = LV_IMG_CF_TRUE_COLOR, 132 | .data = arrowgoright_map, 133 | }; 134 | --------------------------------------------------------------------------------