mirror of
https://github.com/suchmememanyskill/CYD-Klipper.git
synced 2026-03-21 13:43:25 +00:00
Compare commits
92 Commits
v1.6.2
...
atomique-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63ba4a0abb | ||
|
|
1954cb000e | ||
|
|
6b39cbaf9d | ||
|
|
ebd618b481 | ||
|
|
1d7414d0ca | ||
|
|
0992f466cf | ||
|
|
f8ed3afd06 | ||
|
|
fdfa2d014f | ||
|
|
1efaa616e1 | ||
|
|
1cd6c8fd92 | ||
|
|
7b0497c75b | ||
|
|
df610168c0 | ||
|
|
d0f90a56d0 | ||
|
|
b67f091c46 | ||
|
|
71119e1648 | ||
|
|
660723d596 | ||
|
|
5ec2ba66e4 | ||
|
|
4fc16ecc92 | ||
|
|
161c10a43b | ||
|
|
093dd5efff | ||
|
|
4dd70aa3ea | ||
|
|
f4498e95cd | ||
|
|
b342e58cfc | ||
|
|
211fe15aee | ||
|
|
abbb0b2f7e | ||
|
|
6aa74633a8 | ||
|
|
2f1b0095b0 | ||
|
|
68b68af715 | ||
|
|
96f8695b0e | ||
|
|
2fce5a9e30 | ||
|
|
1578b4129d | ||
|
|
fcd133eb32 | ||
|
|
15dedb7255 | ||
|
|
0c364ec597 | ||
|
|
8521664a69 | ||
|
|
1b0ca807e4 | ||
|
|
12781051ca | ||
|
|
e5390e731f | ||
|
|
17143d2878 | ||
|
|
bf90803107 | ||
|
|
f9444829ee | ||
|
|
92b7b68dc5 | ||
|
|
747ff4c79c | ||
|
|
d4ce7a71ba | ||
|
|
0e57aed87c | ||
|
|
66e3a6765c | ||
|
|
f21b480611 | ||
|
|
49a1bd6e57 | ||
|
|
1483345e67 | ||
|
|
205926364c | ||
|
|
9a915bedda | ||
|
|
650b055fcd | ||
|
|
4207d82a7e | ||
|
|
b1138d9510 | ||
|
|
572d27dc8a | ||
|
|
ccc5817799 | ||
|
|
b99e00d79c | ||
|
|
d6e788f0c8 | ||
|
|
5bb4fd2b3c | ||
|
|
69d98a9e19 | ||
|
|
1516b785f5 | ||
|
|
fcdce6c5bf | ||
|
|
c0e329c57d | ||
|
|
6273e10e5a | ||
|
|
75bb334b09 | ||
|
|
be0bf0fc71 | ||
|
|
c35b146762 | ||
|
|
e55c2871d9 | ||
|
|
309a6865a5 | ||
|
|
ec7e6f180d | ||
|
|
337a26be3d | ||
|
|
6a9023eb8d | ||
|
|
2078a1541d | ||
|
|
eed4b3efef | ||
|
|
22fc25ccc7 | ||
|
|
9a6fce854c | ||
|
|
0b1db1d834 | ||
|
|
db019939a6 | ||
|
|
6ebaf68cf1 | ||
|
|
41aa073ae0 | ||
|
|
19cfaefd36 | ||
|
|
04d890227e | ||
|
|
e2c2a38b20 | ||
|
|
5d2571ef83 | ||
|
|
d4645f4fa1 | ||
|
|
4ac87c8ffc | ||
|
|
d780c8d55e | ||
|
|
d69446a11b | ||
|
|
90fd1b0ab2 | ||
|
|
4a96f7db0b | ||
|
|
c640d7fade | ||
|
|
d22a9e1ee4 |
14
.github/workflows/compile.yaml
vendored
14
.github/workflows/compile.yaml
vendored
@@ -17,19 +17,19 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
key: ${{ runner.os }}-pio-cyd-klipper
|
||||
#- uses: actions/cache@v3
|
||||
# with:
|
||||
# path: |
|
||||
# ~/.cache/pip
|
||||
# ~/.platformio/.cache
|
||||
# key: ${{ runner.os }}-pio-cyd-klipper
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
|
||||
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
_site/out/
|
||||
_site/OTA.json
|
||||
_site/esp32-*.json
|
||||
|
||||
pyvenv.cfg
|
||||
bin/
|
||||
out/
|
||||
lib
|
||||
lib64
|
||||
|
||||
__pycache__/
|
||||
37
CYD-Klipper/.vscode/settings.json
vendored
37
CYD-Klipper/.vscode/settings.json
vendored
@@ -13,7 +13,42 @@
|
||||
"cstddef": "cpp",
|
||||
"functional": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cmath": "cpp"
|
||||
"cmath": "cpp",
|
||||
"system_error": "cpp",
|
||||
"random": "cpp",
|
||||
"optional": "cpp",
|
||||
"limits": "cpp",
|
||||
"memory": "cpp",
|
||||
"new": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"atomic": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"exception": "cpp",
|
||||
"iterator": "cpp",
|
||||
"map": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"tuple": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"istream": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp"
|
||||
},
|
||||
"cmake.configureOnOpen": false
|
||||
}
|
||||
143
CYD-Klipper/boards/esp32-8048S043C-smartdisplay-alt.json
Normal file
143
CYD-Klipper/boards/esp32-8048S043C-smartdisplay-alt.json
Normal file
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default_16MB.csv",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"'-D ARDUINO_ESP32S3_DEV'",
|
||||
"'-D BOARD_HAS_PSRAM'",
|
||||
"'-D ARDUINO_USB_MODE=1'",
|
||||
"'-D ARDUINO_RUNNING_CORE=1'",
|
||||
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
|
||||
"'-D ARDUINO_USB_CDC_ON_BOOT=0'",
|
||||
"'-D ESP32_8048S043C'",
|
||||
"'-D LCD_WIDTH=800'",
|
||||
"'-D LCD_HEIGHT=480'",
|
||||
"'-D LVGL_BUFFER_PIXELS=(LCD_WIDTH*LCD_HEIGHT)'",
|
||||
"'-D LVGL_BUFFER_MALLOC_FLAGS=(MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT)'",
|
||||
"'-D GPIO_BCKL=2'",
|
||||
"'-D LCD_ST7262_PAR'",
|
||||
"'-D ST7262_PANEL_CONFIG_CLK_SRC=LCD_CLK_SRC_PLL160M'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_PCLK_HZ=14000000'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_H_RES=LCD_WIDTH'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_V_RES=LCD_HEIGHT'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_HSYNC_PULSE_WIDTH=4'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_HSYNC_BACK_PORCH=8'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_HSYNC_FRONT_PORCH=8'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_VSYNC_PULSE_WIDTH=4'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_VSYNC_BACK_PORCH=8'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_VSYNC_FRONT_PORCH=8'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_FLAGS_HSYNC_IDLE_LOW=false'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_FLAGS_VSYNC_IDLE_LOW=false'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_FLAGS_DE_IDLE_HIGH=false'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_FLAGS_PCLK_ACTIVE_NEG=true'",
|
||||
"'-D ST7262_PANEL_CONFIG_TIMINGS_FLAGS_PCLK_IDLE_HIGH=false'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_WIDTH=16'",
|
||||
"'-D ST7262_PANEL_CONFIG_SRAM_TRANS_ALIGN=4'",
|
||||
"'-D ST7262_PANEL_CONFIG_PSRAM_TRANS_ALIGN=64'",
|
||||
"'-D ST7262_PANEL_CONFIG_HSYNC_GPIO_NUM=39'",
|
||||
"'-D ST7262_PANEL_CONFIG_VSYNC_GPIO_NUM=41'",
|
||||
"'-D ST7262_PANEL_CONFIG_DE_GPIO_NUM=40'",
|
||||
"'-D ST7262_PANEL_CONFIG_PCLK_GPIO_NUM=42'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_R0=8'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_R1=3'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_R2=46'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_R3=9'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_R4=1'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_G0=5'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_G1=6'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_G2=7'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_G3=15'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_G4=16'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_G5=4'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_B0=45'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_B1=48'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_B2=47'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_B3=21'",
|
||||
"'-D ST7262_PANEL_CONFIG_DATA_GPIO_B4=14'",
|
||||
"'-D ST7262_PANEL_CONFIG_DISP_GPIO_NUM=GPIO_NUM_NC'",
|
||||
"'-D ST7262_PANEL_CONFIG_FLAGS_DISP_ACTIVE_LOW=false'",
|
||||
"'-D ST7262_PANEL_CONFIG_FLAGS_RELAX_ON_IDLE=false'",
|
||||
"'-D ST7262_PANEL_CONFIG_FLAGS_FB_IN_PSRAM=true'",
|
||||
"'-D BOARD_HAS_TOUCH'",
|
||||
"'-D TOUCH_GT911_I2C'",
|
||||
"'-D GT911_I2C_HOST=I2C_NUM_0'",
|
||||
"'-D GT911_I2C_CONFIG_SDA_IO_NUM=19'",
|
||||
"'-D GT911_I2C_CONFIG_SCL_IO_NUM=20'",
|
||||
"'-D GT911_I2C_CONFIG_SDA_PULLUP_EN=GPIO_PULLUP_DISABLE'",
|
||||
"'-D GT911_I2C_CONFIG_SCL_PULLUP_EN=GPIO_PULLUP_DISABLE'",
|
||||
"'-D GT911_I2C_CONFIG_MASTER_CLK_SPEED=400000'",
|
||||
"'-D GT911_I2C_CONFIG_CLK_FLAGS=I2C_SCLK_SRC_FLAG_FOR_NOMAL'",
|
||||
"'-D GT911_IO_I2C_CONFIG_DEV_ADDR=ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS'",
|
||||
"'-D GT911_IO_I2C_CONFIG_CONTROL_PHASE_BYTES=1'",
|
||||
"'-D GT911_IO_I2C_CONFIG_DC_BIT_OFFSET=0'",
|
||||
"'-D GT911_IO_I2C_CONFIG_LCD_CMD_BITS=16'",
|
||||
"'-D GT911_IO_I2C_CONFIG_LCD_PARAM_BITS=0'",
|
||||
"'-D GT911_IO_I2C_CONFIG_FLAGS_DC_LOW_ON_DATA=false'",
|
||||
"'-D GT911_IO_I2C_CONFIG_FLAGS_DISABLE_CONTROL_PHASE=true'",
|
||||
"'-D GT911_TOUCH_CONFIG_X_MAX=LCD_WIDTH'",
|
||||
"'-D GT911_TOUCH_CONFIG_Y_MAX=LCD_HEIGHT'",
|
||||
"'-D GT911_TOUCH_CONFIG_RST_GPIO_NUM=38'",
|
||||
"'-D GT911_TOUCH_CONFIG_INT_GPIO_NUM=18'",
|
||||
"'-D GT911_TOUCH_CONFIG_LEVELS_RESET=0'",
|
||||
"'-D GT911_TOUCH_CONFIG_LEVELS_INTERRUPT=0'",
|
||||
"'-D TOUCH_SWAP_XY=false'",
|
||||
"'-D TOUCH_SWAP_X=false'",
|
||||
"'-D TOUCH_SWAP_Y=false'",
|
||||
"'-D BOARD_HAS_TF'",
|
||||
"'-D TF_CS=10'",
|
||||
"'-D TF_SPI_MOSI=11'",
|
||||
"'-D TF_SPI_SCLK=12'",
|
||||
"'-D TF_SPI_MISO=13'",
|
||||
|
||||
"-DCYD_SCREEN_HEIGHT_PX=480",
|
||||
"-DCYD_SCREEN_WIDTH_PX=800",
|
||||
"-DROTATION_INVERTED=LV_DISP_ROT_180",
|
||||
"-DROTATION_NORMAL=LV_DISP_ROT_NONE",
|
||||
"-DCYD_SCREEN_GAP_PX=15",
|
||||
"-DCYD_SCREEN_MIN_BUTTON_HEIGHT_PX=60",
|
||||
"-DCYD_SCREEN_MIN_BUTTON_WIDTH_PX=60",
|
||||
"-DCYD_SCREEN_FONT=lv_font_montserrat_22",
|
||||
"-DCYD_SCREEN_FONT_SMALL=lv_font_montserrat_16",
|
||||
"-DCYD_SCREEN_SIDEBAR_SIZE_PX=70",
|
||||
"-DCYD_SCREEN_DRIVER_ESP32_SMARTDISPLAY=1",
|
||||
"-DCYD_SCREEN_DISABLE_TOUCH_CALIBRATION=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "esp32-8048S043C-SD-alt",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.aliexpress.com/item/1005006110360174.html",
|
||||
"vendor": "Sunton"
|
||||
}
|
||||
63
CYD-Klipper/boards/esp32-CROWPANEL-28R.json
Normal file
63
CYD-Klipper/boards/esp32-CROWPANEL-28R.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DUSER_SETUP_LOADED=1",
|
||||
"-DILI9341_2_DRIVER=1",
|
||||
"-DTFT_BACKLIGHT_ON=HIGH",
|
||||
"-DTFT_BL=27",
|
||||
"-DTFT_MISO=12",
|
||||
"-DTFT_MOSI=13",
|
||||
"-DTFT_SCLK=14",
|
||||
"-DTFT_CS=15",
|
||||
"-DTFT_DC=2",
|
||||
"-DTFT_RST=-1",
|
||||
"-DLOAD_GCLD=1",
|
||||
"-DSPI_FREQUENCY=15999999",
|
||||
"-DSPI_READ_FREQUENCY=20000000",
|
||||
"-DSPI_TOUCH_FREQUENCY=600000",
|
||||
"-DTOUCH_CS=33",
|
||||
|
||||
"-DCYD_SCREEN_HEIGHT_PX=240",
|
||||
"-DCYD_SCREEN_WIDTH_PX=320",
|
||||
"-DCYD_SCREEN_GAP_PX=8",
|
||||
"-DCYD_SCREEN_MIN_BUTTON_HEIGHT_PX=35",
|
||||
"-DCYD_SCREEN_MIN_BUTTON_WIDTH_PX=35",
|
||||
"-DCYD_SCREEN_FONT=lv_font_montserrat_14",
|
||||
"-DCYD_SCREEN_FONT_SMALL=lv_font_montserrat_10",
|
||||
"-DCYD_SCREEN_SIDEBAR_SIZE_PX=40",
|
||||
"-DCYD_SCREEN_DRIVER_ESP32_CROWPANEL_28R=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "40000000L",
|
||||
"flash_mode": "dio",
|
||||
"mcu": "esp32",
|
||||
"variant": "esp32"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi",
|
||||
"bluetooth",
|
||||
"ethernet",
|
||||
"can"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_board": "esp-wroom-32.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "esp32-crowpanel-28R",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.aliexpress.com/item/1005004502250619.html",
|
||||
"vendor": "Sunton"
|
||||
}
|
||||
55
CYD-Klipper/boards/esp32-CROWPANEL-35C.json
Normal file
55
CYD-Klipper/boards/esp32-CROWPANEL-35C.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default_16MB.csv",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DCYD_SCREEN_HEIGHT_PX=320",
|
||||
"-DCYD_SCREEN_WIDTH_PX=480",
|
||||
"-DCYD_SCREEN_GAP_PX=10",
|
||||
"-DCYD_SCREEN_MIN_BUTTON_HEIGHT_PX=45",
|
||||
"-DCYD_SCREEN_MIN_BUTTON_WIDTH_PX=45",
|
||||
"-DCYD_SCREEN_FONT=lv_font_montserrat_16",
|
||||
"-DCYD_SCREEN_FONT_SMALL=lv_font_montserrat_12",
|
||||
"-DCYD_SCREEN_SIDEBAR_SIZE_PX=50",
|
||||
"-DCYD_SCREEN_DRIVER_ESP32_CROWPANEL_35C=1",
|
||||
"-DCYD_SCREEN_DISABLE_TOUCH_CALIBRATION=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [
|
||||
[
|
||||
"0x303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "esp32-8048S043C-SD",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://www.elecrow.com/esp-terminal-with-esp32-3-5-inch-parallel-480x320-tft-capacitive-touch-display-rgb-by-chip-ili9488.html",
|
||||
"vendor": "CROWPANEL"
|
||||
}
|
||||
@@ -9,15 +9,17 @@
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env]
|
||||
platform = https://github.com/platformio/platform-espressif32#v6.4.0
|
||||
platform = espressif32@6.4.0
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
debug_build_flags = -Os
|
||||
lib_deps =
|
||||
https://github.com/suchmememanyskill/esp32-smartdisplay#9c1d737
|
||||
bblanchon/ArduinoJson@^7.0.0
|
||||
plageoj/UrlEncode@^1.0.1
|
||||
erriez/ErriezCRC32 @ ^1.0.1
|
||||
knolleary/PubSubClient@^2.8
|
||||
WiFiClientSecure
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags =
|
||||
-DLV_CONF_PATH="../../../../src/conf/lv_conf.h"
|
||||
@@ -33,7 +35,8 @@ lib_deps =
|
||||
https://github.com/PaulStoffregen/XPT2046_Touchscreen.git
|
||||
bblanchon/ArduinoJson@^7.0.0
|
||||
plageoj/UrlEncode@^1.0.1
|
||||
erriez/ErriezCRC32 @ ^1.0.1
|
||||
knolleary/PubSubClient@^2.8
|
||||
WiFiClientSecure
|
||||
|
||||
[env:esp32-3248S035C]
|
||||
board = esp32-3248S035C
|
||||
@@ -44,7 +47,8 @@ lib_deps =
|
||||
https://github.com/OperatorB/gt911-arduino-fixed-reset.git
|
||||
bblanchon/ArduinoJson@^7.0.0
|
||||
plageoj/UrlEncode@^1.0.1
|
||||
erriez/ErriezCRC32 @ ^1.0.1
|
||||
knolleary/PubSubClient@^2.8
|
||||
WiFiClientSecure
|
||||
|
||||
[env:esp32-3248S035C-V]
|
||||
board = esp32-3248S035C-vertical
|
||||
@@ -55,7 +59,8 @@ lib_deps =
|
||||
https://github.com/OperatorB/gt911-arduino-fixed-reset.git
|
||||
bblanchon/ArduinoJson@^7.0.0
|
||||
plageoj/UrlEncode@^1.0.1
|
||||
erriez/ErriezCRC32 @ ^1.0.1
|
||||
knolleary/PubSubClient@^2.8
|
||||
WiFiClientSecure
|
||||
|
||||
[env:esp32-2432S024C-SD]
|
||||
board = esp32-2432S024C-smartdisplay
|
||||
@@ -84,3 +89,27 @@ board = esp32-4827S043C-smartdisplay
|
||||
[env:esp32-8048S043C-SD]
|
||||
board = esp32-8048S043C-smartdisplay
|
||||
|
||||
[env:esp32-8048S043C-SD-alt]
|
||||
board = esp32-8048S043C-smartdisplay-alt
|
||||
|
||||
[env:esp32-CROWPANEL-28R]
|
||||
board = esp32-CROWPANEL-28R
|
||||
lib_deps =
|
||||
SPI
|
||||
https://github.com/suchmememanyskill/lvgl
|
||||
https://github.com/Bodmer/TFT_eSPI.git
|
||||
bblanchon/ArduinoJson@^7.0.0
|
||||
plageoj/UrlEncode@^1.0.1
|
||||
knolleary/PubSubClient@^2.8
|
||||
WiFiClientSecure
|
||||
|
||||
[env:esp32-CROWPANEL-35C]
|
||||
board = esp32-CROWPANEL-35C
|
||||
lib_deps =
|
||||
SPI
|
||||
https://github.com/suchmememanyskill/lvgl
|
||||
https://github.com/lovyan03/LovyanGFX@1.2.0
|
||||
bblanchon/ArduinoJson@^7.0.0
|
||||
plageoj/UrlEncode@^1.0.1
|
||||
knolleary/PubSubClient@^2.8
|
||||
WiFiClientSecure
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
#include "global_config.h"
|
||||
#include "lvgl.h"
|
||||
|
||||
GLOBAL_CONFIG global_config = {0};
|
||||
GlobalConfig global_config = {0};
|
||||
TemporaryConfig temporary_config = {0};
|
||||
|
||||
COLOR_DEF color_defs[] = {
|
||||
ColorDefinition color_defs[] = {
|
||||
{LV_PALETTE_BLUE, 0, LV_PALETTE_RED},
|
||||
{LV_PALETTE_GREEN, 0, LV_PALETTE_PURPLE},
|
||||
{LV_PALETTE_LIME, -2, LV_PALETTE_PURPLE},
|
||||
@@ -29,27 +30,27 @@ void verify_version()
|
||||
if (!preferences.begin("global_config", false))
|
||||
return;
|
||||
|
||||
GLOBAL_CONFIG config = {0};
|
||||
GlobalConfig config = {0};
|
||||
preferences.getBytes("global_config", &config, sizeof(config));
|
||||
Serial.printf("Config version: %d\n", config.version);
|
||||
LOG_F(("Config version: %d\n", config.version))
|
||||
if (config.version != CONFIG_VERSION) {
|
||||
Serial.println("Clearing Global Config");
|
||||
LOG_LN("Clearing Global Config");
|
||||
preferences.clear();
|
||||
}
|
||||
|
||||
preferences.end();
|
||||
}
|
||||
|
||||
PRINTER_CONFIG* get_current_printer_config()
|
||||
PrinterConfiguration* get_current_printer_config()
|
||||
{
|
||||
return &global_config.printer_config[global_config.printer_index];
|
||||
}
|
||||
|
||||
int get_printer_config_count()
|
||||
int global_config_get_printer_config_count()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < PRINTER_CONFIG_COUNT; i++) {
|
||||
if (global_config.printer_config[i].ip_configured)
|
||||
if (global_config.printer_config[i].setup_complete)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
@@ -58,19 +59,82 @@ int get_printer_config_count()
|
||||
int get_printer_config_free_index()
|
||||
{
|
||||
for (int i = 0; i < PRINTER_CONFIG_COUNT; i++) {
|
||||
if (!global_config.printer_config[i].ip_configured)
|
||||
if (!global_config.printer_config[i].setup_complete)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void global_config_add_new_printer()
|
||||
{
|
||||
int free_index = get_printer_config_free_index();
|
||||
if (free_index <= -1)
|
||||
{
|
||||
LOG_LN("No available slot for new printer");
|
||||
return;
|
||||
}
|
||||
|
||||
PrinterConfiguration* old_config = &global_config.printer_config[global_config.printer_index];
|
||||
PrinterConfiguration* new_config = &global_config.printer_config[free_index];
|
||||
|
||||
new_config->raw = old_config->raw;
|
||||
new_config->setup_complete = false;
|
||||
new_config->ip_configured = false;
|
||||
new_config->auth_configured = false;
|
||||
new_config->printer_type = PrinterType::PrinterTypeNone;
|
||||
|
||||
new_config->printer_name[0] = 0;
|
||||
new_config->printer_host[0] = 0;
|
||||
new_config->printer_auth[0] = 0;
|
||||
new_config->klipper_port = 0;
|
||||
|
||||
new_config->color_scheme = old_config->color_scheme;
|
||||
|
||||
// TODO: Replace with memcpy
|
||||
for (int i = 0; i < 3; i++){
|
||||
new_config->hotend_presets[i] = old_config->hotend_presets[i];
|
||||
new_config->bed_presets[i] = old_config->bed_presets[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++){
|
||||
new_config->printer_move_x_steps[i] = old_config->printer_move_x_steps[i];
|
||||
new_config->printer_move_y_steps[i] = old_config->printer_move_y_steps[i];
|
||||
new_config->printer_move_z_steps[i] = old_config->printer_move_z_steps[i];
|
||||
}
|
||||
|
||||
global_config_set_printer(free_index);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void global_config_set_printer(int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= PRINTER_CONFIG_COUNT || global_config.printer_index == idx)
|
||||
return;
|
||||
|
||||
global_config.printer_index = idx;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
void global_config_delete_printer(int idx)
|
||||
{
|
||||
if (global_config.printer_index == idx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PrinterConfiguration* config = &global_config.printer_config[idx];
|
||||
config->setup_complete = false;
|
||||
write_global_config();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void set_printer_config_index(int index)
|
||||
{
|
||||
if (index < 0 || index >= PRINTER_CONFIG_COUNT)
|
||||
return;
|
||||
|
||||
PRINTER_CONFIG* old_config = &global_config.printer_config[global_config.printer_index];
|
||||
PRINTER_CONFIG* new_config = &global_config.printer_config[index];
|
||||
PrinterConfiguration* old_config = &global_config.printer_config[global_config.printer_index];
|
||||
PrinterConfiguration* new_config = &global_config.printer_config[index];
|
||||
|
||||
global_config.printer_index = index;
|
||||
|
||||
@@ -80,8 +144,8 @@ void set_printer_config_index(int index)
|
||||
new_config->auth_configured = false;
|
||||
|
||||
new_config->printer_name[0] = 0;
|
||||
new_config->klipper_host[0] = 0;
|
||||
new_config->klipper_auth[0] = 0;
|
||||
new_config->printer_host[0] = 0;
|
||||
new_config->printer_auth[0] = 0;
|
||||
new_config->klipper_port = 0;
|
||||
|
||||
new_config->color_scheme = old_config->color_scheme;
|
||||
@@ -131,4 +195,11 @@ void load_global_config()
|
||||
preferences.begin("global_config", true);
|
||||
preferences.getBytes("global_config", &global_config, sizeof(global_config));
|
||||
preferences.end();
|
||||
|
||||
#if defined REPO_DEVELOPMENT && REPO_DEVELOPMENT == 1
|
||||
temporary_config.debug = true;
|
||||
#else
|
||||
temporary_config.debug = false;
|
||||
#endif
|
||||
temporary_config.remote_echo = true;
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
#include "lvgl.h"
|
||||
|
||||
#define CONFIG_VERSION 6
|
||||
#define PRINTER_CONFIG_COUNT 8
|
||||
#define CONFIG_VERSION 7
|
||||
#define PRINTER_CONFIG_COUNT 6
|
||||
#define DISPLAY_SECRETS 0
|
||||
|
||||
enum {
|
||||
REMAINING_TIME_CALC_PERCENTAGE = 0,
|
||||
@@ -19,28 +20,38 @@ enum {
|
||||
SHOW_STATS_ON_PROGRESS_PANEL_ALL = 3,
|
||||
};
|
||||
|
||||
typedef struct _PRINTER_CONFIG {
|
||||
enum PrinterType {
|
||||
PrinterTypeNone = 0,
|
||||
PrinterTypeKlipper = 1,
|
||||
PrinterTypeKlipperSerial = 2,
|
||||
PrinterTypeBambuLocal = 3,
|
||||
PrinterTypeBambuCloud = 3,
|
||||
PrinterTypeOctoprint = 4,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
unsigned int raw;
|
||||
struct {
|
||||
// Internal
|
||||
bool setup_complete : 1;
|
||||
bool ip_configured : 1;
|
||||
bool auth_configured : 1;
|
||||
bool custom_filament_move_macros : 1;
|
||||
PrinterType printer_type : 3;
|
||||
|
||||
// External
|
||||
bool light_mode : 1;
|
||||
bool invert_colors : 1;
|
||||
unsigned char remaining_time_calc_mode : 2;
|
||||
unsigned char show_stats_on_progress_panel : 2;
|
||||
|
||||
bool custom_filament_move_macros : 1;
|
||||
};
|
||||
};
|
||||
|
||||
char printer_name[25];
|
||||
char klipper_host[65];
|
||||
char klipper_auth[33];
|
||||
unsigned short klipper_port;
|
||||
char printer_host[65];
|
||||
char printer_auth[65];
|
||||
unsigned int klipper_port;
|
||||
|
||||
unsigned char color_scheme;
|
||||
|
||||
@@ -50,9 +61,9 @@ typedef struct _PRINTER_CONFIG {
|
||||
unsigned short printer_move_x_steps[3];
|
||||
unsigned short printer_move_y_steps[3];
|
||||
unsigned short printer_move_z_steps[3];
|
||||
} PRINTER_CONFIG;
|
||||
} PrinterConfiguration;
|
||||
|
||||
typedef struct _GLOBAL_CONFIG {
|
||||
typedef struct {
|
||||
unsigned char version;
|
||||
union {
|
||||
unsigned int raw;
|
||||
@@ -60,6 +71,7 @@ typedef struct _GLOBAL_CONFIG {
|
||||
// Internal
|
||||
bool screen_calibrated : 1;
|
||||
bool wifi_configured : 1;
|
||||
bool wifi_configuration_skipped : 1;
|
||||
|
||||
// External
|
||||
bool rotate_screen : 1;
|
||||
@@ -68,10 +80,14 @@ typedef struct _GLOBAL_CONFIG {
|
||||
bool on_during_print : 1;
|
||||
bool display_mode : 1; // Driver specifc usage. Currently only used on ESP32-2432S028R to fix the screen on the usb-c model
|
||||
bool disable_m117_messaging : 1;
|
||||
bool sort_macros : 1;
|
||||
bool show_estop : 1;
|
||||
bool full_filenames : 1;
|
||||
bool double_size_gcode_img : 1;
|
||||
};
|
||||
};
|
||||
|
||||
PRINTER_CONFIG printer_config[PRINTER_CONFIG_COUNT];
|
||||
PrinterConfiguration printer_config[PRINTER_CONFIG_COUNT];
|
||||
|
||||
float screen_cal_x_offset;
|
||||
float screen_cal_x_mult;
|
||||
@@ -84,24 +100,39 @@ typedef struct _GLOBAL_CONFIG {
|
||||
unsigned char brightness;
|
||||
unsigned char screen_timeout;
|
||||
unsigned char printer_index;
|
||||
} GLOBAL_CONFIG;
|
||||
} GlobalConfig;
|
||||
|
||||
// Volatile/temporary config that doesn't survive a reset
|
||||
typedef struct {
|
||||
bool debug : 1;
|
||||
bool remote_echo : 1;
|
||||
} TemporaryConfig;
|
||||
|
||||
typedef struct _COLOR_DEF {
|
||||
typedef struct {
|
||||
lv_palette_t primary_color;
|
||||
short primary_color_light;
|
||||
lv_palette_t secondary_color;
|
||||
} COLOR_DEF;
|
||||
} ColorDefinition;
|
||||
|
||||
extern GLOBAL_CONFIG global_config;
|
||||
extern COLOR_DEF color_defs[];
|
||||
extern GlobalConfig global_config;
|
||||
extern TemporaryConfig temporary_config;
|
||||
extern ColorDefinition color_defs[];
|
||||
|
||||
#define LOG(x) if(temporary_config.debug){ Serial.print(x);}
|
||||
#define LOG_LN(x) if(temporary_config.debug){ Serial.println(x);}
|
||||
#define LOG_F(x) if(temporary_config.debug){ Serial.printf x ;} // use with double braces, LOF_F(("x=%d\n",x));
|
||||
|
||||
void write_global_config();
|
||||
void verify_version();
|
||||
void load_global_config();
|
||||
|
||||
PRINTER_CONFIG* get_current_printer_config();
|
||||
int get_printer_config_count();
|
||||
void set_printer_config_index(int index);
|
||||
int get_printer_config_free_index();
|
||||
void global_config_add_new_printer();
|
||||
void global_config_set_printer(int idx);
|
||||
void global_config_delete_printer(int idx);
|
||||
|
||||
//PRINTER_CONFIG* get_current_printer_config();
|
||||
int global_config_get_printer_config_count();
|
||||
//void set_printer_config_index(int index);
|
||||
//int get_printer_config_free_index();
|
||||
|
||||
#endif // !_GLOBAL_CONFIG_INIT
|
||||
371
CYD-Klipper/src/core/bambu/bambu_printer_integration.cpp
Normal file
371
CYD-Klipper/src/core/bambu/bambu_printer_integration.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
#include "bambu_printer_integration.hpp"
|
||||
#include <PubSubClient.h>
|
||||
|
||||
WiFiClientSecure wifi_client;
|
||||
PubSubClient client(wifi_client);
|
||||
BambuPrinter* current_printer = NULL;
|
||||
|
||||
const char* COMMAND_FETCH_ALL = "{\"pushing\":{\"sequence_id\":\"0\",\"command\":\"pushall\",\"version\":1,\"push_target\":1}}";
|
||||
const char* COMMAND_LIGHTCTL = "{\"system\":{\"sequence_id\":\"0\",\"command\":\"ledctrl\",\"led_node\":\"%s\",\"led_mode\":\"%s\"}}";
|
||||
const char* COMMAND_SEND_GCODE = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"gcode_line\",\"param\":\"%s\"}}";
|
||||
const char* COMMAND_PRINT_STOP = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"stop\",\"param\":\"\"}}";
|
||||
const char* COMMAND_PRINT_PAUSE = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"pause\",\"param\":\"\"}}";
|
||||
const char* COMMAND_PRINT_RESUME = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"resume\",\"param\":\"\"}}";
|
||||
const char* COMMAND_FILAMENT_UNLOAD = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"unload_filament\"}}";
|
||||
const char* COMMAND_FILAMENT_LOAD_EXTERNAL = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"ams_change_filament\",\"target\":254,\"curr_temp\":215,\"tar_temp\":250}}";
|
||||
const char* COMMAND_AMS_CONTOL_DONE = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"ams_control\",\"param\":\"done\"}}";
|
||||
const char* COMMAND_AMS_CONTOL_RETRY = "{\"print\":{\"sequence_id\":\"0\",\"command\":\"ams_control\",\"param\":\"resume\"}}";
|
||||
|
||||
static void callback(char* topic, byte* payload, unsigned int length)
|
||||
{
|
||||
if (current_printer != NULL)
|
||||
{
|
||||
current_printer->receive_data(payload, length);
|
||||
}
|
||||
}
|
||||
|
||||
void BambuPrinter::receive_data(unsigned char* data, unsigned int length)
|
||||
{
|
||||
data[length] = 0;
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, data);
|
||||
parse_state(doc);
|
||||
}
|
||||
|
||||
bool BambuPrinter::publish_mqtt_command(const char* command)
|
||||
{
|
||||
if (!client.connected())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char auth[48] = {0};
|
||||
sprintf(auth, "device/%s/request", printer_config->printer_auth);
|
||||
|
||||
LOG_F(("Publishing MQTT Command: %s\n", command));
|
||||
return client.publish(auth, command);
|
||||
}
|
||||
|
||||
bool BambuPrinter::move_printer(const char* axis, float amount, bool relative)
|
||||
{
|
||||
if (!printer_data.homed_axis || printer_data.state == PrinterStatePrinting)
|
||||
return false;
|
||||
|
||||
char gcode[64];
|
||||
const char* extra = (amount > 0) ? "+" : "";
|
||||
const char* start = "";
|
||||
const char* end = "";
|
||||
|
||||
if (relative) {
|
||||
start = "G91\n";
|
||||
}
|
||||
else {
|
||||
start = "G90\n";
|
||||
}
|
||||
|
||||
sprintf(gcode, "%sG1 %s%s%.3f F6000", start, axis, extra, amount);
|
||||
send_gcode(gcode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BambuPrinter::execute_feature(PrinterFeatures feature)
|
||||
{
|
||||
switch (feature)
|
||||
{
|
||||
case PrinterFeatureHome:
|
||||
return send_gcode("G28");
|
||||
case PrinterFeatureDisableSteppers:
|
||||
return send_gcode("M18 X Y Z");
|
||||
case PrinterFeaturePause:
|
||||
return publish_mqtt_command(COMMAND_PRINT_PAUSE);
|
||||
case PrinterFeatureResume:
|
||||
return publish_mqtt_command(COMMAND_PRINT_RESUME);
|
||||
case PrinterFeatureStop:
|
||||
return publish_mqtt_command(COMMAND_PRINT_STOP);
|
||||
case PrinterFeatureExtrude:
|
||||
if (printer_data.state == PrinterStatePrinting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_gcode("M83\nG1 E25 F300");
|
||||
case PrinterFeatureRetract:
|
||||
if (printer_data.state == PrinterStatePrinting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_gcode("M83\nG1 E-25 F300");
|
||||
case PrinterFeatureCooldown:
|
||||
return send_gcode("M104 S0\nM140 S0");
|
||||
case PrinterFeatureContinueError:
|
||||
return publish_mqtt_command(COMMAND_AMS_CONTOL_DONE);
|
||||
case PrinterFeatureRetryError:
|
||||
return publish_mqtt_command(COMMAND_AMS_CONTOL_RETRY);
|
||||
case PrinterFeatureIgnoreError:
|
||||
ignore_error = last_error;
|
||||
publish_mqtt_command(COMMAND_FETCH_ALL);
|
||||
return true;
|
||||
default:
|
||||
LOG_F(("Unsupported printer feature %d", feature));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BambuPrinter::connect()
|
||||
{
|
||||
wifi_client.setInsecure();
|
||||
wifi_client.setTimeout(3);
|
||||
client.setBufferSize(4096);
|
||||
client.setServer(printer_config->printer_host, 8883);
|
||||
current_printer = this;
|
||||
client.setCallback(NULL);
|
||||
char buff[10] = {0};
|
||||
sprintf(buff, "%d", printer_config->klipper_port);
|
||||
if (!client.connect("id", "bblp", buff))
|
||||
{
|
||||
LOG_LN("Bambu: Wrong IP or LAN code.");
|
||||
return false;
|
||||
}
|
||||
|
||||
char auth[48] = {0};
|
||||
sprintf(auth, "device/%s/report", printer_config->printer_auth);
|
||||
|
||||
if (!client.subscribe(auth))
|
||||
{
|
||||
LOG_LN("Bambu: Wrong serial number.");
|
||||
return false;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
client.loop();
|
||||
|
||||
if (!client.connected())
|
||||
{
|
||||
LOG_LN("Bambu: Connection lost. Likely wrong serial number.");
|
||||
return false;
|
||||
}
|
||||
|
||||
client.setCallback(callback);
|
||||
printer_data.state = PrinterState::PrinterStateIdle;
|
||||
return publish_mqtt_command(COMMAND_FETCH_ALL);
|
||||
}
|
||||
|
||||
void BambuPrinter::disconnect()
|
||||
{
|
||||
current_printer = NULL;
|
||||
printer_data.state = PrinterState::PrinterStateOffline;
|
||||
client.disconnect();
|
||||
client.setCallback(NULL);
|
||||
client.setBufferSize(16);
|
||||
}
|
||||
|
||||
bool BambuPrinter::fetch()
|
||||
{
|
||||
if (!client.connected())
|
||||
{
|
||||
LOG_LN("Failed to fetch printer data: Not connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!client.loop())
|
||||
{
|
||||
LOG_LN("Failed to fetch printer data: Fetching data failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PrinterDataMinimal BambuPrinter::fetch_min()
|
||||
{
|
||||
PrinterDataMinimal min = {};
|
||||
min.success = true;
|
||||
min.state = PrinterState::PrinterStateIdle;
|
||||
min.print_progress = 0;
|
||||
min.power_devices = 0;
|
||||
return min;
|
||||
}
|
||||
|
||||
const char * MACRO_UNLOAD = "Unload filament";
|
||||
const char * MACRO_LOAD = "Load filament (External)";
|
||||
|
||||
Macros BambuPrinter::get_macros()
|
||||
{
|
||||
Macros macros = {0};
|
||||
macros.success = true;
|
||||
macros.count = get_macros_count();
|
||||
macros.macros = (char **)malloc(sizeof(char *) * macros.count);
|
||||
|
||||
macros.macros[0] = (char *)malloc(25);
|
||||
strcpy(macros.macros[0], MACRO_LOAD);
|
||||
|
||||
macros.macros[1] = (char *)malloc(16);
|
||||
strcpy(macros.macros[1], MACRO_UNLOAD);
|
||||
|
||||
return macros;
|
||||
}
|
||||
|
||||
int BambuPrinter::get_macros_count()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool BambuPrinter::execute_macro(const char* macro)
|
||||
{
|
||||
if (strcmp(macro, MACRO_LOAD) == 0)
|
||||
{
|
||||
return publish_mqtt_command(COMMAND_FILAMENT_LOAD_EXTERNAL);
|
||||
}
|
||||
else if (strcmp(macro, MACRO_UNLOAD) == 0)
|
||||
{
|
||||
return publish_mqtt_command(COMMAND_FILAMENT_UNLOAD);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* WORK_LIGHT = "Work Light";
|
||||
const char* CHAMBER_LIGHT = "Chamber Light";
|
||||
|
||||
PowerDevices BambuPrinter::get_power_devices()
|
||||
{
|
||||
PowerDevices power_devices = {0};
|
||||
power_devices.success = true;
|
||||
int count = get_power_devices_count();
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return power_devices;
|
||||
}
|
||||
|
||||
power_devices.power_devices = (char **)malloc(sizeof(char *) * count);
|
||||
power_devices.power_states = (bool *)malloc(sizeof(bool) * count);
|
||||
|
||||
if (work_light_available)
|
||||
{
|
||||
power_devices.power_devices[power_devices.count] = (char *)malloc(10 + 1);
|
||||
strcpy(power_devices.power_devices[power_devices.count], WORK_LIGHT);
|
||||
power_devices.power_states[power_devices.count] = work_light_on;
|
||||
power_devices.count++;
|
||||
}
|
||||
|
||||
if (chamber_light_available)
|
||||
{
|
||||
power_devices.power_devices[power_devices.count] = (char *)malloc(13 + 1);
|
||||
strcpy(power_devices.power_devices[power_devices.count], CHAMBER_LIGHT);
|
||||
power_devices.power_states[power_devices.count] = chamber_light_on;
|
||||
power_devices.count++;
|
||||
}
|
||||
|
||||
return power_devices;
|
||||
}
|
||||
|
||||
int BambuPrinter::get_power_devices_count()
|
||||
{
|
||||
return (work_light_available ? 1 : 0) + (chamber_light_available ? 1 : 0);
|
||||
}
|
||||
|
||||
bool BambuPrinter::set_power_device_state(const char* device_name, bool state)
|
||||
{
|
||||
char buff[128] = {0};
|
||||
const char* device;
|
||||
|
||||
if (strcmp(device_name, WORK_LIGHT) == 0)
|
||||
{
|
||||
device = "work_light";
|
||||
}
|
||||
else if (strcmp(device_name, CHAMBER_LIGHT) == 0)
|
||||
{
|
||||
device = "chamber_light";
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sprintf(buff, COMMAND_LIGHTCTL, device, state ? "on" : "off");
|
||||
return publish_mqtt_command(buff);
|
||||
}
|
||||
|
||||
Files BambuPrinter::get_files()
|
||||
{
|
||||
PrinterState state = printer_data.state;
|
||||
disconnect();
|
||||
Files files = parse_files(wifi_client, 20);
|
||||
connect();
|
||||
printer_data.state = state;
|
||||
return files;
|
||||
}
|
||||
|
||||
Thumbnail BambuPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename)
|
||||
{
|
||||
Thumbnail thumbnail = {0};
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
bool BambuPrinter::set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature)
|
||||
{
|
||||
char gcode[64] = {0};
|
||||
|
||||
switch (device)
|
||||
{
|
||||
case PrinterTemperatureDeviceBed:
|
||||
sprintf(gcode, "M140 S%d", temperature);
|
||||
break;
|
||||
case PrinterTemperatureDeviceNozzle1:
|
||||
sprintf(gcode, "M104 S%d", temperature);
|
||||
break;
|
||||
default:
|
||||
LOG_F(("Unknown temperature device %d was requested to heat to %.2f", device, temperature));
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_gcode(gcode);
|
||||
}
|
||||
|
||||
bool BambuPrinter::send_gcode(const char* gcode, bool wait)
|
||||
{
|
||||
char* buff = (char *)malloc(strlen(gcode) + 70);
|
||||
sprintf(buff, COMMAND_SEND_GCODE, gcode);
|
||||
return publish_mqtt_command(buff);
|
||||
}
|
||||
|
||||
BambuConnectionStatus connection_test_bambu(PrinterConfiguration* config)
|
||||
{
|
||||
WiFiClientSecure connection_test_wifi_client;
|
||||
PubSubClient connection_test_client(connection_test_wifi_client);
|
||||
connection_test_wifi_client.setInsecure();
|
||||
connection_test_client.setServer(config->printer_host, 8883);
|
||||
char buff[10] = {0};
|
||||
sprintf(buff, "%d", config->klipper_port);
|
||||
if (!connection_test_client.connect("id", "bblp", buff))
|
||||
{
|
||||
LOG_LN("Bambu: Wrong IP or LAN code.");
|
||||
return BambuConnectionStatus::BambuConnectFail;
|
||||
}
|
||||
|
||||
char auth[48] = {0};
|
||||
sprintf(auth, "device/%s/report", config->printer_auth);
|
||||
|
||||
if (!connection_test_client.subscribe(auth))
|
||||
{
|
||||
LOG_LN("Bambu: Wrong serial number.");
|
||||
return BambuConnectionStatus::BambuConnectSNFail;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
connection_test_client.loop();
|
||||
|
||||
if (!connection_test_client.connected())
|
||||
{
|
||||
LOG_LN("Bambu: Connection lost. Likely wrong serial number.");
|
||||
return BambuConnectionStatus::BambuConnectSNFail;
|
||||
}
|
||||
|
||||
connection_test_client.disconnect();
|
||||
LOG_LN("Bambu: Connection test successful!");
|
||||
return BambuConnectionStatus::BambuConnectOk;
|
||||
}
|
||||
97
CYD-Klipper/src/core/bambu/bambu_printer_integration.hpp
Normal file
97
CYD-Klipper/src/core/bambu/bambu_printer_integration.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
#include "../printer_integration.hpp"
|
||||
#include <ArduinoJson.h>
|
||||
#include <WifiClientSecure.h>
|
||||
|
||||
enum BambuSpeedProfile
|
||||
{
|
||||
BambuSpeedProfileSilent = 1,
|
||||
BambuSpeedProfileNormal = 2,
|
||||
BambuSpeedProfileSport = 3,
|
||||
BambuSpeedProfileLudicrous = 4,
|
||||
};
|
||||
|
||||
class BambuPrinter : public BasePrinter
|
||||
{
|
||||
private:
|
||||
unsigned int last_error = 0;
|
||||
unsigned int ignore_error = 0;
|
||||
unsigned long print_start;
|
||||
|
||||
protected:
|
||||
void parse_state(JsonDocument& in);
|
||||
void init_ui_panels();
|
||||
Files parse_files(WiFiClientSecure& client, int max_files);
|
||||
|
||||
public:
|
||||
float aux_fan_speed;
|
||||
float chamber_fan_speed;
|
||||
BambuSpeedProfile speed_profile = BambuSpeedProfileNormal;
|
||||
|
||||
union {
|
||||
struct {
|
||||
bool chamber_light_available : 1;
|
||||
bool chamber_light_on : 1;
|
||||
bool work_light_available : 1;
|
||||
bool work_light_on : 1;
|
||||
bool has_ams : 1;
|
||||
};
|
||||
unsigned char bambu_misc;
|
||||
};
|
||||
|
||||
BambuPrinter(int index) : BasePrinter(index)
|
||||
{
|
||||
supported_features = PrinterFeatureHome
|
||||
| PrinterFeatureDisableSteppers
|
||||
| PrinterFeaturePause
|
||||
| PrinterFeatureResume
|
||||
| PrinterFeatureStop
|
||||
| PrinterFeatureEmergencyStop
|
||||
| PrinterFeatureCooldown
|
||||
| PrinterFeatureContinueError
|
||||
| PrinterFeatureExtrude
|
||||
| PrinterFeatureRetract
|
||||
| PrinterFeatureIgnoreError
|
||||
| PrinterFeatureRetryError;
|
||||
|
||||
supported_temperature_devices = PrinterTemperatureDeviceBed
|
||||
| PrinterTemperatureDeviceNozzle1;
|
||||
|
||||
popup_message_timeout_s = -1;
|
||||
bambu_misc = 0;
|
||||
printer_data.error_screen_features = PrinterFeatureRetryError | PrinterFeatureIgnoreError | PrinterFeatureContinueError;
|
||||
print_start = millis();
|
||||
|
||||
init_ui_panels();
|
||||
no_confirm_print_file = true;
|
||||
}
|
||||
|
||||
bool move_printer(const char* axis, float amount, bool relative);
|
||||
bool execute_feature(PrinterFeatures feature);
|
||||
bool connect();
|
||||
bool fetch();
|
||||
PrinterDataMinimal fetch_min();
|
||||
void disconnect();
|
||||
Macros get_macros();
|
||||
int get_macros_count();
|
||||
bool execute_macro(const char* macro);
|
||||
PowerDevices get_power_devices();
|
||||
int get_power_devices_count();
|
||||
bool set_power_device_state(const char* device_name, bool state);
|
||||
Files get_files();
|
||||
bool start_file(const char* filename);
|
||||
Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename);
|
||||
bool set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature);
|
||||
bool send_gcode(const char* gcode, bool wait = true);
|
||||
void receive_data(unsigned char* data, unsigned int length);
|
||||
bool publish_mqtt_command(const char* command);
|
||||
};
|
||||
|
||||
enum BambuConnectionStatus {
|
||||
BambuConnectFail = 0,
|
||||
BambuConnectOk = 1,
|
||||
BambuConnectSNFail = 2,
|
||||
};
|
||||
|
||||
BambuConnectionStatus connection_test_bambu(PrinterConfiguration* config);
|
||||
257
CYD-Klipper/src/core/bambu/bambu_printer_panels.cpp
Normal file
257
CYD-Klipper/src/core/bambu/bambu_printer_panels.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
#include "bambu_printer_integration.hpp"
|
||||
#include "lvgl.h"
|
||||
#include "../../ui/ui_utils.h"
|
||||
#include <stdio.h>
|
||||
#include "../common/constants.h"
|
||||
|
||||
const char* speed_profiles[] = { "Silent (50%)", "Normal (100%)", "Sport (124%)", "Ludicrous (166%)" };
|
||||
const BambuSpeedProfile speed_profile_values[] = { BambuSpeedProfileSilent, BambuSpeedProfileNormal, BambuSpeedProfileSport, BambuSpeedProfileLudicrous };
|
||||
const char* COMMAND_SET_PRINT_SPEED = "{\"print\":{\"command\":\"print_speed\",\"param\":\"%d\"}}";
|
||||
const char* COMMAND_START_PRINT_3MF = "{\"print\":{\"command\":\"project_file\",\"param\":\"Metadata/plate_1.gcode\",\"project_id\":\"0\",\"profile_id\":\"0\",\"task_id\":\"0\",\"subtask_id\":\"0\",\"subtask_name\":\"CYD-Klipper Print Job\",\"url\":\"file:///sdcard/%s\",\"timelapse\":%s,\"bed_type\":\"auto\",\"bed_leveling\":%s,\"flow_cali\":%s,\"vibration_cali\":%s,\"layer_inspect\":%s,\"ams_mapping\":[],\"use_ams\":%s}}";
|
||||
|
||||
enum FanIndex
|
||||
{
|
||||
PartFan = 1,
|
||||
AuxFan = 2,
|
||||
ChamberFan = 3,
|
||||
};
|
||||
|
||||
static void set_fan_speed_text(lv_event_t* e, FanIndex index)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[16];
|
||||
|
||||
float fan_speed = 0;
|
||||
const char* fan_type = "";
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case PartFan:
|
||||
fan_speed = get_current_printer_data()->fan_speed;
|
||||
fan_type = "P.Fan";
|
||||
break;
|
||||
case AuxFan:
|
||||
fan_speed = ((BambuPrinter*)get_current_printer)->aux_fan_speed;
|
||||
fan_type = "A.Fan";
|
||||
break;
|
||||
case ChamberFan:
|
||||
fan_speed = ((BambuPrinter*)get_current_printer)->chamber_fan_speed;
|
||||
fan_type = "C.Fan";
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(data, "%s: %.0f%%", fan_type, get_current_printer_data()->fan_speed * 100);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_fan_speed(lv_event_t* e, FanIndex index)
|
||||
{
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
int actual_speed = fan_percent_to_byte(speed);
|
||||
BambuPrinter* printer = (BambuPrinter*)get_current_printer(); // TODO: pass by ref
|
||||
char buff[20];
|
||||
sprintf(buff, "M106 P%d S%d", index, actual_speed);
|
||||
printer->send_gcode(buff);
|
||||
}
|
||||
|
||||
static void set_part_fan_speed_text(lv_event_t * e)
|
||||
{
|
||||
set_fan_speed_text(e, FanIndex::PartFan);
|
||||
}
|
||||
|
||||
static void set_part_fan_speed(lv_event_t * e)
|
||||
{
|
||||
set_fan_speed(e, FanIndex::PartFan);
|
||||
}
|
||||
|
||||
FAN_SPEED_COLUMN(set_part_fan_speed, part_fan_speed_columns)
|
||||
|
||||
static void set_aux_fan_speed_text(lv_event_t * e)
|
||||
{
|
||||
set_fan_speed_text(e, FanIndex::AuxFan);
|
||||
}
|
||||
|
||||
static void set_aux_fan_speed(lv_event_t * e)
|
||||
{
|
||||
set_fan_speed(e, FanIndex::AuxFan);
|
||||
}
|
||||
|
||||
FAN_SPEED_COLUMN(set_aux_fan_speed, aux_fan_speed_columns)
|
||||
|
||||
static void set_chamber_fan_speed_text(lv_event_t * e)
|
||||
{
|
||||
set_fan_speed_text(e, FanIndex::ChamberFan);
|
||||
}
|
||||
|
||||
static void set_chamber_fan_speed(lv_event_t * e)
|
||||
{
|
||||
set_fan_speed(e, FanIndex::ChamberFan);
|
||||
}
|
||||
|
||||
FAN_SPEED_COLUMN(set_chamber_fan_speed, chamber_fan_speed_columns)
|
||||
|
||||
// TODO: move to common
|
||||
static void set_speed_mult_text(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char buff[16];
|
||||
sprintf(buff, "Speed: %.0f%%", get_current_printer_data()->speed_mult * 100);
|
||||
lv_label_set_text(label, buff);
|
||||
}
|
||||
|
||||
static void set_speed_mult(lv_event_t * e)
|
||||
{
|
||||
BambuSpeedProfile speed = (BambuSpeedProfile)((int)lv_event_get_user_data(e));
|
||||
BambuPrinter* printer = (BambuPrinter*)get_current_printer(); // TODO: pass by ref
|
||||
char buff[128];
|
||||
|
||||
sprintf(buff, COMMAND_SET_PRINT_SPEED, speed);
|
||||
printer->publish_mqtt_command(buff);
|
||||
}
|
||||
|
||||
lv_button_column_t speed_profile_columns[] = {
|
||||
{ set_speed_mult, speed_profiles, (const void**)speed_profile_values, 4},
|
||||
};
|
||||
|
||||
static void open_part_fan_speed_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_part_fan_speed_text, part_fan_speed_columns, 3);
|
||||
}
|
||||
|
||||
static void open_aux_fan_speed_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_aux_fan_speed_text, aux_fan_speed_columns, 3);
|
||||
}
|
||||
|
||||
static void open_chamber_fan_speed_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_chamber_fan_speed_text, chamber_fan_speed_columns, 3);
|
||||
}
|
||||
|
||||
|
||||
static void open_speed_mult_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_speed_mult_text, speed_profile_columns, 1);
|
||||
}
|
||||
|
||||
static PrinterUiPanel bambu_ui_panels[4] {
|
||||
{ .set_label = (void*)set_speed_mult_text, .open_panel = (void*)open_speed_mult_panel },
|
||||
{ .set_label = (void*)set_part_fan_speed_text, .open_panel = (void*)open_part_fan_speed_panel },
|
||||
{ .set_label = (void*)set_chamber_fan_speed_text, .open_panel = (void*)open_chamber_fan_speed_panel },
|
||||
{ .set_label = (void*)set_aux_fan_speed_text, .open_panel = (void*)open_aux_fan_speed_panel },
|
||||
};
|
||||
|
||||
void BambuPrinter::init_ui_panels()
|
||||
{
|
||||
custom_menus_count = 4;
|
||||
custom_menus = bambu_ui_panels;
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
const char* bambu_current_file;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool bambu_option_use_ams : 1;
|
||||
bool bambu_option_timelapse : 1;
|
||||
bool bambu_option_bed_leveling : 1;
|
||||
bool bambu_option_flow_calibration : 1;
|
||||
bool bambu_option_vibration_compensation : 1;
|
||||
bool bambu_option_layer_inspect : 1;
|
||||
};
|
||||
unsigned char bambu_options_raw;
|
||||
};
|
||||
} __internal_bambu_file_state = {};
|
||||
|
||||
#define SET_BOOL_STATE(bool_name, func_name) static void func_name (lv_event_t * e) { auto state = lv_obj_get_state(lv_event_get_target(e)); bool_name = (state & LV_STATE_CHECKED == LV_STATE_CHECKED); }
|
||||
|
||||
SET_BOOL_STATE(__internal_bambu_file_state.bambu_option_use_ams, set_bambu_option_use_ams)
|
||||
SET_BOOL_STATE(__internal_bambu_file_state.bambu_option_timelapse, set_bambu_option_timelapse)
|
||||
SET_BOOL_STATE(__internal_bambu_file_state.bambu_option_bed_leveling, set_bambu_option_bed_leveling)
|
||||
SET_BOOL_STATE(__internal_bambu_file_state.bambu_option_flow_calibration, set_bambu_option_flow_calibration)
|
||||
SET_BOOL_STATE(__internal_bambu_file_state.bambu_option_vibration_compensation, set_bambu_option_vibration_compensation)
|
||||
SET_BOOL_STATE(__internal_bambu_file_state.bambu_option_layer_inspect, set_bambu_option_layer_inspect)
|
||||
|
||||
#define BOOLEAN_TO_STRING(b) b ? "true" : "false"
|
||||
|
||||
static void print_file_start(lv_event_t * e)
|
||||
{
|
||||
BambuPrinter* printer = (BambuPrinter*)get_current_printer();
|
||||
char buff[713];
|
||||
|
||||
if (snprintf(buff, 713, COMMAND_START_PRINT_3MF,
|
||||
__internal_bambu_file_state.bambu_current_file,
|
||||
BOOLEAN_TO_STRING(__internal_bambu_file_state.bambu_option_timelapse),
|
||||
BOOLEAN_TO_STRING(__internal_bambu_file_state.bambu_option_bed_leveling),
|
||||
BOOLEAN_TO_STRING(__internal_bambu_file_state.bambu_option_flow_calibration),
|
||||
BOOLEAN_TO_STRING(__internal_bambu_file_state.bambu_option_vibration_compensation),
|
||||
BOOLEAN_TO_STRING(__internal_bambu_file_state.bambu_option_layer_inspect),
|
||||
BOOLEAN_TO_STRING(__internal_bambu_file_state.bambu_option_use_ams)) >= 712)
|
||||
{
|
||||
LOG_LN("Failed to prepare message to start print");
|
||||
return;
|
||||
}
|
||||
|
||||
printer->publish_mqtt_command(buff);
|
||||
}
|
||||
|
||||
bool BambuPrinter::start_file(const char* filename){
|
||||
if (get_current_printer_data()->state != PrinterState::PrinterStateIdle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
__internal_bambu_file_state.bambu_current_file = filename;
|
||||
|
||||
lv_obj_t * panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_style_pad_all(panel, CYD_SCREEN_GAP_PX * 2, 0);
|
||||
lv_layout_flex_column(panel);
|
||||
lv_obj_set_size(panel, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 3, CYD_SCREEN_HEIGHT_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
lv_obj_align(panel, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
lv_obj_t * label_print_file = lv_label_create(panel);
|
||||
lv_obj_set_width(label_print_file, LV_PCT(100));
|
||||
lv_label_set_long_mode(label_print_file, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_label_set_text_fmt(label_print_file, "Settings for %s", __internal_bambu_file_state.bambu_current_file);
|
||||
|
||||
__internal_bambu_file_state.bambu_option_use_ams = ((BambuPrinter*)get_current_printer())->has_ams;
|
||||
__internal_bambu_file_state.bambu_option_timelapse = false;
|
||||
__internal_bambu_file_state.bambu_option_bed_leveling = true;
|
||||
__internal_bambu_file_state.bambu_option_flow_calibration = true;
|
||||
__internal_bambu_file_state.bambu_option_vibration_compensation = true;
|
||||
__internal_bambu_file_state.bambu_option_layer_inspect = true;
|
||||
|
||||
if (__internal_bambu_file_state.bambu_option_use_ams)
|
||||
{
|
||||
lv_create_custom_menu_switch("Use AMS", panel, set_bambu_option_use_ams, __internal_bambu_file_state.bambu_option_use_ams);
|
||||
}
|
||||
|
||||
lv_create_custom_menu_switch("Timelapse", panel, set_bambu_option_timelapse, __internal_bambu_file_state.bambu_option_timelapse);
|
||||
lv_create_custom_menu_switch("Bed Leveling", panel, set_bambu_option_bed_leveling, __internal_bambu_file_state.bambu_option_bed_leveling);
|
||||
lv_create_custom_menu_switch("Flow Calibration", panel, set_bambu_option_flow_calibration, __internal_bambu_file_state.bambu_option_flow_calibration);
|
||||
lv_create_custom_menu_switch("Vibration Compensation", panel, set_bambu_option_vibration_compensation, __internal_bambu_file_state.bambu_option_vibration_compensation);
|
||||
lv_create_custom_menu_switch("Inspect First Layer", panel, set_bambu_option_layer_inspect, __internal_bambu_file_state.bambu_option_layer_inspect);
|
||||
|
||||
lv_obj_t* buttons_panel = lv_create_empty_panel(panel);
|
||||
lv_layout_flex_row(buttons_panel);
|
||||
lv_obj_set_size(buttons_panel, LV_PCT(100), CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
|
||||
lv_obj_t* btn = lv_btn_create(buttons_panel);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, destroy_event_user_data, LV_EVENT_CLICKED, panel);
|
||||
|
||||
lv_obj_t* label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_CLOSE " Cancel");
|
||||
lv_obj_center(label);
|
||||
|
||||
btn = lv_btn_create(buttons_panel);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, print_file_start, LV_EVENT_CLICKED, panel);
|
||||
lv_obj_add_event_cb(btn, destroy_event_user_data, LV_EVENT_CLICKED, panel);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_OK " Print");
|
||||
lv_obj_center(label);
|
||||
|
||||
return true;
|
||||
}
|
||||
398
CYD-Klipper/src/core/bambu/bambu_printer_parsers.cpp
Normal file
398
CYD-Klipper/src/core/bambu/bambu_printer_parsers.cpp
Normal file
@@ -0,0 +1,398 @@
|
||||
#include "bambu_printer_integration.hpp"
|
||||
#include <HTTPClient.h>
|
||||
#include <list>
|
||||
|
||||
#define BIT_X_AXIS_HOMED BIT(0)
|
||||
#define BIT_Y_AXIS_HOMED BIT(1)
|
||||
#define BIT_Z_AXIS_HOMED BIT(2)
|
||||
|
||||
float convert_fan_speed(const char* in)
|
||||
{
|
||||
if (in == NULL || strlen(in) <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int part_value = atoi(in);
|
||||
float percentage = (part_value / 15.0f) * 100;
|
||||
return round(percentage / 10) / 10;
|
||||
}
|
||||
|
||||
void BambuPrinter::parse_state(JsonDocument& in)
|
||||
{
|
||||
if (!in.containsKey("print"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject print = in["print"];
|
||||
|
||||
if (print.containsKey("print_error"))
|
||||
{
|
||||
unsigned int error = print["print_error"].as<unsigned int>();
|
||||
if (error != last_error)
|
||||
{
|
||||
last_error = error;
|
||||
|
||||
if (error > 0)
|
||||
{
|
||||
HTTPClient client;
|
||||
client.setTimeout(1000);
|
||||
client.setConnectTimeout(1000);
|
||||
|
||||
LOG_F(("Free heap: %d bytes\n", esp_get_free_heap_size()))
|
||||
|
||||
char buff[10] = {0};
|
||||
sprintf(buff, "%X_%X", error >> 16, error & 0xFFFF);
|
||||
int http_status_code = 0;
|
||||
|
||||
try
|
||||
{
|
||||
client.begin("http://bambu.suchmeme.nl/" + String(buff));
|
||||
LOG_F(("Sending request to http://bambu.suchmeme.nl/%s", buff));
|
||||
http_status_code = client.GET();
|
||||
LOG_F(("Response: %d", http_status_code));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_LN("Error downloading error code page");
|
||||
}
|
||||
|
||||
if (http_status_code == 200)
|
||||
{
|
||||
printer_data.state_message = (char *)malloc(client.getSize() + 20);
|
||||
sprintf(printer_data.state_message, "%s: %s", buff, client.getString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
printer_data.state_message = (char *)malloc(20);
|
||||
sprintf(printer_data.state_message, "Error: %s", buff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (print.containsKey("nozzle_temper"))
|
||||
{
|
||||
printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] = print["nozzle_temper"];
|
||||
printer_data.can_extrude = printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] >= MIN_EXTRUDER_EXTRUDE_TEMP;
|
||||
}
|
||||
|
||||
if (print.containsKey("nozzle_target_temper"))
|
||||
{
|
||||
printer_data.target_temperatures[PrinterTemperatureDeviceIndexNozzle1] = print["nozzle_target_temper"];
|
||||
}
|
||||
|
||||
if (print.containsKey("bed_temper"))
|
||||
{
|
||||
printer_data.temperatures[PrinterTemperatureDeviceIndexBed] = print["bed_temper"];
|
||||
}
|
||||
|
||||
if (print.containsKey("bed_target_temper"))
|
||||
{
|
||||
printer_data.target_temperatures[PrinterTemperatureDeviceIndexBed] = print["bed_target_temper"];
|
||||
}
|
||||
|
||||
if (print.containsKey("spd_lvl"))
|
||||
{
|
||||
int speed_profile_int = print["spd_lvl"];
|
||||
speed_profile = (BambuSpeedProfile)speed_profile_int;
|
||||
|
||||
switch (speed_profile)
|
||||
{
|
||||
case BambuSpeedProfileSilent:
|
||||
printer_data.speed_mult = 0.5f;
|
||||
break;
|
||||
case BambuSpeedProfileNormal:
|
||||
printer_data.speed_mult = 1.0f;
|
||||
break;
|
||||
case BambuSpeedProfileSport:
|
||||
printer_data.speed_mult = 1.24f;
|
||||
break;
|
||||
case BambuSpeedProfileLudicrous:
|
||||
printer_data.speed_mult = 1.66f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (print.containsKey("home_flag"))
|
||||
{
|
||||
unsigned int home_flag = print["home_flag"].as<unsigned int>();
|
||||
printer_data.homed_axis = (home_flag & (BIT_X_AXIS_HOMED | BIT_Y_AXIS_HOMED | BIT_Z_AXIS_HOMED)) == (BIT_X_AXIS_HOMED | BIT_Y_AXIS_HOMED | BIT_Z_AXIS_HOMED);
|
||||
}
|
||||
|
||||
if (last_error > 0 && last_error != ignore_error)
|
||||
{
|
||||
printer_data.state = PrinterState::PrinterStateError;
|
||||
}
|
||||
else if (print.containsKey("gcode_state"))
|
||||
{
|
||||
const char* state = print["gcode_state"];
|
||||
|
||||
if (strcasecmp(state, "pause") == 0)
|
||||
{
|
||||
printer_data.state = PrinterState::PrinterStatePaused;
|
||||
}
|
||||
else if (strcasecmp(state, "running") == 0 || strcasecmp(state, "prepare") == 0)
|
||||
{
|
||||
printer_data.state = PrinterState::PrinterStatePrinting;
|
||||
}
|
||||
else
|
||||
{
|
||||
printer_data.state = PrinterState::PrinterStateIdle;
|
||||
}
|
||||
}
|
||||
|
||||
if (print.containsKey("mc_remaining_time"))
|
||||
{
|
||||
printer_data.remaining_time_s = print["mc_remaining_time"];
|
||||
printer_data.remaining_time_s *= 60;
|
||||
if (printer_data.remaining_time_s > 300)
|
||||
{
|
||||
print_start = millis() - (printer_data.remaining_time_s / (1 - printer_data.print_progress) * printer_data.print_progress * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (print.containsKey("mc_percent"))
|
||||
{
|
||||
printer_data.print_progress = print["mc_percent"];
|
||||
printer_data.print_progress /= 100;
|
||||
}
|
||||
|
||||
if (printer_data.state == PrinterState::PrinterStatePrinting)
|
||||
{
|
||||
printer_data.elapsed_time_s = (millis() - print_start) / 1000;
|
||||
}
|
||||
|
||||
if (print.containsKey("layer_num"))
|
||||
{
|
||||
printer_data.current_layer = print["layer_num"];
|
||||
}
|
||||
|
||||
if (print.containsKey("total_layer_num"))
|
||||
{
|
||||
printer_data.total_layers = print["total_layer_num"];
|
||||
}
|
||||
|
||||
if (print.containsKey("lights_report"))
|
||||
{
|
||||
for (JsonObject lights : print["lights_report"].as<JsonArray>())
|
||||
{
|
||||
if (lights.containsKey("node") && lights.containsKey("mode"))
|
||||
{
|
||||
bool mode = !(lights["mode"] == "off");
|
||||
const char* node = lights["node"];
|
||||
|
||||
if (node == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(node, "chamber_light") == 0)
|
||||
{
|
||||
chamber_light_available = true;
|
||||
chamber_light_on = mode;
|
||||
}
|
||||
else if (strcmp(node, "work_light") == 0)
|
||||
{
|
||||
work_light_available = true;
|
||||
work_light_on = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (print.containsKey("gcode_file"))
|
||||
{
|
||||
const char* filename = print["gcode_file"];
|
||||
|
||||
if (filename != NULL && (printer_data.print_filename == NULL || strcmp(printer_data.print_filename, filename)))
|
||||
{
|
||||
printer_data.print_filename = (char *)malloc(strlen(filename) + 1);
|
||||
strcpy(printer_data.print_filename, filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (print.containsKey("cooling_fan_speed"))
|
||||
{
|
||||
printer_data.fan_speed = convert_fan_speed(print["cooling_fan_speed"]);
|
||||
}
|
||||
|
||||
if (print.containsKey("big_fan1_speed"))
|
||||
{
|
||||
aux_fan_speed = convert_fan_speed(print["big_fan1_speed"]);
|
||||
}
|
||||
|
||||
if (print.containsKey("big_fan2_speed"))
|
||||
{
|
||||
chamber_fan_speed = convert_fan_speed(print["big_fan2_speed"]);
|
||||
}
|
||||
|
||||
if (print.containsKey("ams_exist_bits"))
|
||||
{
|
||||
const char* ams_exists = print["ams_exist_bits"];
|
||||
if (!strcmp(ams_exists, "0"))
|
||||
{
|
||||
has_ams = true;
|
||||
}
|
||||
}
|
||||
|
||||
printer_data.extrude_mult = 1;
|
||||
}
|
||||
|
||||
// Derived from https://github.com/ldab/ESP32_FTPClient/blob/master/src/ESP32_FTPClient.cpp
|
||||
bool wifi_client_response_pass(WiFiClientSecure& client)
|
||||
{
|
||||
unsigned long _m = millis();
|
||||
bool first_char = true;
|
||||
while (!client.available() && millis() < _m + 500) delay(1);
|
||||
|
||||
if(!client.available())
|
||||
{
|
||||
LOG_LN("FTPS: No response from server");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_LN("[FTPS response]");
|
||||
bool response = true;
|
||||
while (client.available())
|
||||
{
|
||||
char byte = client.read();
|
||||
|
||||
if (first_char && (byte == '4' || byte == '5'))
|
||||
{
|
||||
LOG_LN("FTPS: Server returned an error");
|
||||
response = false;
|
||||
}
|
||||
|
||||
first_char = false;
|
||||
|
||||
LOG_F(("%c", byte));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
bool wifi_client_response_parse(WiFiClientSecure& client, std::list<char*> &files, int max_files)
|
||||
{
|
||||
unsigned long _m = millis();
|
||||
while (!client.available() && millis() < _m + 500) delay(1);
|
||||
|
||||
if(!client.available())
|
||||
{
|
||||
LOG_LN("FTPS: No response from server");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_LN("[FTPS response]");
|
||||
char buff[128] = {0};
|
||||
int index = 0;
|
||||
while (client.available()) {
|
||||
int byte = client.read();
|
||||
LOG_F(("%c", byte));
|
||||
buff[index] = byte;
|
||||
|
||||
if (byte == '\n' || byte == '\r' || byte <= 0)
|
||||
{
|
||||
buff[index] = 0;
|
||||
if (index > 10)
|
||||
{
|
||||
char* file = (char*)malloc(index + 1);
|
||||
|
||||
if (file != NULL)
|
||||
{
|
||||
strcpy(file, buff);
|
||||
files.push_front(file);
|
||||
|
||||
if (files.size() > max_files)
|
||||
{
|
||||
auto last_entry = files.back();
|
||||
|
||||
if (last_entry != NULL)
|
||||
free(last_entry);
|
||||
|
||||
files.pop_back();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_LN("Failed to allocate memory");
|
||||
}
|
||||
}
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send_command_without_response(WiFiClientSecure& client, const char* command)
|
||||
{
|
||||
client.println(command);
|
||||
LOG_F(("[FTPS Command] %s\n", command));
|
||||
return wifi_client_response_pass(client);
|
||||
}
|
||||
|
||||
// TODO: This isn't a 'pure' parser implementation. Remove network calls, only do parsing
|
||||
Files BambuPrinter::parse_files(WiFiClientSecure& wifi_client, int max_files)
|
||||
{
|
||||
LOG_F(("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size()));
|
||||
|
||||
unsigned long timer_request = millis();
|
||||
Files result = {0};
|
||||
|
||||
if (!wifi_client.connect(printer_config->printer_host, 990))
|
||||
{
|
||||
LOG_LN("Failed to fetch files: connection failed");
|
||||
}
|
||||
|
||||
wifi_client_response_pass(wifi_client);
|
||||
|
||||
char auth_code_buff[16] = {0};
|
||||
sprintf(auth_code_buff, "PASS %d", printer_config->klipper_port);
|
||||
send_command_without_response(wifi_client, "USER bblp");
|
||||
wifi_client_response_pass(wifi_client);
|
||||
send_command_without_response(wifi_client, auth_code_buff);
|
||||
send_command_without_response(wifi_client, "PASV");
|
||||
send_command_without_response(wifi_client, "NLST");
|
||||
wifi_client.stop();
|
||||
|
||||
if (wifi_client.connect(printer_config->printer_host, 2024))
|
||||
{
|
||||
unsigned long timer_parse = millis();
|
||||
std::list<char*> files;
|
||||
wifi_client_response_parse(wifi_client, files, max_files);
|
||||
result.available_files = (char**)malloc(sizeof(char*) * files.size());
|
||||
if (result.available_files == NULL)
|
||||
{
|
||||
LOG_LN("Failed to allocate memory");
|
||||
|
||||
for (auto file : files){
|
||||
free(file);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto file : files){
|
||||
result.available_files[result.count++] = file;
|
||||
}
|
||||
|
||||
result.success = true;
|
||||
LOG_F(("Heap space post-file-parse: %d bytes\n", esp_get_free_heap_size()))
|
||||
LOG_F(("Got %d files. Request took %dms, parsing took %dms\n", files.size(), timer_parse - timer_request, millis() - timer_parse))
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_LN("Failed to fetch files: data connection failed");
|
||||
}
|
||||
|
||||
wifi_client.stop();
|
||||
return result;
|
||||
}
|
||||
15
CYD-Klipper/src/core/common/constants.cpp
Normal file
15
CYD-Klipper/src/core/common/constants.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "constants.h"
|
||||
|
||||
const char* fan_speeds_col_1[] = { "On\n100%", "Off\n0%" };
|
||||
const int fan_speeds_col_1_values[] = { 100, 0 };
|
||||
|
||||
const char* fan_speeds_col_2[] = { "10%", "20%", "30%", "40%", "50%"};
|
||||
const int fan_speeds_col_2_values[] = { 10, 20, 30, 40, 50 };
|
||||
|
||||
const char* fan_speeds_col_3[] = { "60%", "70%", "80%", "90%"};
|
||||
const int fan_speeds_col_3_values[] = { 60, 70, 80, 90 };
|
||||
|
||||
unsigned char fan_percent_to_byte(int percent)
|
||||
{
|
||||
return percent * 255 / 100;
|
||||
}
|
||||
14
CYD-Klipper/src/core/common/constants.h
Normal file
14
CYD-Klipper/src/core/common/constants.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
extern const char* fan_speeds_col_1[];
|
||||
extern const int fan_speeds_col_1_values[];
|
||||
|
||||
extern const char* fan_speeds_col_2[];
|
||||
extern const int fan_speeds_col_2_values[];
|
||||
|
||||
extern const char* fan_speeds_col_3[];
|
||||
extern const int fan_speeds_col_3_values[];
|
||||
|
||||
unsigned char fan_percent_to_byte(int percent);
|
||||
|
||||
#define FAN_SPEED_COLUMN(set_fan_speed, column_name) lv_button_column_t column_name[] = {{ set_fan_speed, fan_speeds_col_2, (const void**)fan_speeds_col_2_values, 5},{ set_fan_speed, fan_speeds_col_3, (const void**)fan_speeds_col_3_values, 4}, { set_fan_speed, fan_speeds_col_1, (const void**)fan_speeds_col_1_values, 2}};
|
||||
99
CYD-Klipper/src/core/current_printer.cpp
Normal file
99
CYD-Klipper/src/core/current_printer.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "current_printer.h"
|
||||
#include "semaphore.h"
|
||||
|
||||
bool current_printer_move_printer(const char* axis, float amount, bool relative)
|
||||
{
|
||||
freeze_request_thread();
|
||||
bool result = get_current_printer()->move_printer(axis, amount, relative);
|
||||
unfreeze_request_thread();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool current_printer_execute_feature(PrinterFeatures feature)
|
||||
{
|
||||
freeze_request_thread();
|
||||
bool result = get_current_printer()->execute_feature(feature);
|
||||
unfreeze_request_thread();
|
||||
return result;
|
||||
}
|
||||
|
||||
Macros current_printer_get_macros()
|
||||
{
|
||||
freeze_request_thread();
|
||||
Macros macros = get_current_printer()->get_macros();
|
||||
unfreeze_request_thread();
|
||||
return macros;
|
||||
}
|
||||
|
||||
int current_printer_get_macros_count()
|
||||
{
|
||||
freeze_request_thread();
|
||||
int count = get_current_printer()->get_macros_count();
|
||||
unfreeze_request_thread();
|
||||
return count;
|
||||
}
|
||||
|
||||
bool current_printer_execute_macro(const char* macro)
|
||||
{
|
||||
freeze_request_thread();
|
||||
bool result = get_current_printer()->execute_macro(macro);
|
||||
unfreeze_request_thread();
|
||||
return result;
|
||||
}
|
||||
|
||||
PowerDevices current_printer_get_power_devices()
|
||||
{
|
||||
freeze_request_thread();
|
||||
PowerDevices power_devices = get_current_printer()->get_power_devices();
|
||||
unfreeze_request_thread();
|
||||
return power_devices;
|
||||
}
|
||||
|
||||
int current_printer_get_power_devices_count()
|
||||
{
|
||||
freeze_request_thread();
|
||||
int count = get_current_printer()->get_power_devices_count();
|
||||
unfreeze_request_thread();
|
||||
return count;
|
||||
}
|
||||
|
||||
bool current_printer_set_power_device_state(const char* device_name, bool state)
|
||||
{
|
||||
freeze_request_thread();
|
||||
bool result = get_current_printer()->set_power_device_state(device_name, state);
|
||||
unfreeze_request_thread();
|
||||
return result;
|
||||
}
|
||||
|
||||
Files current_printer_get_files()
|
||||
{
|
||||
freeze_request_thread();
|
||||
Files files = get_current_printer()->get_files();
|
||||
unfreeze_request_thread();
|
||||
return files;
|
||||
}
|
||||
|
||||
bool current_printer_start_file(const char* filename)
|
||||
{
|
||||
freeze_request_thread();
|
||||
bool result = get_current_printer()->start_file(filename);
|
||||
unfreeze_request_thread();
|
||||
return result;
|
||||
}
|
||||
|
||||
Thumbnail current_printer_get_32_32_png_image_thumbnail(const char* gcode_filename)
|
||||
{
|
||||
freeze_request_thread();
|
||||
Thumbnail thumbnail = get_current_printer()->get_32_32_png_image_thumbnail(gcode_filename);
|
||||
unfreeze_request_thread();
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
bool current_printer_set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature)
|
||||
{
|
||||
freeze_request_thread();
|
||||
bool result = get_current_printer()->set_target_temperature(device, temperature);
|
||||
unfreeze_request_thread();
|
||||
return result;
|
||||
}
|
||||
|
||||
15
CYD-Klipper/src/core/current_printer.h
Normal file
15
CYD-Klipper/src/core/current_printer.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "printer_integration.hpp"
|
||||
|
||||
bool current_printer_move_printer(const char* axis, float amount, bool relative);
|
||||
bool current_printer_execute_feature(PrinterFeatures feature);
|
||||
Macros current_printer_get_macros();
|
||||
int current_printer_get_macros_count();
|
||||
bool current_printer_execute_macro(const char* macro);
|
||||
PowerDevices current_printer_get_power_devices();
|
||||
int current_printer_get_power_devices_count();
|
||||
bool current_printer_set_power_device_state(const char* device_name, bool state);
|
||||
Files current_printer_get_files();
|
||||
bool current_printer_start_file(const char* filename);
|
||||
Thumbnail current_printer_get_32_32_png_image_thumbnail(const char* gcode_filename);
|
||||
bool current_printer_set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature);
|
||||
@@ -1,428 +1,56 @@
|
||||
|
||||
#include "data_setup.h"
|
||||
#include "lvgl.h"
|
||||
#include "../conf/global_config.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include "semaphore.h"
|
||||
#include <esp_task_wdt.h>
|
||||
#include "macros_query.h"
|
||||
#include <UrlEncode.h>
|
||||
#include "http_client.h"
|
||||
#include "../ui/ui_utils.h"
|
||||
#include "macros_query.h"
|
||||
#include "printer_integration.hpp"
|
||||
#include "klipper/klipper_printer_integration.hpp"
|
||||
#include "klipper-serial/serial_klipper_printer_integration.hpp"
|
||||
#include "bambu/bambu_printer_integration.hpp"
|
||||
#include "octoprint/octoprint_printer_integration.hpp"
|
||||
|
||||
Printer printer = {0};
|
||||
PrinterMinimal *printer_minimal;
|
||||
int klipper_request_consecutive_fail_count = 999;
|
||||
char filename_buff[512] = {0};
|
||||
SemaphoreHandle_t freezeRenderThreadSemaphore, freezeRequestThreadSemaphore;
|
||||
const long data_update_interval = 780;
|
||||
unsigned char lock_absolute_relative_mode_swap = 0;
|
||||
|
||||
void semaphore_init(){
|
||||
freezeRenderThreadSemaphore = xSemaphoreCreateMutex();
|
||||
freezeRequestThreadSemaphore = xSemaphoreCreateMutex();
|
||||
xSemaphoreGive(freezeRenderThreadSemaphore);
|
||||
xSemaphoreGive(freezeRequestThreadSemaphore);
|
||||
}
|
||||
|
||||
void freeze_request_thread(){
|
||||
xSemaphoreTake(freezeRequestThreadSemaphore, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void unfreeze_request_thread(){
|
||||
xSemaphoreGive(freezeRequestThreadSemaphore);
|
||||
}
|
||||
|
||||
void freeze_render_thread(){
|
||||
xSemaphoreTake(freezeRenderThreadSemaphore, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void unfreeze_render_thread(){
|
||||
xSemaphoreGive(freezeRenderThreadSemaphore);
|
||||
}
|
||||
|
||||
void send_gcode(bool wait, const char *gcode)
|
||||
{
|
||||
Serial.printf("Sending gcode: %s\n", gcode);
|
||||
|
||||
SETUP_HTTP_CLIENT_FULL("/printer/gcode/script?script=" + urlEncode(gcode), false, wait ? 5000 : 750);
|
||||
try
|
||||
{
|
||||
client.GET();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Serial.println("Failed to send gcode");
|
||||
}
|
||||
}
|
||||
|
||||
int get_slicer_time_estimate_s()
|
||||
{
|
||||
if (printer.state == PRINTER_STATE_IDLE)
|
||||
return 0;
|
||||
|
||||
delay(10);
|
||||
|
||||
SETUP_HTTP_CLIENT("/server/files/metadata?filename=" + urlEncode(printer.print_filename));
|
||||
|
||||
int httpCode = client.GET();
|
||||
|
||||
if (httpCode != 200)
|
||||
return 0;
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
int time_estimate_s = doc["result"]["estimated_time"];
|
||||
Serial.printf("Got slicer time estimate: %ds\n", time_estimate_s);
|
||||
return time_estimate_s;
|
||||
}
|
||||
|
||||
void move_printer(const char* axis, float amount, bool relative) {
|
||||
if (!printer.homed_axis || printer.state == PRINTER_STATE_PRINTING)
|
||||
return;
|
||||
|
||||
char gcode[64];
|
||||
const char* extra = (amount > 0) ? "+" : "";
|
||||
const char* start = "";
|
||||
const char* end = "";
|
||||
|
||||
bool absolute_coords = printer.absolute_coords;
|
||||
|
||||
if (absolute_coords && relative) {
|
||||
start = "G91\n";
|
||||
}
|
||||
else if (!absolute_coords && !relative) {
|
||||
start = "G90\n";
|
||||
}
|
||||
|
||||
if (absolute_coords && relative) {
|
||||
end = "\nG90";
|
||||
}
|
||||
else if (!absolute_coords && !relative) {
|
||||
end = "\nG91";
|
||||
}
|
||||
|
||||
sprintf(gcode, "%sG1 %s%s%.3f F6000%s", start, axis, extra, amount, end);
|
||||
send_gcode(true, gcode);
|
||||
|
||||
lock_absolute_relative_mode_swap = 2;
|
||||
}
|
||||
|
||||
int last_slicer_time_query = -15000;
|
||||
|
||||
void fetch_printer_data()
|
||||
{
|
||||
freeze_request_thread();
|
||||
PRINTER_CONFIG *config = get_current_printer_config();
|
||||
SETUP_HTTP_CLIENT("/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks&fan&display_status")
|
||||
|
||||
int httpCode = client.GET();
|
||||
delay(10);
|
||||
if (httpCode == 200)
|
||||
if (get_current_printer_data()->state == PrinterStateOffline)
|
||||
{
|
||||
int printer_state = printer.state;
|
||||
|
||||
if (printer.state == PRINTER_STATE_OFFLINE)
|
||||
if (!get_current_printer()->connect())
|
||||
{
|
||||
printer.state = PRINTER_STATE_ERROR;
|
||||
LOG_LN("Failed to connect to printer");
|
||||
unfreeze_request_thread();
|
||||
return;
|
||||
}
|
||||
|
||||
klipper_request_consecutive_fail_count = 0;
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
auto status = doc["result"]["status"];
|
||||
bool emit_state_update = false;
|
||||
|
||||
delay(10);
|
||||
unfreeze_request_thread();
|
||||
freeze_render_thread();
|
||||
|
||||
if (status.containsKey("webhooks"))
|
||||
{
|
||||
const char *state = status["webhooks"]["state"];
|
||||
const char *message = status["webhooks"]["state_message"];
|
||||
|
||||
if (strcmp(state, "ready") == 0 && printer.state == PRINTER_STATE_ERROR)
|
||||
{
|
||||
printer_state = PRINTER_STATE_IDLE;
|
||||
}
|
||||
else if ((strcmp(state, "shutdown") == 0 || strcmp(state, "error") == 0) && printer.state != PRINTER_STATE_ERROR)
|
||||
{
|
||||
printer_state = PRINTER_STATE_ERROR;
|
||||
}
|
||||
|
||||
if (printer.state_message == NULL || strcmp(printer.state_message, message))
|
||||
{
|
||||
if (printer.state_message != NULL)
|
||||
{
|
||||
free(printer.state_message);
|
||||
}
|
||||
|
||||
printer.state_message = (char *)malloc(strlen(message) + 1);
|
||||
strcpy(printer.state_message, message);
|
||||
emit_state_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_state != PRINTER_STATE_ERROR)
|
||||
{
|
||||
if (status.containsKey("extruder"))
|
||||
{
|
||||
printer.extruder_temp = status["extruder"]["temperature"];
|
||||
printer.extruder_target_temp = status["extruder"]["target"];
|
||||
bool can_extrude = status["extruder"]["can_extrude"];
|
||||
printer.pressure_advance = status["extruder"]["pressure_advance"];
|
||||
printer.smooth_time = status["extruder"]["smooth_time"];
|
||||
printer.can_extrude = can_extrude == true;
|
||||
}
|
||||
|
||||
if (status.containsKey("heater_bed"))
|
||||
{
|
||||
printer.bed_temp = status["heater_bed"]["temperature"];
|
||||
printer.bed_target_temp = status["heater_bed"]["target"];
|
||||
}
|
||||
|
||||
if (status.containsKey("toolhead"))
|
||||
{
|
||||
const char *homed_axis = status["toolhead"]["homed_axes"];
|
||||
printer.homed_axis = strcmp(homed_axis, "xyz") == 0;
|
||||
}
|
||||
|
||||
if (status.containsKey("gcode_move"))
|
||||
{
|
||||
printer.position[0] = status["gcode_move"]["gcode_position"][0];
|
||||
printer.position[1] = status["gcode_move"]["gcode_position"][1];
|
||||
printer.position[2] = status["gcode_move"]["gcode_position"][2];
|
||||
printer.gcode_offset[0] = status["gcode_move"]["homing_origin"][0];
|
||||
printer.gcode_offset[1] = status["gcode_move"]["homing_origin"][1];
|
||||
printer.gcode_offset[2] = status["gcode_move"]["homing_origin"][2];
|
||||
bool absolute_coords = status["gcode_move"]["absolute_coordinates"];
|
||||
|
||||
if (lock_absolute_relative_mode_swap > 0)
|
||||
{
|
||||
lock_absolute_relative_mode_swap--;
|
||||
}
|
||||
else
|
||||
{
|
||||
printer.absolute_coords = absolute_coords == true;
|
||||
}
|
||||
|
||||
printer.speed_mult = status["gcode_move"]["speed_factor"];
|
||||
printer.extrude_mult = status["gcode_move"]["extrude_factor"];
|
||||
printer.feedrate_mm_per_s = status["gcode_move"]["speed"];
|
||||
printer.feedrate_mm_per_s /= 60; // convert mm/m to mm/s
|
||||
}
|
||||
|
||||
if (status.containsKey("fan"))
|
||||
{
|
||||
printer.fan_speed = status["fan"]["speed"];
|
||||
}
|
||||
|
||||
if (status.containsKey("virtual_sdcard"))
|
||||
{
|
||||
printer.print_progress = status["virtual_sdcard"]["progress"];
|
||||
}
|
||||
|
||||
if (status.containsKey("print_stats"))
|
||||
{
|
||||
const char *filename = status["print_stats"]["filename"];
|
||||
strcpy(filename_buff, filename == NULL ? "" : filename);
|
||||
printer.print_filename = filename_buff;
|
||||
printer.elapsed_time_s = status["print_stats"]["total_duration"];
|
||||
printer.printed_time_s = status["print_stats"]["print_duration"];
|
||||
printer.filament_used_mm = status["print_stats"]["filament_used"];
|
||||
printer.total_layers = status["print_stats"]["info"]["total_layer"];
|
||||
printer.current_layer = status["print_stats"]["info"]["current_layer"];
|
||||
|
||||
const char *state = status["print_stats"]["state"];
|
||||
|
||||
if (state == nullptr)
|
||||
{
|
||||
// Continue
|
||||
}
|
||||
else if (strcmp(state, "printing") == 0)
|
||||
{
|
||||
printer_state = PRINTER_STATE_PRINTING;
|
||||
}
|
||||
else if (strcmp(state, "paused") == 0)
|
||||
{
|
||||
printer_state = PRINTER_STATE_PAUSED;
|
||||
}
|
||||
else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0)
|
||||
{
|
||||
printer_state = PRINTER_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (status.containsKey("display_status"))
|
||||
{
|
||||
printer.print_progress = status["display_status"]["progress"];
|
||||
const char* message = status["display_status"]["message"];
|
||||
|
||||
if (!global_config.disable_m117_messaging)
|
||||
{
|
||||
lv_create_popup_message(message, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
if (printer.state == PRINTER_STATE_PRINTING && printer.print_progress > 0)
|
||||
{
|
||||
float remaining_time_s_percentage = (printer.printed_time_s / printer.print_progress) - printer.printed_time_s;
|
||||
float remaining_time_s_slicer = 0;
|
||||
|
||||
if (printer.slicer_estimated_print_time_s > 0)
|
||||
{
|
||||
remaining_time_s_slicer = printer.slicer_estimated_print_time_s - printer.printed_time_s;
|
||||
}
|
||||
|
||||
if (remaining_time_s_slicer <= 0 || config->remaining_time_calc_mode == REMAINING_TIME_CALC_PERCENTAGE)
|
||||
{
|
||||
printer.remaining_time_s = remaining_time_s_percentage;
|
||||
}
|
||||
else if (config->remaining_time_calc_mode == REMAINING_TIME_CALC_INTERPOLATED)
|
||||
{
|
||||
printer.remaining_time_s = remaining_time_s_percentage * printer.print_progress + remaining_time_s_slicer * (1 - printer.print_progress);
|
||||
}
|
||||
else if (config->remaining_time_calc_mode == REMAINING_TIME_CALC_SLICER)
|
||||
{
|
||||
printer.remaining_time_s = remaining_time_s_slicer;
|
||||
}
|
||||
}
|
||||
|
||||
if (printer.remaining_time_s < 0)
|
||||
{
|
||||
printer.remaining_time_s = 0;
|
||||
}
|
||||
|
||||
if (printer.state == PRINTER_STATE_IDLE)
|
||||
{
|
||||
printer.slicer_estimated_print_time_s = 0;
|
||||
}
|
||||
|
||||
lv_msg_send(DATA_PRINTER_DATA, &printer);
|
||||
}
|
||||
|
||||
if (printer.state != printer_state || emit_state_update)
|
||||
{
|
||||
printer.state = printer_state;
|
||||
lv_msg_send(DATA_PRINTER_STATE, &printer);
|
||||
}
|
||||
|
||||
if (printer.state == PRINTER_STATE_PRINTING && millis() - last_slicer_time_query > 30000 && printer.slicer_estimated_print_time_s <= 0)
|
||||
{
|
||||
delay(10);
|
||||
last_slicer_time_query = millis();
|
||||
printer.slicer_estimated_print_time_s = get_slicer_time_estimate_s();
|
||||
}
|
||||
|
||||
unfreeze_render_thread();
|
||||
}
|
||||
else
|
||||
|
||||
bool fetch_result = get_current_printer()->fetch();
|
||||
unfreeze_request_thread();
|
||||
|
||||
freeze_render_thread();
|
||||
if (!fetch_result)
|
||||
{
|
||||
unfreeze_request_thread();
|
||||
klipper_request_consecutive_fail_count++;
|
||||
|
||||
if (klipper_request_consecutive_fail_count == 5)
|
||||
{
|
||||
freeze_render_thread();
|
||||
printer.state = PRINTER_STATE_OFFLINE;
|
||||
lv_msg_send(DATA_PRINTER_STATE, &printer);
|
||||
unfreeze_render_thread();
|
||||
}
|
||||
|
||||
Serial.printf("Failed to fetch printer data: %d\n", httpCode);
|
||||
LOG_LN("Failed to fetch printer data")
|
||||
get_current_printer()->disconnect();
|
||||
}
|
||||
|
||||
get_current_printer()->AnnouncePrinterData();
|
||||
unfreeze_render_thread();
|
||||
}
|
||||
|
||||
void fetch_printer_data_minimal()
|
||||
{
|
||||
PrinterMinimal data[PRINTER_CONFIG_COUNT] = {0};
|
||||
|
||||
for (int i = 0; i < PRINTER_CONFIG_COUNT; i++){
|
||||
PRINTER_CONFIG *config = &global_config.printer_config[i];
|
||||
|
||||
if (!config->ip_configured)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_OFFLINE;
|
||||
continue;
|
||||
}
|
||||
|
||||
delay(10);
|
||||
HTTPClient client;
|
||||
configure_http_client(client, get_full_url("/printer/objects/query?webhooks&print_stats&virtual_sdcard", config), true, 1000);
|
||||
PrinterDataMinimal data[PRINTER_CONFIG_COUNT] = {{}};
|
||||
for (int i = 0; i < get_printer_count(); i++)
|
||||
{
|
||||
freeze_request_thread();
|
||||
|
||||
int httpCode = client.GET();
|
||||
delay(10);
|
||||
if (httpCode == 200)
|
||||
{
|
||||
if (data[i].state == PRINTER_STATE_OFFLINE)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_ERROR;
|
||||
}
|
||||
|
||||
data[i].power_devices = power_devices_count(config);
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
auto status = doc["result"]["status"];
|
||||
|
||||
unfreeze_request_thread();
|
||||
|
||||
if (status.containsKey("webhooks"))
|
||||
{
|
||||
const char *state = status["webhooks"]["state"];
|
||||
|
||||
if (strcmp(state, "ready") == 0 && data[i].state == PRINTER_STATE_ERROR)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_IDLE;
|
||||
}
|
||||
else if (strcmp(state, "shutdown") == 0 && data[i].state != PRINTER_STATE_ERROR)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[i].state != PRINTER_STATE_ERROR)
|
||||
{
|
||||
if (status.containsKey("virtual_sdcard"))
|
||||
{
|
||||
data[i].print_progress = status["virtual_sdcard"]["progress"];
|
||||
}
|
||||
|
||||
if (status.containsKey("print_stats"))
|
||||
{
|
||||
const char *state = status["print_stats"]["state"];
|
||||
|
||||
if (state == nullptr)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_ERROR;
|
||||
}
|
||||
else if (strcmp(state, "printing") == 0)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_PRINTING;
|
||||
}
|
||||
else if (strcmp(state, "paused") == 0)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_PAUSED;
|
||||
}
|
||||
else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0)
|
||||
{
|
||||
data[i].state = PRINTER_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data[i].state = PRINTER_STATE_OFFLINE;
|
||||
data[i].power_devices = power_devices_count(config);
|
||||
unfreeze_request_thread();
|
||||
}
|
||||
BasePrinter* printer = get_printer(i);
|
||||
unfreeze_request_thread();
|
||||
data[i] = printer->fetch_min();
|
||||
}
|
||||
|
||||
freeze_render_thread();
|
||||
memcpy(printer_minimal, data, sizeof(PrinterMinimal) * PRINTER_CONFIG_COUNT);
|
||||
lv_msg_send(DATA_PRINTER_MINIMAL, NULL);
|
||||
announce_printer_data_minimal(data);
|
||||
unfreeze_render_thread();
|
||||
}
|
||||
|
||||
@@ -453,11 +81,41 @@ TaskHandle_t background_loop;
|
||||
|
||||
void data_setup()
|
||||
{
|
||||
printer_minimal = (PrinterMinimal *)calloc(sizeof(PrinterMinimal), PRINTER_CONFIG_COUNT);
|
||||
semaphore_init();
|
||||
printer.print_filename = filename_buff;
|
||||
fetch_printer_data();
|
||||
BasePrinter** available_printers = (BasePrinter**)malloc(sizeof(BasePrinter*) * PRINTER_CONFIG_COUNT);
|
||||
int count = 0;
|
||||
int true_current_printer_index = 0;
|
||||
for (int i = 0; i < PRINTER_CONFIG_COUNT; i++)
|
||||
{
|
||||
if (global_config.printer_config[i].setup_complete)
|
||||
{
|
||||
if (global_config.printer_index == i)
|
||||
{
|
||||
true_current_printer_index = count;;
|
||||
}
|
||||
|
||||
switch (global_config.printer_config[i].printer_type)
|
||||
{
|
||||
case PrinterType::PrinterTypeKlipper:
|
||||
available_printers[count++] = new KlipperPrinter(i);
|
||||
break;
|
||||
case PrinterType::PrinterTypeBambuLocal:
|
||||
available_printers[count++] = new BambuPrinter(i);
|
||||
break;
|
||||
case PrinterType::PrinterTypeKlipperSerial:
|
||||
available_printers[count++] = new SerialKlipperPrinter(i);
|
||||
break;
|
||||
case PrinterType::PrinterTypeOctoprint:
|
||||
available_printers[count++] = new OctoPrinter(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initialize_printers(available_printers, count);
|
||||
set_current_printer(true_current_printer_index);
|
||||
LOG_F(("Free heap after printer creation: %d bytes\n", esp_get_free_heap_size()));
|
||||
semaphore_init();
|
||||
fetch_printer_data();
|
||||
freeze_render_thread();
|
||||
xTaskCreatePinnedToCore(data_loop_background, "data_loop_background", 5000, NULL, 2, &background_loop, 0);
|
||||
}
|
||||
|
||||
@@ -1,61 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
enum {
|
||||
PRINTER_STATE_OFFLINE = 0,
|
||||
PRINTER_STATE_ERROR = 1,
|
||||
PRINTER_STATE_IDLE = 2,
|
||||
PRINTER_STATE_PRINTING = 3,
|
||||
PRINTER_STATE_PAUSED = 4,
|
||||
};
|
||||
|
||||
typedef struct _Printer {
|
||||
unsigned char state;
|
||||
char* state_message;
|
||||
float extruder_temp;
|
||||
float extruder_target_temp;
|
||||
float bed_temp;
|
||||
float bed_target_temp;
|
||||
float position[3];
|
||||
unsigned char can_extrude;
|
||||
unsigned char homed_axis;
|
||||
unsigned char absolute_coords;
|
||||
float elapsed_time_s;
|
||||
float printed_time_s;
|
||||
float remaining_time_s;
|
||||
float filament_used_mm;
|
||||
char* print_filename;
|
||||
float print_progress; // 0 -> 1
|
||||
float fan_speed; // 0 -> 1
|
||||
float gcode_offset[3];
|
||||
float speed_mult;
|
||||
float extrude_mult;
|
||||
int total_layers;
|
||||
int current_layer;
|
||||
float pressure_advance;
|
||||
float smooth_time;
|
||||
int feedrate_mm_per_s;
|
||||
int slicer_estimated_print_time_s;
|
||||
} Printer;
|
||||
|
||||
typedef struct _PrinterMinimal {
|
||||
unsigned char state;
|
||||
float print_progress; // 0 -> 1
|
||||
unsigned int power_devices;
|
||||
} PrinterMinimal;
|
||||
|
||||
extern Printer printer;
|
||||
extern PrinterMinimal *printer_minimal;
|
||||
extern int klipper_request_consecutive_fail_count;
|
||||
|
||||
#define DATA_PRINTER_STATE 1
|
||||
#define DATA_PRINTER_DATA 2
|
||||
#define DATA_PRINTER_TEMP_PRESET 3
|
||||
#define DATA_PRINTER_MINIMAL 4
|
||||
|
||||
void data_loop();
|
||||
void data_setup();
|
||||
void send_gcode(bool wait, const char* gcode);
|
||||
void move_printer(const char* axis, float amount, bool relative);
|
||||
|
||||
void freeze_request_thread();
|
||||
void unfreeze_request_thread();
|
||||
void data_setup();
|
||||
@@ -67,7 +67,7 @@ void screen_lv_touchRead(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
|
||||
}
|
||||
|
||||
void set_invert_display(){
|
||||
tft.invertDisplay(get_current_printer_config()->invert_colors);
|
||||
tft.invertDisplay(global_config.printer_config[global_config.printer_index].invert_colors);
|
||||
}
|
||||
|
||||
void screen_setup()
|
||||
|
||||
@@ -86,7 +86,7 @@ void screen_lv_touchRead(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
|
||||
|
||||
void set_invert_display()
|
||||
{
|
||||
tft.invertDisplay(get_current_printer_config()->invert_colors);
|
||||
tft.invertDisplay(global_config.printer_config[global_config.printer_index].invert_colors);
|
||||
}
|
||||
|
||||
void set_LED_color(uint8_t rgbVal[3])
|
||||
|
||||
183
CYD-Klipper/src/core/device/ESP32-CROWPANEL-35C.cpp
Normal file
183
CYD-Klipper/src/core/device/ESP32-CROWPANEL-35C.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
// Adapted from https://github.com/OzInFl/Elecrow-3.5-RGB-TFT-SQUARELINE-EXAMPLE
|
||||
|
||||
#ifdef CYD_SCREEN_DRIVER_ESP32_CROWPANEL_35C
|
||||
#include "../screen_driver.h"
|
||||
#include "lvgl.h"
|
||||
#include "../../conf/global_config.h"
|
||||
#include <LovyanGFX.hpp>
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
#ifdef CYD_SCREEN_VERTICAL
|
||||
#error "Vertical screen not supported with the ESP32_CROWPANEL_28R driver"
|
||||
#endif
|
||||
|
||||
static lv_disp_draw_buf_t draw_buf;
|
||||
static lv_color_t buf[CYD_SCREEN_HEIGHT_PX * CYD_SCREEN_WIDTH_PX / 10];
|
||||
|
||||
#define BUZZER_PIN 20
|
||||
#define LCD_BL 46
|
||||
#define SDA_FT6236 38
|
||||
#define SCL_FT6236 39
|
||||
#define I2C_TOUCH_ADDR 0x38
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_ILI9488 _panel_instance;
|
||||
lgfx::Bus_Parallel16 _bus_instance;
|
||||
lgfx::Touch_FT5x06 _touch_instance;
|
||||
|
||||
public:
|
||||
LGFX()
|
||||
{
|
||||
auto bus_cfg = _bus_instance.config();
|
||||
bus_cfg.port = 0;
|
||||
bus_cfg.freq_write = 80000000;
|
||||
bus_cfg.pin_wr = 18;
|
||||
bus_cfg.pin_rd = 48;
|
||||
bus_cfg.pin_rs = 45;
|
||||
bus_cfg.pin_d0 = 47;
|
||||
bus_cfg.pin_d1 = 21;
|
||||
bus_cfg.pin_d2 = 14;
|
||||
bus_cfg.pin_d3 = 13;
|
||||
bus_cfg.pin_d4 = 12;
|
||||
bus_cfg.pin_d5 = 11;
|
||||
bus_cfg.pin_d6 = 10;
|
||||
bus_cfg.pin_d7 = 9;
|
||||
bus_cfg.pin_d8 = 3;
|
||||
bus_cfg.pin_d9 = 8;
|
||||
bus_cfg.pin_d10 = 16;
|
||||
bus_cfg.pin_d11 = 15;
|
||||
bus_cfg.pin_d12 = 7;
|
||||
bus_cfg.pin_d13 = 6;
|
||||
bus_cfg.pin_d14 = 5;
|
||||
bus_cfg.pin_d15 = 4;
|
||||
_bus_instance.config(bus_cfg);
|
||||
_panel_instance.setBus(&_bus_instance);
|
||||
|
||||
auto panel_cfg = _panel_instance.config();
|
||||
panel_cfg.pin_cs = -1;
|
||||
panel_cfg.pin_rst = -1;
|
||||
panel_cfg.pin_busy = -1;
|
||||
panel_cfg.memory_width = 320;
|
||||
panel_cfg.memory_height = 480;
|
||||
panel_cfg.panel_width = 320;
|
||||
panel_cfg.panel_height = 480;
|
||||
panel_cfg.offset_x = 0;
|
||||
panel_cfg.offset_y = 0;
|
||||
panel_cfg.offset_rotation = 0;
|
||||
panel_cfg.dummy_read_pixel = 8;
|
||||
panel_cfg.dummy_read_bits = 1;
|
||||
panel_cfg.readable = true;
|
||||
panel_cfg.invert = global_config.printer_config[global_config.printer_index].invert_colors ? true : false;
|
||||
panel_cfg.rgb_order = false;
|
||||
panel_cfg.dlen_16bit = true;
|
||||
panel_cfg.bus_shared = true;
|
||||
|
||||
_panel_instance.config(panel_cfg);
|
||||
|
||||
auto touch_cfg = _touch_instance.config();
|
||||
touch_cfg.x_min = 0;
|
||||
touch_cfg.x_max = 319;
|
||||
touch_cfg.y_min = 0;
|
||||
touch_cfg.y_max = 479;
|
||||
touch_cfg.pin_int = -1;
|
||||
touch_cfg.bus_shared = false;
|
||||
touch_cfg.offset_rotation = 0;
|
||||
|
||||
touch_cfg.i2c_port = 1;
|
||||
touch_cfg.i2c_addr = 0x38;
|
||||
touch_cfg.pin_sda = 38;
|
||||
touch_cfg.pin_scl = 39;
|
||||
touch_cfg.freq = 400000;
|
||||
|
||||
_touch_instance.config(touch_cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
|
||||
setPanel(&_panel_instance);
|
||||
}
|
||||
};
|
||||
|
||||
LGFX tft;
|
||||
|
||||
void screen_setBrightness(unsigned char brightness)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void set_invert_display()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
void screen_lv_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
|
||||
{
|
||||
uint32_t w = (area->x2 - area->x1 + 1);
|
||||
uint32_t h = (area->y2 - area->y1 + 1);
|
||||
|
||||
tft.startWrite();
|
||||
tft.setAddrWindow(area->x1, area->y1, w, h);
|
||||
tft.writePixels((lgfx::rgb565_t *)&color_p->full, w * h);
|
||||
tft.endWrite();
|
||||
|
||||
lv_disp_flush_ready(disp);
|
||||
}
|
||||
|
||||
void screen_lv_touchRead(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
|
||||
{
|
||||
uint16_t touchX, touchY;
|
||||
|
||||
bool touched = tft.getTouch(&touchX, &touchY);
|
||||
|
||||
if (touchX > CYD_SCREEN_WIDTH_PX || touchY > CYD_SCREEN_HEIGHT_PX)
|
||||
{
|
||||
LOG_LN("Y or y outside of expected parameters..");
|
||||
}
|
||||
else
|
||||
{
|
||||
data->state = touched ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
|
||||
data->point.x = touchX;
|
||||
data->point.y = touchY;
|
||||
}
|
||||
}
|
||||
|
||||
void screen_setup()
|
||||
{
|
||||
pinMode(BUZZER_PIN, OUTPUT);
|
||||
ledcSetup(4, 5000, 8);
|
||||
ledcAttachPin(BUZZER_PIN, 4);
|
||||
|
||||
tft.begin();
|
||||
tft.setRotation(global_config.rotate_screen ? 3 : 1);
|
||||
|
||||
delay(500);
|
||||
|
||||
pinMode(LCD_BL, OUTPUT);
|
||||
digitalWrite(LCD_BL, HIGH);
|
||||
|
||||
/*
|
||||
ledcSetup(0, 5000, 12);
|
||||
ledcAttachPin(LCD_BL, 0);
|
||||
*/
|
||||
|
||||
lv_init();
|
||||
lv_disp_draw_buf_init(&draw_buf, buf, NULL, CYD_SCREEN_WIDTH_PX * CYD_SCREEN_HEIGHT_PX / 10);
|
||||
|
||||
/*Initialize the display*/
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.hor_res = CYD_SCREEN_WIDTH_PX;
|
||||
disp_drv.ver_res = CYD_SCREEN_HEIGHT_PX;
|
||||
disp_drv.flush_cb = screen_lv_flush;
|
||||
disp_drv.draw_buf = &draw_buf;
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
/*Initialize the (dummy) input device driver*/
|
||||
static lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init(&indev_drv);
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = screen_lv_touchRead;
|
||||
lv_indev_drv_register(&indev_drv);
|
||||
}
|
||||
|
||||
#endif
|
||||
100
CYD-Klipper/src/core/device/ESP32-CROWPANEL_28R.cpp
Normal file
100
CYD-Klipper/src/core/device/ESP32-CROWPANEL_28R.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifdef CYD_SCREEN_DRIVER_ESP32_CROWPANEL_28R
|
||||
#include "../screen_driver.h"
|
||||
|
||||
#ifdef CYD_SCREEN_VERTICAL
|
||||
#error "Vertical screen not supported with the ESP32_CROWPANEL_28R driver"
|
||||
#endif
|
||||
|
||||
#include <SPI.h>
|
||||
#include <TFT_eSPI.h>
|
||||
#include "../../conf/global_config.h"
|
||||
#include "lvgl.h"
|
||||
#include <TFT_eSPI.h>
|
||||
#include "../lv_setup.h"
|
||||
|
||||
#define TOUCH_THRESHOLD 600
|
||||
|
||||
static lv_disp_draw_buf_t draw_buf;
|
||||
static lv_color_t buf[CYD_SCREEN_HEIGHT_PX * CYD_SCREEN_WIDTH_PX / 10];
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
|
||||
uint16_t touchX, touchY;
|
||||
|
||||
void screen_setBrightness(byte brightness)
|
||||
{
|
||||
// calculate duty, 4095 from 2 ^ 12 - 1
|
||||
uint32_t duty = (4095 / 255) * brightness;
|
||||
|
||||
// write duty to LEDC
|
||||
ledcWrite(0, duty);
|
||||
}
|
||||
|
||||
void screen_lv_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
|
||||
{
|
||||
uint32_t w = (area->x2 - area->x1 + 1);
|
||||
uint32_t h = (area->y2 - area->y1 + 1);
|
||||
|
||||
tft.startWrite();
|
||||
tft.setAddrWindow(area->x1, area->y1, w, h);
|
||||
tft.pushColors((uint16_t *)&color_p->full, w * h, true);
|
||||
tft.endWrite();
|
||||
|
||||
lv_disp_flush_ready(disp);
|
||||
}
|
||||
|
||||
void screen_lv_touchRead(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
|
||||
{
|
||||
if (tft.getTouch( &touchX, &touchY, TOUCH_THRESHOLD))
|
||||
{
|
||||
data->state = LV_INDEV_STATE_PR;
|
||||
data->point.x = touchX;
|
||||
data->point.y = touchY;
|
||||
}
|
||||
else
|
||||
{
|
||||
data->state = LV_INDEV_STATE_REL;
|
||||
}
|
||||
}
|
||||
|
||||
void set_invert_display(){
|
||||
tft.invertDisplay(global_config.printer_config[global_config.printer_index].invert_colors);
|
||||
}
|
||||
|
||||
void screen_setup()
|
||||
{
|
||||
uint16_t calData[5] = { 189, 3416, 359, 3439, 1};
|
||||
|
||||
lv_init();
|
||||
|
||||
tft.init();
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.invertDisplay(false);
|
||||
delay(300);
|
||||
|
||||
tft.setRotation(1);
|
||||
tft.setTouch( calData );
|
||||
|
||||
ledcSetup(0, 5000, 12);
|
||||
ledcAttachPin(TFT_BL, 0);
|
||||
|
||||
lv_disp_draw_buf_init(&draw_buf, buf, NULL, CYD_SCREEN_HEIGHT_PX * CYD_SCREEN_WIDTH_PX / 10);
|
||||
|
||||
/*Initialize the display*/
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.hor_res = CYD_SCREEN_WIDTH_PX;
|
||||
disp_drv.ver_res = CYD_SCREEN_HEIGHT_PX;
|
||||
disp_drv.flush_cb = screen_lv_flush;
|
||||
disp_drv.draw_buf = &draw_buf;
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
/*Initialize the (dummy) input device driver*/
|
||||
static lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init(&indev_drv);
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = screen_lv_touchRead;
|
||||
lv_indev_drv_register(&indev_drv);
|
||||
}
|
||||
|
||||
#endif // CYD_SCREEN_DRIVER_ESP32_CROWPANEL_28R
|
||||
@@ -21,7 +21,7 @@ void set_invert_display()
|
||||
|
||||
void lv_screen_intercept(_lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
|
||||
{
|
||||
if (get_current_printer_config()->invert_colors) {
|
||||
if (global_config.printer_config[global_config.printer_index].invert_colors) {
|
||||
uint32_t w = (area->x2 - area->x1 + 1);
|
||||
uint32_t h = (area->y2 - area->y1 + 1);
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
#include <list>
|
||||
#include "files_query.h"
|
||||
#include "../conf/global_config.h"
|
||||
#include "data_setup.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include "http_client.h"
|
||||
|
||||
// Always has +1 entry with a null'd name
|
||||
FILESYSTEM_FILE* last_query = NULL;
|
||||
|
||||
FILESYSTEM_FILE* get_files(int limit){
|
||||
freeze_request_thread();
|
||||
|
||||
if (last_query != NULL){
|
||||
FILESYSTEM_FILE* current = last_query;
|
||||
|
||||
while (current->name != NULL){
|
||||
free(current->name);
|
||||
current += 1;
|
||||
}
|
||||
|
||||
free(last_query);
|
||||
}
|
||||
|
||||
Serial.printf("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size());
|
||||
std::list<FILESYSTEM_FILE> files;
|
||||
|
||||
auto timer_request = millis();
|
||||
SETUP_HTTP_CLIENT_FULL("/server/files/list", true, 5000);
|
||||
|
||||
int httpCode = client.GET();
|
||||
auto timer_parse = millis();
|
||||
|
||||
if (httpCode == 200){
|
||||
JsonDocument doc;
|
||||
auto parseResult = deserializeJson(doc, client.getStream());
|
||||
Serial.printf("Json parse: %s\n", parseResult.c_str());
|
||||
auto result = doc["result"].as<JsonArray>();
|
||||
|
||||
for (auto file : result){
|
||||
FILESYSTEM_FILE f = {0};
|
||||
const char* path = file["path"];
|
||||
float modified = file["modified"];
|
||||
auto file_iter = files.begin();
|
||||
|
||||
while (file_iter != files.end()){
|
||||
if ((*file_iter).modified < modified)
|
||||
break;
|
||||
|
||||
file_iter++;
|
||||
}
|
||||
|
||||
if (file_iter == files.end() && files.size() >= limit)
|
||||
continue;
|
||||
|
||||
f.name = (char*)malloc(strlen(path) + 1);
|
||||
if (f.name == NULL){
|
||||
Serial.println("Failed to allocate memory");
|
||||
continue;
|
||||
}
|
||||
strcpy(f.name, path);
|
||||
f.modified = modified;
|
||||
|
||||
if (file_iter != files.end())
|
||||
files.insert(file_iter, f);
|
||||
else
|
||||
files.push_back(f);
|
||||
|
||||
if (files.size() > limit){
|
||||
auto last_entry = files.back();
|
||||
|
||||
if (last_entry.name != NULL)
|
||||
free(last_entry.name);
|
||||
|
||||
files.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t size = sizeof(FILESYSTEM_FILE) * (files.size() + 1);
|
||||
FILESYSTEM_FILE* result = (FILESYSTEM_FILE*)malloc(size);
|
||||
|
||||
if (result == NULL){
|
||||
Serial.println("Failed to allocate memory");
|
||||
|
||||
for (auto file : files){
|
||||
free(file.name);
|
||||
}
|
||||
|
||||
unfreeze_request_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
last_query = result;
|
||||
result[files.size()].name = NULL;
|
||||
|
||||
for (auto file : files){
|
||||
*result = file;
|
||||
result += 1;
|
||||
}
|
||||
|
||||
Serial.printf("Heap space post-file-parse: %d bytes\n", esp_get_free_heap_size());
|
||||
Serial.printf("Got %d files. Request took %dms, parsing took %dms\n", files.size(), timer_parse - timer_request, millis() - timer_parse);
|
||||
unfreeze_request_thread();
|
||||
return last_query;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
At some point it may be a fun challenge to try to implement a virtual folder structure, but not today.
|
||||
|
||||
typedef struct _FILESYSTEM_FILE {
|
||||
char* name;
|
||||
char* parent_folder_name;
|
||||
long level;
|
||||
} FILESYSTEM_FILE;
|
||||
|
||||
typedef struct _FILESYSTEM_FOLDER {
|
||||
char** files;
|
||||
char* folder_path;
|
||||
FILESYSTEM_FOLDER* folders;
|
||||
} FILESYSTEM_FOLDER;
|
||||
*/
|
||||
|
||||
typedef struct _FILESYSTEM_FILE {
|
||||
char* name;
|
||||
float modified;
|
||||
} FILESYSTEM_FILE;
|
||||
|
||||
FILESYSTEM_FILE* get_files(int limit);
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "http_client.h"
|
||||
|
||||
String get_full_url(String url_part, PRINTER_CONFIG * config)
|
||||
{
|
||||
return "http://" + String(config->klipper_host) + ":" + String(config->klipper_port) + url_part;
|
||||
}
|
||||
|
||||
String get_full_url(String url_part)
|
||||
{
|
||||
return "http://" + String(get_current_printer_config()->klipper_host) + ":" + String(get_current_printer_config()->klipper_port) + url_part;
|
||||
}
|
||||
|
||||
void configure_http_client(HTTPClient &client, String url, bool stream, int timeout)
|
||||
{
|
||||
if (stream){
|
||||
client.useHTTP10(true);
|
||||
}
|
||||
|
||||
if (timeout > 0){
|
||||
client.setTimeout(timeout);
|
||||
client.setConnectTimeout(timeout);
|
||||
}
|
||||
|
||||
client.begin(url);
|
||||
|
||||
if (get_current_printer_config()->auth_configured) {
|
||||
client.addHeader("X-Api-Key", get_current_printer_config()->klipper_auth);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include "../conf/global_config.h"
|
||||
|
||||
String get_full_url(String url_part);
|
||||
String get_full_url(String url_part, PRINTER_CONFIG * config);
|
||||
|
||||
void configure_http_client(HTTPClient &client, String url, bool stream = true, int timeout = 1000);
|
||||
|
||||
#define SETUP_HTTP_CLIENT(url_part) HTTPClient client; configure_http_client(client, get_full_url(url_part));
|
||||
|
||||
#define SETUP_HTTP_CLIENT_FULL(url_part, stream, timeout) HTTPClient client; configure_http_client(client, get_full_url(url_part), stream, timeout);
|
||||
@@ -0,0 +1,399 @@
|
||||
#include "serial_klipper_printer_integration.hpp"
|
||||
#include <HardwareSerial.h>
|
||||
#include <UrlEncode.h>
|
||||
#include "../../ui/serial/serial_console.h"
|
||||
|
||||
void clear_serial_buffer(bool can_rely_on_newline_terminator = true)
|
||||
{
|
||||
if (can_rely_on_newline_terminator)
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
while (Serial.read() != '\n')
|
||||
;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (Serial.available())
|
||||
{
|
||||
Serial.read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Request: {timeout} {method} {endpoint}
|
||||
// Response: {status code} {body}
|
||||
bool make_serial_request(JsonDocument &out, int timeout_ms, HttpRequestType requestType, const char* endpoint)
|
||||
{
|
||||
serial_console::global_disable_serial_console = true;
|
||||
temporary_config.debug = false;
|
||||
char buff[10];
|
||||
clear_serial_buffer();
|
||||
|
||||
// TODO: Add semaphore here
|
||||
if (!Serial.availableForWrite())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("HTTP_REQUEST %d %s %s\n", timeout_ms, requestType == HttpGet ? "GET" : "POST", endpoint);
|
||||
|
||||
if (timeout_ms <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
unsigned long _m = millis();
|
||||
while (!Serial.available() && millis() < _m + timeout_ms + 10) delay(1);
|
||||
|
||||
if (!Serial.available())
|
||||
{
|
||||
Serial.println("Timeout...");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.readBytes(buff, 4);
|
||||
buff[3] = 0;
|
||||
|
||||
if (buff[0] < '0' || buff[0] > '9')
|
||||
{
|
||||
Serial.printf("Invalid error code, got char '%c'\n", buff[0]);
|
||||
clear_serial_buffer();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int status_code = atoi(buff);
|
||||
|
||||
if (status_code < 200 || status_code >= 300)
|
||||
{
|
||||
Serial.println("Non-200 error code");
|
||||
clear_serial_buffer();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = deserializeJson(out, Serial);
|
||||
Serial.printf("Deserialization result: %s\n", result.c_str());
|
||||
bool success = result == DeserializationError::Ok;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
unsigned char* data;
|
||||
} BinaryResponse;
|
||||
|
||||
// Request: {timeout} {method} {endpoint}
|
||||
// Response: {8 char 0's padded body length}{body}
|
||||
bool make_binary_request(BinaryResponse* data, int timeout_ms, HttpRequestType requestType, const char* endpoint)
|
||||
{
|
||||
serial_console::global_disable_serial_console = true;
|
||||
temporary_config.debug = false;
|
||||
char buff[10];
|
||||
clear_serial_buffer();
|
||||
|
||||
// TODO: Add semaphore here
|
||||
if (!Serial.availableForWrite() || timeout_ms <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("HTTP_BINARY %d %s %s\n", timeout_ms, requestType == HttpGet ? "GET" : "POST", endpoint);
|
||||
|
||||
unsigned long _m = millis();
|
||||
while (!Serial.available() && millis() < _m + timeout_ms + 10) delay(1);
|
||||
|
||||
if (!Serial.available())
|
||||
{
|
||||
Serial.println("Timeout...");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.readBytes(buff, 8);
|
||||
buff[9] = 0;
|
||||
|
||||
if (buff[0] < '0' || buff[0] > '9')
|
||||
{
|
||||
Serial.println("Invalid length");
|
||||
clear_serial_buffer(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int data_length = atoi(buff);
|
||||
|
||||
if (data_length <= 0)
|
||||
{
|
||||
Serial.println("0 Length");
|
||||
clear_serial_buffer(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
data->len = data_length;
|
||||
data->data = (unsigned char*)malloc(data_length);
|
||||
|
||||
if (data->data == NULL)
|
||||
{
|
||||
Serial.println("Failed to allocate memory");
|
||||
clear_serial_buffer(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = Serial.readBytes((char*)data->data, data_length) == data_length;
|
||||
if (!result)
|
||||
{
|
||||
free(data->data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool make_serial_request_nocontent(HttpRequestType requestType, const char* endpoint)
|
||||
{
|
||||
JsonDocument doc;
|
||||
make_serial_request(doc, 0, requestType, endpoint);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialKlipperPrinter::connect()
|
||||
{
|
||||
return connection_test_serial_klipper(printer_config) == KlipperConnectionStatus::ConnectOk;
|
||||
}
|
||||
|
||||
bool SerialKlipperPrinter::fetch()
|
||||
{
|
||||
JsonDocument doc;
|
||||
if (make_serial_request(doc, 1000, HttpGet, "/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks&fan&display_status"))
|
||||
{
|
||||
if (printer_data.state == PrinterStateOffline)
|
||||
{
|
||||
printer_data.state = PrinterStateError;
|
||||
}
|
||||
|
||||
klipper_request_consecutive_fail_count = 0;
|
||||
parse_state(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
klipper_request_consecutive_fail_count++;
|
||||
if (klipper_request_consecutive_fail_count >= 5)
|
||||
{
|
||||
printer_data.state = PrinterStateOffline;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PrinterDataMinimal SerialKlipperPrinter::fetch_min()
|
||||
{
|
||||
JsonDocument doc;
|
||||
PrinterDataMinimal data = {};
|
||||
data.success = false;
|
||||
|
||||
if (!printer_config->setup_complete)
|
||||
{
|
||||
data.state = PrinterStateOffline;
|
||||
return data;
|
||||
}
|
||||
|
||||
data.success = true;
|
||||
|
||||
if (make_serial_request(doc, 1000, HttpGet, "/printer/objects/query?webhooks&print_stats&virtual_sdcard"))
|
||||
{
|
||||
data.state = PrinterState::PrinterStateIdle;
|
||||
parse_state_min(doc, &data);
|
||||
data.power_devices = get_power_devices_count();
|
||||
}
|
||||
else
|
||||
{
|
||||
data.state = PrinterState::PrinterStateOffline;
|
||||
data.power_devices = get_power_devices_count();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
Macros SerialKlipperPrinter::get_macros()
|
||||
{
|
||||
Macros macros = {0};
|
||||
JsonDocument doc;
|
||||
if (make_serial_request(doc, 1000, HttpGet, "/printer/gcode/help"))
|
||||
{
|
||||
macros = parse_macros(doc);
|
||||
}
|
||||
|
||||
return macros;
|
||||
}
|
||||
|
||||
int SerialKlipperPrinter::get_macros_count()
|
||||
{
|
||||
JsonDocument doc;
|
||||
if (make_serial_request(doc, 1000, HttpGet, "/printer/gcode/help"))
|
||||
{
|
||||
return parse_macros_count(doc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PowerDevices SerialKlipperPrinter::get_power_devices()
|
||||
{
|
||||
PowerDevices power_devices = {0};
|
||||
JsonDocument doc;
|
||||
if (make_serial_request(doc, 1000, HttpGet, "/machine/device_power/devices"))
|
||||
{
|
||||
power_devices = parse_power_devices(doc);
|
||||
}
|
||||
|
||||
return power_devices;
|
||||
}
|
||||
|
||||
int SerialKlipperPrinter::get_power_devices_count()
|
||||
{
|
||||
JsonDocument doc;
|
||||
if (make_serial_request(doc, 1000, HttpGet, "/machine/device_power/devices"))
|
||||
{
|
||||
return parse_power_devices_count(doc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SerialKlipperPrinter::set_power_device_state(const char* device_name, bool state)
|
||||
{
|
||||
String request = "/machine/device_power/device?device=" + urlEncode(device_name) + "&action=" + (state ? "on" : "off");
|
||||
return make_serial_request_nocontent(HttpGet, request.c_str());
|
||||
}
|
||||
|
||||
Files SerialKlipperPrinter::get_files()
|
||||
{
|
||||
Files files_result = {0};
|
||||
files_result.success = false;
|
||||
JsonDocument doc;
|
||||
LOG_F(("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size()));
|
||||
std::list<KlipperFileSystemFile> files;
|
||||
|
||||
auto timer_request = millis();
|
||||
bool result = make_serial_request(doc, 5000, HttpGet, "/server/files/list");
|
||||
auto timer_parse = millis();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return files_result;
|
||||
}
|
||||
|
||||
parse_file_list(doc, files, 20);
|
||||
|
||||
files_result.available_files = (char**)malloc(sizeof(char*) * files.size());
|
||||
|
||||
if (files_result.available_files == NULL){
|
||||
LOG_LN("Failed to allocate memory");
|
||||
|
||||
for (auto file : files){
|
||||
free(file.name);
|
||||
}
|
||||
|
||||
return files_result;
|
||||
}
|
||||
|
||||
for (auto file : files){
|
||||
files_result.available_files[files_result.count++] = file.name;
|
||||
}
|
||||
|
||||
files_result.success = true;
|
||||
|
||||
LOG_F(("Heap space post-file-parse: %d bytes\n", esp_get_free_heap_size()))
|
||||
LOG_F(("Got %d files. Request took %dms, parsing took %dms\n", files.size(), timer_parse - timer_request, millis() - timer_parse))
|
||||
return files_result;
|
||||
}
|
||||
|
||||
bool SerialKlipperPrinter::start_file(const char* filename)
|
||||
{
|
||||
JsonDocument doc;
|
||||
String request = "/printer/print/start?filename=" + urlEncode(filename);
|
||||
return make_serial_request_nocontent(HttpPost, request.c_str());;
|
||||
}
|
||||
|
||||
Thumbnail SerialKlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename)
|
||||
{
|
||||
Thumbnail thumbnail = {0};
|
||||
JsonDocument doc;
|
||||
char* img_filename_path = NULL;
|
||||
|
||||
String request = "/server/files/thumbnails?filename=" + urlEncode(gcode_filename);
|
||||
if (make_serial_request(doc, 1000, HttpGet, request.c_str()))
|
||||
{
|
||||
img_filename_path = parse_thumbnails(doc);
|
||||
doc.clear();
|
||||
}
|
||||
|
||||
if (img_filename_path == NULL)
|
||||
{
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
request = "/server/files/gcodes/" + urlEncode(img_filename_path);
|
||||
BinaryResponse data = {0};
|
||||
if (make_binary_request(&data, 2000, HttpGet, request.c_str()))
|
||||
{
|
||||
thumbnail.png = data.data;
|
||||
thumbnail.size = data.len;
|
||||
thumbnail.success = true;
|
||||
}
|
||||
|
||||
free(img_filename_path);
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
bool SerialKlipperPrinter::send_gcode(const char* gcode, bool wait)
|
||||
{
|
||||
JsonDocument doc;
|
||||
String request = "/printer/gcode/script?script=" + urlEncode(gcode);
|
||||
|
||||
return wait
|
||||
? make_serial_request(doc, 5000, HttpGet, request.c_str())
|
||||
: make_serial_request_nocontent(HttpGet, request.c_str());
|
||||
}
|
||||
|
||||
bool SerialKlipperPrinter::send_emergency_stop()
|
||||
{
|
||||
return make_serial_request_nocontent(HttpGet, "/printer/emergency_stop");
|
||||
}
|
||||
|
||||
int SerialKlipperPrinter::get_slicer_time_estimate_s()
|
||||
{
|
||||
if (printer_data.state != PrinterStatePrinting && printer_data.state != PrinterStatePaused)
|
||||
return 0;
|
||||
|
||||
String request = "/server/files/metadata?filename=" + urlEncode(printer_data.print_filename);
|
||||
JsonDocument doc;
|
||||
|
||||
if (!make_serial_request(doc, 2000, HttpGet, request.c_str()))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parse_slicer_time_estimate(doc);
|
||||
}
|
||||
|
||||
KlipperConnectionStatus connection_test_serial_klipper(PrinterConfiguration* config)
|
||||
{
|
||||
serial_console::global_disable_serial_console = true;
|
||||
temporary_config.debug = false;
|
||||
JsonDocument doc;
|
||||
if (make_serial_request(doc, 1000, HttpGet, "/printer/info"))
|
||||
{
|
||||
return KlipperConnectionStatus::ConnectOk;
|
||||
}
|
||||
|
||||
return KlipperConnectionStatus::ConnectFail;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "../klipper/klipper_printer_integration.hpp"
|
||||
|
||||
class SerialKlipperPrinter : public KlipperPrinter
|
||||
{
|
||||
protected:
|
||||
bool send_emergency_stop();
|
||||
int get_slicer_time_estimate_s();
|
||||
public:
|
||||
SerialKlipperPrinter(int index) : KlipperPrinter(index)
|
||||
{}
|
||||
|
||||
bool connect();
|
||||
bool fetch();
|
||||
PrinterDataMinimal fetch_min();
|
||||
Macros get_macros();
|
||||
int get_macros_count();
|
||||
PowerDevices get_power_devices();
|
||||
int get_power_devices_count();
|
||||
bool set_power_device_state(const char* device_name, bool state);
|
||||
Files get_files();
|
||||
bool start_file(const char* filename);
|
||||
Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename);
|
||||
bool send_gcode(const char* gcode, bool wait = true);
|
||||
};
|
||||
|
||||
KlipperConnectionStatus connection_test_serial_klipper(PrinterConfiguration* config);
|
||||
519
CYD-Klipper/src/core/klipper/klipper_printer_integration.cpp
Normal file
519
CYD-Klipper/src/core/klipper/klipper_printer_integration.cpp
Normal file
@@ -0,0 +1,519 @@
|
||||
#include "klipper_printer_integration.hpp"
|
||||
#include "../../conf/global_config.h"
|
||||
#include <HTTPClient.h>
|
||||
#include <UrlEncode.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <list>
|
||||
|
||||
void KlipperPrinter::configure_http_client(HTTPClient &client, String url_part, bool stream, int timeout)
|
||||
{
|
||||
client.useHTTP10(stream);
|
||||
|
||||
if (timeout > 0){
|
||||
client.setTimeout(timeout);
|
||||
client.setConnectTimeout(timeout);
|
||||
}
|
||||
|
||||
client.begin("http://" + String(printer_config->printer_host) + ":" + String(printer_config->klipper_port) + url_part);
|
||||
|
||||
if (printer_config->auth_configured) {
|
||||
client.addHeader("X-Api-Key", printer_config->printer_auth);
|
||||
}
|
||||
}
|
||||
|
||||
int KlipperPrinter::get_slicer_time_estimate_s()
|
||||
{
|
||||
if (printer_data.state != PrinterStatePrinting && printer_data.state != PrinterStatePaused)
|
||||
return 0;
|
||||
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/server/files/metadata?filename=" + urlEncode(printer_data.print_filename), true, 5000);
|
||||
int http_code = client.GET();
|
||||
|
||||
if (http_code != 200)
|
||||
return 0;
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
return parse_slicer_time_estimate(doc);
|
||||
}
|
||||
|
||||
bool KlipperPrinter::send_gcode(const char *gcode, bool wait)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/gcode/script?script=" + urlEncode(gcode), false, wait ? 5000 : 750);
|
||||
LOG_F(("Sending gcode: %s\n", gcode))
|
||||
|
||||
try
|
||||
{
|
||||
client.GET();
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_LN("Failed to send gcode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool KlipperPrinter::move_printer(const char* axis, float amount, bool relative)
|
||||
{
|
||||
if (!printer_data.homed_axis || printer_data.state == PrinterStatePrinting)
|
||||
return false;
|
||||
|
||||
char gcode[64];
|
||||
const char* extra = (amount > 0) ? "+" : "";
|
||||
const char* start = "";
|
||||
const char* end = "";
|
||||
|
||||
if (printer_data.absolute_coords && relative) {
|
||||
start = "G91\n";
|
||||
}
|
||||
else if (!printer_data.absolute_coords && !relative) {
|
||||
start = "G90\n";
|
||||
}
|
||||
|
||||
if (printer_data.absolute_coords && relative) {
|
||||
end = "\nG90";
|
||||
}
|
||||
else if (!printer_data.absolute_coords && !relative) {
|
||||
end = "\nG91";
|
||||
}
|
||||
|
||||
sprintf(gcode, "%sG1 %s%s%.3f F6000%s", start, axis, extra, amount, end);
|
||||
send_gcode(gcode);
|
||||
|
||||
lock_absolute_relative_mode_swap = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KlipperPrinter::send_emergency_stop()
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/emergency_stop", false, 5000);
|
||||
|
||||
try
|
||||
{
|
||||
return client.GET() == 200;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_LN("Failed to send estop");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool KlipperPrinter::execute_feature(PrinterFeatures feature)
|
||||
{
|
||||
switch (feature)
|
||||
{
|
||||
case PrinterFeatureRestart:
|
||||
return send_gcode("RESTART", false);
|
||||
case PrinterFeatureFirmwareRestart:
|
||||
return send_gcode("FIRMWARE_RESTART", false);
|
||||
case PrinterFeatureHome:
|
||||
return send_gcode("G28");
|
||||
case PrinterFeatureDisableSteppers:
|
||||
return send_gcode("M18");
|
||||
case PrinterFeaturePause:
|
||||
return send_gcode("PAUSE");
|
||||
case PrinterFeatureResume:
|
||||
return send_gcode("RESUME");
|
||||
case PrinterFeatureStop:
|
||||
return send_gcode("CANCEL_PRINT");
|
||||
case PrinterFeatureEmergencyStop:
|
||||
LOG_LN("Sending estop");
|
||||
send_gcode("M112", false);
|
||||
send_emergency_stop();
|
||||
|
||||
return true;
|
||||
case PrinterFeatureExtrude:
|
||||
if (printer_data.state == PrinterStatePrinting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (printer_config->custom_filament_move_macros)
|
||||
{
|
||||
return send_gcode("FILAMENT_EXTRUDE");
|
||||
}
|
||||
else
|
||||
{
|
||||
return send_gcode("M83\nG1 E25 F300");
|
||||
}
|
||||
case PrinterFeatureRetract:
|
||||
if (printer_data.state == PrinterStatePrinting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (printer_config->custom_filament_move_macros)
|
||||
{
|
||||
return send_gcode("FILAMENT_RETRACT");
|
||||
}
|
||||
else
|
||||
{
|
||||
return send_gcode("M83\nG1 E-25 F300");
|
||||
}
|
||||
case PrinterFeatureCooldown:
|
||||
return send_gcode("M104 S0\nM140 S0");
|
||||
default:
|
||||
LOG_F(("Unsupported printer feature %d", feature));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KlipperPrinter::connect()
|
||||
{
|
||||
return connection_test_klipper(printer_config) == KlipperConnectionStatus::ConnectOk;
|
||||
}
|
||||
|
||||
bool KlipperPrinter::fetch()
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/objects/query?extruder&heater_bed&toolhead&gcode_move&virtual_sdcard&print_stats&webhooks&fan&display_status", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
if (http_code == 200)
|
||||
{
|
||||
if (printer_data.state == PrinterStateOffline)
|
||||
{
|
||||
printer_data.state = PrinterStateError;
|
||||
}
|
||||
|
||||
klipper_request_consecutive_fail_count = 0;
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
parse_state(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
klipper_request_consecutive_fail_count++;
|
||||
LOG_F(("Failed to fetch printer data: %d\n", http_code));
|
||||
|
||||
if (klipper_request_consecutive_fail_count >= 5)
|
||||
{
|
||||
printer_data.state = PrinterStateOffline;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PrinterDataMinimal KlipperPrinter::fetch_min()
|
||||
{
|
||||
PrinterDataMinimal data = {};
|
||||
data.success = false;
|
||||
|
||||
if (!printer_config->setup_complete)
|
||||
{
|
||||
data.state = PrinterStateOffline;
|
||||
return data;
|
||||
}
|
||||
|
||||
data.success = true;
|
||||
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/objects/query?webhooks&print_stats&virtual_sdcard", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
if (http_code == 200)
|
||||
{
|
||||
data.state = PrinterState::PrinterStateIdle;
|
||||
data.power_devices = get_power_devices_count();
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
parse_state_min(doc, &data);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.state = PrinterState::PrinterStateOffline;
|
||||
data.power_devices = get_power_devices_count();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void KlipperPrinter::disconnect()
|
||||
{
|
||||
// Nothing to disconnect, everything is http request based
|
||||
printer_data.state = PrinterStateOffline;
|
||||
}
|
||||
|
||||
Macros KlipperPrinter::get_macros()
|
||||
{
|
||||
HTTPClient client;
|
||||
Macros macros = {0};
|
||||
|
||||
configure_http_client(client, "/printer/gcode/help", true, 1000);
|
||||
int http_code = client.GET();
|
||||
|
||||
if (http_code == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
return parse_macros(doc);
|
||||
}
|
||||
|
||||
return macros;
|
||||
}
|
||||
|
||||
int KlipperPrinter::get_macros_count()
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/gcode/help", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
|
||||
if (http_code == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
return parse_macros_count(doc);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool KlipperPrinter::execute_macro(const char* macro)
|
||||
{
|
||||
return send_gcode(macro);
|
||||
}
|
||||
|
||||
PowerDevices KlipperPrinter::get_power_devices()
|
||||
{
|
||||
HTTPClient client;
|
||||
PowerDevices power_devices = {0};
|
||||
configure_http_client(client, "/machine/device_power/devices", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
|
||||
if (http_code == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
return parse_power_devices(doc);
|
||||
}
|
||||
|
||||
return power_devices;
|
||||
}
|
||||
|
||||
int KlipperPrinter::get_power_devices_count()
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/machine/device_power/devices", true, 1000);
|
||||
|
||||
int http_code = client.GET();
|
||||
|
||||
if (http_code == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
return parse_power_devices_count(doc);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool KlipperPrinter::set_power_device_state(const char* device_name, bool state)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/machine/device_power/device?device=" + urlEncode(device_name) + "&action=" + (state ? "on" : "off"), true, 1000);
|
||||
return client.POST("") == 200;
|
||||
}
|
||||
|
||||
#define KLIPPER_FILE_FETCH_LIMIT 20
|
||||
|
||||
Files KlipperPrinter::get_files()
|
||||
{
|
||||
Files files_result = {0};
|
||||
HTTPClient client;
|
||||
LOG_F(("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size()));
|
||||
std::list<KlipperFileSystemFile> files;
|
||||
|
||||
auto timer_request = millis();
|
||||
configure_http_client(client, "/server/files/list", true, 5000);
|
||||
|
||||
int http_code = client.GET();
|
||||
auto timer_parse = millis();
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
JsonDocument doc;
|
||||
auto parseResult = deserializeJson(doc, client.getStream());
|
||||
LOG_F(("Json parse: %s\n", parseResult.c_str()))
|
||||
parse_file_list(doc, files, KLIPPER_FILE_FETCH_LIMIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
return files_result;
|
||||
}
|
||||
|
||||
files_result.available_files = (char**)malloc(sizeof(char*) * files.size());
|
||||
|
||||
if (files_result.available_files == NULL){
|
||||
LOG_LN("Failed to allocate memory");
|
||||
|
||||
for (auto file : files){
|
||||
free(file.name);
|
||||
}
|
||||
|
||||
return files_result;
|
||||
}
|
||||
|
||||
for (auto file : files){
|
||||
files_result.available_files[files_result.count++] = file.name;
|
||||
}
|
||||
|
||||
files_result.success = true;
|
||||
|
||||
LOG_F(("Heap space post-file-parse: %d bytes\n", esp_get_free_heap_size()))
|
||||
LOG_F(("Got %d files. Request took %dms, parsing took %dms\n", files.size(), timer_parse - timer_request, millis() - timer_parse))
|
||||
return files_result;
|
||||
}
|
||||
|
||||
bool KlipperPrinter::start_file(const char *filename)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/printer/print/start?filename=" + urlEncode(filename), false, 1000);
|
||||
|
||||
int http_code = client.POST("");
|
||||
LOG_F(("Print start: HTTP %d\n", http_code))
|
||||
return http_code == 200;
|
||||
}
|
||||
|
||||
bool KlipperPrinter::set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature)
|
||||
{
|
||||
char gcode[64] = {0};
|
||||
|
||||
switch (device)
|
||||
{
|
||||
case PrinterTemperatureDeviceBed:
|
||||
sprintf(gcode, "M140 S%d", temperature);
|
||||
break;
|
||||
case PrinterTemperatureDeviceNozzle1:
|
||||
sprintf(gcode, "M104 S%d", temperature);
|
||||
break;
|
||||
default:
|
||||
LOG_F(("Unknown temperature device %d was requested to heat to %.2f", device, temperature));
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_gcode(gcode);
|
||||
}
|
||||
|
||||
Thumbnail KlipperPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename)
|
||||
{
|
||||
Thumbnail thumbnail = {0};
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/server/files/thumbnails?filename=" + urlEncode(gcode_filename), true, 1000);
|
||||
char* img_filename_path = NULL;
|
||||
unsigned char* data_png = NULL;
|
||||
|
||||
int http_code = 0;
|
||||
try
|
||||
{
|
||||
http_code = client.GET();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_LN("Exception while fetching gcode img location");
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
img_filename_path = parse_thumbnails(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_F(("Failed to fetch gcode image data: %d\n", http_code))
|
||||
}
|
||||
|
||||
if (img_filename_path == NULL)
|
||||
{
|
||||
LOG_LN("No compatible thumbnail found");
|
||||
return thumbnail;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_F(("Found 32x32 PNG gcode img at %s\n", gcode_filename));
|
||||
}
|
||||
|
||||
client.end();
|
||||
|
||||
configure_http_client(client, "/server/files/gcodes/" + urlEncode(img_filename_path), false, 2000);
|
||||
|
||||
http_code = 0;
|
||||
try
|
||||
{
|
||||
http_code = client.GET();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_LN("Exception while fetching gcode img");
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
size_t len = client.getSize();
|
||||
if (len <= 0)
|
||||
{
|
||||
LOG_LN("No gcode img data");
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
data_png = (unsigned char*)malloc(len + 1);
|
||||
|
||||
if (data_png != NULL)
|
||||
{
|
||||
if (len != client.getStream().readBytes(data_png, len))
|
||||
{
|
||||
LOG_LN("Failed to read gcode img data");
|
||||
free(data_png);
|
||||
}
|
||||
else
|
||||
{
|
||||
thumbnail.png = data_png;
|
||||
thumbnail.size = len;
|
||||
thumbnail.success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(img_filename_path);
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
KlipperConnectionStatus connection_test_klipper(PrinterConfiguration* config)
|
||||
{
|
||||
HTTPClient client;
|
||||
|
||||
client.setTimeout(1000);
|
||||
client.setConnectTimeout(1000);
|
||||
client.begin("http://" + String(config->printer_host) + ":" + String(config->klipper_port) + "/printer/info");
|
||||
|
||||
if (config->auth_configured) {
|
||||
client.addHeader("X-Api-Key", config->printer_auth);
|
||||
}
|
||||
|
||||
int http_code;
|
||||
try {
|
||||
http_code = client.GET();
|
||||
|
||||
if (http_code == 403)
|
||||
{
|
||||
return KlipperConnectionStatus::ConnectAuthRequired;
|
||||
}
|
||||
|
||||
return http_code == 200 ? KlipperConnectionStatus::ConnectOk : KlipperConnectionStatus::ConnectFail;
|
||||
}
|
||||
catch (...) {
|
||||
LOG_LN("Failed to connect");
|
||||
return KlipperConnectionStatus::ConnectFail;
|
||||
}
|
||||
}
|
||||
87
CYD-Klipper/src/core/klipper/klipper_printer_integration.hpp
Normal file
87
CYD-Klipper/src/core/klipper/klipper_printer_integration.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include "../printer_integration.hpp"
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <list>
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
float modified;
|
||||
} KlipperFileSystemFile;
|
||||
|
||||
class KlipperPrinter : public BasePrinter
|
||||
{
|
||||
private:
|
||||
unsigned int slicer_estimated_print_time_s{};
|
||||
unsigned int last_slicer_time_query{};
|
||||
void configure_http_client(HTTPClient &client, String url_part, bool stream, int timeout);
|
||||
|
||||
protected:
|
||||
unsigned char lock_absolute_relative_mode_swap{};
|
||||
unsigned char klipper_request_consecutive_fail_count{};
|
||||
|
||||
virtual bool send_emergency_stop();
|
||||
virtual int get_slicer_time_estimate_s();
|
||||
void init_ui_panels();
|
||||
|
||||
int parse_slicer_time_estimate(JsonDocument& in);
|
||||
void parse_state(JsonDocument& in);
|
||||
void parse_state_min(JsonDocument &in, PrinterDataMinimal* data);
|
||||
Macros parse_macros(JsonDocument &in);
|
||||
int parse_macros_count(JsonDocument &in);
|
||||
PowerDevices parse_power_devices(JsonDocument &in);
|
||||
int parse_power_devices_count(JsonDocument &in);
|
||||
void parse_file_list(JsonDocument &in, std::list<KlipperFileSystemFile> &files, int fetch_limit);
|
||||
char *parse_thumbnails(JsonDocument &in);
|
||||
|
||||
public:
|
||||
float gcode_offset[3]{};
|
||||
|
||||
KlipperPrinter(int index) : BasePrinter(index)
|
||||
{
|
||||
supported_features = PrinterFeatureRestart
|
||||
| PrinterFeatureFirmwareRestart
|
||||
| PrinterFeatureHome
|
||||
| PrinterFeatureDisableSteppers
|
||||
| PrinterFeaturePause
|
||||
| PrinterFeatureResume
|
||||
| PrinterFeatureStop
|
||||
| PrinterFeatureEmergencyStop
|
||||
| PrinterFeatureExtrude
|
||||
| PrinterFeatureRetract
|
||||
| PrinterFeatureCooldown;
|
||||
|
||||
supported_temperature_devices = PrinterTemperatureDeviceBed
|
||||
| PrinterTemperatureDeviceNozzle1;
|
||||
|
||||
init_ui_panels();
|
||||
printer_data.error_screen_features = PrinterFeatureRestart | PrinterFeatureFirmwareRestart;
|
||||
}
|
||||
|
||||
bool move_printer(const char* axis, float amount, bool relative);
|
||||
bool execute_feature(PrinterFeatures feature);
|
||||
virtual bool connect();
|
||||
virtual bool fetch();
|
||||
virtual PrinterDataMinimal fetch_min();
|
||||
void disconnect();
|
||||
virtual Macros get_macros();
|
||||
virtual int get_macros_count();
|
||||
bool execute_macro(const char* macro);
|
||||
virtual PowerDevices get_power_devices();
|
||||
virtual int get_power_devices_count();
|
||||
virtual bool set_power_device_state(const char* device_name, bool state);
|
||||
virtual Files get_files();
|
||||
virtual bool start_file(const char* filename);
|
||||
virtual Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename);
|
||||
bool set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature);
|
||||
virtual bool send_gcode(const char* gcode, bool wait = true);
|
||||
};
|
||||
|
||||
enum KlipperConnectionStatus {
|
||||
ConnectFail = 0,
|
||||
ConnectOk = 1,
|
||||
ConnectAuthRequired = 2,
|
||||
};
|
||||
|
||||
KlipperConnectionStatus connection_test_klipper(PrinterConfiguration* config);
|
||||
188
CYD-Klipper/src/core/klipper/klipper_printer_panels.cpp
Normal file
188
CYD-Klipper/src/core/klipper/klipper_printer_panels.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "klipper_printer_integration.hpp"
|
||||
#include "lvgl.h"
|
||||
#include "../../ui/ui_utils.h"
|
||||
#include "../common/constants.h"
|
||||
#include <stdio.h>
|
||||
#include "../semaphore.h"
|
||||
|
||||
bool send_gcode_blocking(const char *gcode, bool wait = true)
|
||||
{
|
||||
freeze_request_thread();
|
||||
KlipperPrinter* printer = (KlipperPrinter*)get_current_printer(); // TODO: pass by ref
|
||||
bool result = printer->send_gcode(gcode);
|
||||
unfreeze_request_thread();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool move_printer_blocking(const char* axis, float amount, bool relative)
|
||||
{
|
||||
freeze_request_thread();
|
||||
KlipperPrinter* printer = (KlipperPrinter*)get_current_printer(); // TODO: pass by ref
|
||||
bool result = printer->move_printer(axis, amount, relative);
|
||||
unfreeze_request_thread();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void set_fan_speed_text(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[16];
|
||||
sprintf(data, "Fan: %.0f%%", get_current_printer_data()->fan_speed * 100);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_fan_speed(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
int actual_speed = fan_percent_to_byte(speed);
|
||||
char gcode[16];
|
||||
sprintf(gcode, "M106 S%d", actual_speed);
|
||||
send_gcode_blocking(gcode);
|
||||
}
|
||||
|
||||
FAN_SPEED_COLUMN(set_fan_speed, klipper_fan_speed_columns)
|
||||
|
||||
static void set_zoffset_text(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
KlipperPrinter* printer = (KlipperPrinter*)get_current_printer(); // TODO: pass by ref
|
||||
char data[24];
|
||||
sprintf(data, "Z Offset: %.03f", printer->gcode_offset[2]);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_zoffset_text_ex(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
KlipperPrinter* printer = (KlipperPrinter*)get_current_printer(); // TODO: pass by ref
|
||||
char data[32];
|
||||
sprintf(data, "Z Offset: %.03f, Z: %.03f", printer->gcode_offset[2], get_current_printer_data()->position[2]);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_zoffset(lv_event_t * e){
|
||||
char* offset = (char*)lv_event_get_user_data(e);
|
||||
char gcode[48];
|
||||
sprintf(gcode, "SET_GCODE_OFFSET Z_ADJUST=%s MOVE=1", offset);
|
||||
send_gcode_blocking(gcode);
|
||||
}
|
||||
|
||||
static void set_z(lv_event_t * e){
|
||||
void* ptr = lv_event_get_user_data(e);
|
||||
float value = *(float *)(&ptr);
|
||||
|
||||
if (value < 0) {
|
||||
send_gcode_blocking("SET_GCODE_OFFSET Z=0 MOVE=1");
|
||||
return;
|
||||
}
|
||||
|
||||
move_printer_blocking("Z", value, false);
|
||||
}
|
||||
|
||||
const char* zoffsets[] = { "-0.01", "-0.025", "-0.05", "-0.2" };
|
||||
const char* zoffsets_2[] = { "+0.01", "+0.025", "+0.05", "+0.2" };
|
||||
const char* zabs[] = { "Z=0", "Z=0.1", "Z=1", "Clear" };
|
||||
const float zabsvalues[] = { 0, 0.1f, 1.0f, -1.0f };
|
||||
|
||||
lv_button_column_t zoffset_columns[] = {
|
||||
{ set_zoffset, zoffsets, (const void**)zoffsets, 4},
|
||||
{ set_zoffset, zoffsets_2, (const void**)zoffsets_2, 4},
|
||||
{ set_z, zabs, (const void**)zabsvalues, 4}
|
||||
};
|
||||
|
||||
static void set_speed_mult_text(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[16];
|
||||
sprintf(data, "Speed: %.0f%%", get_current_printer_data()->speed_mult * 100);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_speed_mult(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
char gcode[16];
|
||||
sprintf(gcode, "M220 S%d", speed);
|
||||
send_gcode_blocking(gcode);
|
||||
}
|
||||
|
||||
static void set_speed_mult_offset(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
float result = get_current_printer_data()->speed_mult * 100 + speed;
|
||||
get_current_printer_data()->speed_mult = result / 100;
|
||||
char gcode[16];
|
||||
sprintf(gcode, "M220 S%.0f", result);
|
||||
send_gcode_blocking(gcode);
|
||||
}
|
||||
|
||||
const char* speed_presets[] = { "50%", "100%", "150%", "200%" };
|
||||
const int speed_presets_values[] = { 50, 100, 150, 200 };
|
||||
const char* speed_presets_minus[] = { "-1%", "-5%", "-10%", "-25%" };
|
||||
const int speed_presets_minus_values[] = { -1, -5, -10, -25 };
|
||||
const char* speed_presets_plus[] = { "+1%", "+5%", "+10%", "+25%" };
|
||||
const int speed_presets_plus_values[] = { 1, 5, 10, 25 };
|
||||
|
||||
lv_button_column_t speed_mult_columns[] = {
|
||||
{ set_speed_mult, speed_presets, (const void**)speed_presets_values, 4},
|
||||
{ set_speed_mult_offset, speed_presets_minus, (const void**)speed_presets_minus_values, 4},
|
||||
{ set_speed_mult_offset, speed_presets_plus, (const void**)speed_presets_plus_values, 4}
|
||||
};
|
||||
|
||||
static void set_extrude_mult_text(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[16];
|
||||
sprintf(data, "Flow: %.0f%%", get_current_printer_data()->extrude_mult * 100);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_extrude_mult(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
char gcode[16];
|
||||
sprintf(gcode, "M221 S%d", speed);
|
||||
send_gcode_blocking(gcode);
|
||||
}
|
||||
|
||||
static void set_extrude_mult_offset(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
float result = get_current_printer_data()->extrude_mult * 100 + speed;
|
||||
get_current_printer_data()->extrude_mult = result / 100;
|
||||
char gcode[16];
|
||||
sprintf(gcode, "M221 S%.0f", result);
|
||||
|
||||
send_gcode_blocking(gcode);
|
||||
}
|
||||
|
||||
const char* extrude_presets[] = { "95%", "100%", "105%", "110%" };
|
||||
const int extrude_presets_values[] = { 95, 100, 105, 110 };
|
||||
const char* extrude_offset[] = { "+5%", "+1%", "-1%", "-5%" };
|
||||
const int extrude_offset_values[] = { 5, 1, -1, -5 };
|
||||
|
||||
lv_button_column_t extrude_mult_columns[] = {
|
||||
{ set_extrude_mult, extrude_presets, (const void**)extrude_presets_values, 4},
|
||||
{ set_extrude_mult_offset, extrude_offset, (const void**)extrude_offset_values, 4}
|
||||
};
|
||||
|
||||
static void open_fan_speed_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_fan_speed_text, klipper_fan_speed_columns, 3);
|
||||
}
|
||||
|
||||
static void open_zoffset_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_zoffset_text_ex, zoffset_columns, get_current_printer_data()->state == PrinterStateIdle ? 3 : 2);
|
||||
}
|
||||
|
||||
static void open_speed_mult_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_speed_mult_text, speed_mult_columns, 3);
|
||||
}
|
||||
|
||||
static void open_extrude_mult_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_extrude_mult_text, extrude_mult_columns, 2);
|
||||
}
|
||||
|
||||
static PrinterUiPanel klipper_ui_panels[4] {
|
||||
{ .set_label = (void*)set_fan_speed_text, .open_panel = (void*)open_fan_speed_panel },
|
||||
{ .set_label = (void*)set_zoffset_text, .open_panel = (void*)open_zoffset_panel },
|
||||
{ .set_label = (void*)set_speed_mult_text, .open_panel = (void*)open_speed_mult_panel },
|
||||
{ .set_label = (void*)set_extrude_mult_text, .open_panel = (void*)open_extrude_mult_panel }
|
||||
};
|
||||
|
||||
void KlipperPrinter::init_ui_panels()
|
||||
{
|
||||
custom_menus_count = 4;
|
||||
custom_menus = klipper_ui_panels;
|
||||
}
|
||||
384
CYD-Klipper/src/core/klipper/klipper_printer_parsers.cpp
Normal file
384
CYD-Klipper/src/core/klipper/klipper_printer_parsers.cpp
Normal file
@@ -0,0 +1,384 @@
|
||||
#include "../printer_integration.hpp"
|
||||
#include "klipper_printer_integration.hpp"
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
int KlipperPrinter::parse_slicer_time_estimate(JsonDocument &in)
|
||||
{
|
||||
int time_estimate_s = in["result"]["estimated_time"];
|
||||
LOG_F(("Got slicer time estimate: %ds\n", time_estimate_s))
|
||||
return time_estimate_s;
|
||||
}
|
||||
|
||||
void KlipperPrinter::parse_state(JsonDocument &in)
|
||||
{
|
||||
JsonObject status = in["result"]["status"];
|
||||
|
||||
if (status.containsKey("webhooks"))
|
||||
{
|
||||
const char *state = status["webhooks"]["state"];
|
||||
const char *message = status["webhooks"]["state_message"];
|
||||
|
||||
if (strcmp(state, "ready") == 0 && printer_data.state == PrinterStateError)
|
||||
{
|
||||
printer_data.state = PrinterStateIdle;
|
||||
}
|
||||
else if ((strcmp(state, "shutdown") == 0 || strcmp(state, "error") == 0) && printer_data.state != PrinterStateError)
|
||||
{
|
||||
printer_data.state = PrinterStateError;
|
||||
}
|
||||
|
||||
if (message != NULL && (printer_data.state_message == NULL || strcmp(printer_data.state_message, message)))
|
||||
{
|
||||
printer_data.state_message = (char *)malloc(strlen(message) + 1);
|
||||
strcpy(printer_data.state_message, message);
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_data.state != PrinterStateError)
|
||||
{
|
||||
if (status.containsKey("extruder"))
|
||||
{
|
||||
printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] = status["extruder"]["temperature"];
|
||||
printer_data.target_temperatures[PrinterTemperatureDeviceIndexNozzle1] = status["extruder"]["target"];
|
||||
bool can_extrude = status["extruder"]["can_extrude"];
|
||||
printer_data.pressure_advance = status["extruder"]["pressure_advance"];
|
||||
printer_data.smooth_time = status["extruder"]["smooth_time"];
|
||||
printer_data.can_extrude = can_extrude == true;
|
||||
}
|
||||
|
||||
if (status.containsKey("heater_bed"))
|
||||
{
|
||||
printer_data.temperatures[PrinterTemperatureDeviceIndexBed] = status["heater_bed"]["temperature"];
|
||||
printer_data.target_temperatures[PrinterTemperatureDeviceIndexBed] = status["heater_bed"]["target"];
|
||||
}
|
||||
|
||||
if (status.containsKey("toolhead"))
|
||||
{
|
||||
const char *homed_axis = status["toolhead"]["homed_axes"];
|
||||
printer_data.homed_axis = strcmp(homed_axis, "xyz") == 0;
|
||||
}
|
||||
|
||||
if (status.containsKey("gcode_move"))
|
||||
{
|
||||
printer_data.position[0] = status["gcode_move"]["gcode_position"][0];
|
||||
printer_data.position[1] = status["gcode_move"]["gcode_position"][1];
|
||||
printer_data.position[2] = status["gcode_move"]["gcode_position"][2];
|
||||
gcode_offset[0] = status["gcode_move"]["homing_origin"][0];
|
||||
gcode_offset[1] = status["gcode_move"]["homing_origin"][1];
|
||||
gcode_offset[2] = status["gcode_move"]["homing_origin"][2];
|
||||
bool absolute_coords = status["gcode_move"]["absolute_coordinates"];
|
||||
|
||||
if (lock_absolute_relative_mode_swap > 0)
|
||||
{
|
||||
lock_absolute_relative_mode_swap--;
|
||||
}
|
||||
else
|
||||
{
|
||||
printer_data.absolute_coords = absolute_coords == true;
|
||||
}
|
||||
|
||||
printer_data.speed_mult = status["gcode_move"]["speed_factor"];
|
||||
printer_data.extrude_mult = status["gcode_move"]["extrude_factor"];
|
||||
printer_data.feedrate_mm_per_s = status["gcode_move"]["speed"];
|
||||
printer_data.feedrate_mm_per_s /= 60; // convert mm/m to mm/s
|
||||
}
|
||||
|
||||
if (status.containsKey("fan"))
|
||||
{
|
||||
printer_data.fan_speed = status["fan"]["speed"];
|
||||
}
|
||||
|
||||
if (status.containsKey("virtual_sdcard"))
|
||||
{
|
||||
printer_data.print_progress = status["virtual_sdcard"]["progress"];
|
||||
}
|
||||
|
||||
if (status.containsKey("print_stats"))
|
||||
{
|
||||
const char *filename = status["print_stats"]["filename"];
|
||||
|
||||
if (filename != NULL && (printer_data.print_filename == NULL || strcmp(printer_data.print_filename, filename)))
|
||||
{
|
||||
printer_data.print_filename = (char *)malloc(strlen(filename) + 1);
|
||||
strcpy(printer_data.print_filename, filename);
|
||||
}
|
||||
|
||||
printer_data.elapsed_time_s = status["print_stats"]["total_duration"];
|
||||
printer_data.printed_time_s = status["print_stats"]["print_duration"];
|
||||
printer_data.filament_used_mm = status["print_stats"]["filament_used"];
|
||||
printer_data.total_layers = status["print_stats"]["info"]["total_layer"];
|
||||
printer_data.current_layer = status["print_stats"]["info"]["current_layer"];
|
||||
|
||||
const char *state = status["print_stats"]["state"];
|
||||
|
||||
if (state == nullptr)
|
||||
{
|
||||
// Continue
|
||||
}
|
||||
else if (strcmp(state, "printing") == 0)
|
||||
{
|
||||
printer_data.state = PrinterStatePrinting;
|
||||
}
|
||||
else if (strcmp(state, "paused") == 0)
|
||||
{
|
||||
printer_data.state = PrinterStatePaused;
|
||||
}
|
||||
else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0)
|
||||
{
|
||||
printer_data.state = PrinterStateIdle;
|
||||
}
|
||||
}
|
||||
|
||||
if (status.containsKey("display_status"))
|
||||
{
|
||||
printer_data.print_progress = status["display_status"]["progress"];
|
||||
const char *message = status["display_status"]["message"];
|
||||
|
||||
if (!global_config.disable_m117_messaging && message != NULL && (printer_data.popup_message == NULL || strcmp(printer_data.popup_message, message)))
|
||||
{
|
||||
printer_data.popup_message = (char *)malloc(strlen(message) + 1);
|
||||
strcpy(printer_data.popup_message, message);
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_data.state == PrinterStatePrinting && printer_data.print_progress > 0)
|
||||
{
|
||||
float remaining_time_s_percentage = (printer_data.printed_time_s / printer_data.print_progress) - printer_data.printed_time_s;
|
||||
float remaining_time_s_slicer = 0;
|
||||
|
||||
if (slicer_estimated_print_time_s > 0)
|
||||
{
|
||||
remaining_time_s_slicer = slicer_estimated_print_time_s - printer_data.printed_time_s;
|
||||
}
|
||||
|
||||
if (remaining_time_s_slicer <= 0 || printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_PERCENTAGE)
|
||||
{
|
||||
printer_data.remaining_time_s = remaining_time_s_percentage;
|
||||
}
|
||||
else if (printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_INTERPOLATED)
|
||||
{
|
||||
printer_data.remaining_time_s = remaining_time_s_percentage * printer_data.print_progress + remaining_time_s_slicer * (1 - printer_data.print_progress);
|
||||
}
|
||||
else if (printer_config->remaining_time_calc_mode == REMAINING_TIME_CALC_SLICER)
|
||||
{
|
||||
printer_data.remaining_time_s = remaining_time_s_slicer;
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_data.remaining_time_s < 0)
|
||||
{
|
||||
printer_data.remaining_time_s = 0;
|
||||
}
|
||||
|
||||
if (printer_data.state == PrinterStateIdle)
|
||||
{
|
||||
slicer_estimated_print_time_s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_data.state == PrinterStatePrinting && millis() - last_slicer_time_query > 30000 && slicer_estimated_print_time_s <= 0)
|
||||
{
|
||||
last_slicer_time_query = millis();
|
||||
slicer_estimated_print_time_s = get_slicer_time_estimate_s();
|
||||
}
|
||||
}
|
||||
|
||||
void KlipperPrinter::parse_state_min(JsonDocument &in, PrinterDataMinimal* data)
|
||||
{
|
||||
JsonObject status = in["result"]["status"];
|
||||
|
||||
if (status.containsKey("webhooks"))
|
||||
{
|
||||
const char *state = status["webhooks"]["state"];
|
||||
|
||||
if (strcmp(state, "shutdown") == 0)
|
||||
{
|
||||
data->state = PrinterState::PrinterStateError;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->state != PrinterStateError)
|
||||
{
|
||||
if (status.containsKey("virtual_sdcard"))
|
||||
{
|
||||
data->print_progress = status["virtual_sdcard"]["progress"];
|
||||
}
|
||||
|
||||
if (status.containsKey("print_stats"))
|
||||
{
|
||||
const char *state = status["print_stats"]["state"];
|
||||
|
||||
if (state == nullptr)
|
||||
{
|
||||
data->state = PrinterState::PrinterStateError;
|
||||
}
|
||||
else if (strcmp(state, "printing") == 0)
|
||||
{
|
||||
data->state = PrinterState::PrinterStatePrinting;
|
||||
}
|
||||
else if (strcmp(state, "paused") == 0)
|
||||
{
|
||||
data->state = PrinterState::PrinterStatePaused;
|
||||
}
|
||||
else if (strcmp(state, "complete") == 0 || strcmp(state, "cancelled") == 0 || strcmp(state, "standby") == 0)
|
||||
{
|
||||
data->state = PrinterState::PrinterStateIdle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Macros KlipperPrinter::parse_macros(JsonDocument &in)
|
||||
{
|
||||
JsonObject result = in["result"];
|
||||
Macros macros = {0};
|
||||
macros.macros = (char **)malloc(sizeof(char *) * 32);
|
||||
macros.count = 0;
|
||||
macros.success = true;
|
||||
|
||||
for (JsonPair i : result)
|
||||
{
|
||||
const char *key = i.key().c_str();
|
||||
const char *value = i.value().as<String>().c_str();
|
||||
if (strcmp(value, "CYD_SCREEN_MACRO") == 0)
|
||||
{
|
||||
char *macro = (char *)malloc(strlen(key) + 1);
|
||||
strcpy(macro, key);
|
||||
macros.macros[macros.count++] = macro;
|
||||
}
|
||||
}
|
||||
|
||||
return macros;
|
||||
}
|
||||
|
||||
int KlipperPrinter::parse_macros_count(JsonDocument &in)
|
||||
{
|
||||
JsonObject result = in["result"];
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (JsonPair i : result)
|
||||
{
|
||||
const char *value = i.value().as<String>().c_str();
|
||||
if (strcmp(value, "CYD_SCREEN_MACRO") == 0)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
PowerDevices KlipperPrinter::parse_power_devices(JsonDocument &in)
|
||||
{
|
||||
PowerDevices power_devices = {0};
|
||||
JsonArray result = in["result"]["devices"];
|
||||
power_devices.power_devices = (char **)malloc(sizeof(char *) * 16);
|
||||
power_devices.power_states = (bool *)malloc(sizeof(bool) * 16);
|
||||
power_devices.count = 0;
|
||||
power_devices.success = true;
|
||||
|
||||
for (JsonObject i : result)
|
||||
{
|
||||
const char *device_name = i["device"];
|
||||
const char *device_state = i["status"];
|
||||
power_devices.power_devices[power_devices.count] = (char *)malloc(strlen(device_name) + 1);
|
||||
strcpy(power_devices.power_devices[power_devices.count], device_name);
|
||||
power_devices.power_states[power_devices.count] = strcmp(device_state, "on") == 0;
|
||||
power_devices.count++;
|
||||
}
|
||||
|
||||
return power_devices;
|
||||
}
|
||||
|
||||
int KlipperPrinter::parse_power_devices_count(JsonDocument &in)
|
||||
{
|
||||
JsonArray result = in["result"]["devices"];
|
||||
int count = 0;
|
||||
|
||||
for (JsonObject i : result)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void KlipperPrinter::parse_file_list(JsonDocument &in, std::list<KlipperFileSystemFile> &files, int fetch_limit)
|
||||
{
|
||||
JsonArray result = in["result"];
|
||||
|
||||
for (JsonObject file : result)
|
||||
{
|
||||
KlipperFileSystemFile f = {0};
|
||||
const char *path = file["path"];
|
||||
float modified = file["modified"];
|
||||
auto file_iter = files.begin();
|
||||
|
||||
while (file_iter != files.end())
|
||||
{
|
||||
if ((*file_iter).modified < modified)
|
||||
break;
|
||||
|
||||
file_iter++;
|
||||
}
|
||||
|
||||
if (file_iter == files.end() && files.size() >= fetch_limit)
|
||||
continue;
|
||||
|
||||
f.name = (char *)malloc(strlen(path) + 1);
|
||||
if (f.name == NULL)
|
||||
{
|
||||
LOG_LN("Failed to allocate memory");
|
||||
continue;
|
||||
}
|
||||
strcpy(f.name, path);
|
||||
f.modified = modified;
|
||||
|
||||
if (file_iter != files.end())
|
||||
files.insert(file_iter, f);
|
||||
else
|
||||
files.push_back(f);
|
||||
|
||||
if (files.size() > fetch_limit)
|
||||
{
|
||||
auto last_entry = files.back();
|
||||
|
||||
if (last_entry.name != NULL)
|
||||
free(last_entry.name);
|
||||
|
||||
files.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *KlipperPrinter::parse_thumbnails(JsonDocument &in)
|
||||
{
|
||||
JsonArray result = in["result"];
|
||||
const char *chosen_thumb = NULL;
|
||||
for (JsonObject file : result)
|
||||
{
|
||||
int width = file["width"];
|
||||
int height = file["height"];
|
||||
int size = file["size"];
|
||||
const char *thumbnail = file["thumbnail_path"];
|
||||
|
||||
if (width != height || width != 32)
|
||||
continue;
|
||||
|
||||
if (strcmp(thumbnail + strlen(thumbnail) - 4, ".png"))
|
||||
continue;
|
||||
|
||||
chosen_thumb = thumbnail;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chosen_thumb != NULL)
|
||||
{
|
||||
char* img_filename_path = (char *)malloc(strlen(chosen_thumb) + 1);
|
||||
strcpy(img_filename_path, chosen_thumb);
|
||||
return img_filename_path;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lvgl.h"
|
||||
#include "../ui/ui_utils.h"
|
||||
#include <Esp.h>
|
||||
#include "../ui/serial/serial_console.h"
|
||||
|
||||
#ifndef CPU_FREQ_HIGH
|
||||
#define CPU_FREQ_HIGH 240
|
||||
@@ -71,6 +72,7 @@ void lv_touch_intercept(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
|
||||
}
|
||||
|
||||
data->state = LV_INDEV_STATE_REL;
|
||||
delay(300); // Some screens don't debounce their signal properly
|
||||
}
|
||||
|
||||
screen_timer_wake();
|
||||
@@ -117,6 +119,7 @@ void lv_do_calibration(){
|
||||
|
||||
while (true){
|
||||
lv_handler();
|
||||
serial_console::run();
|
||||
|
||||
if (point[0] != 0 && point[1] != 0){
|
||||
break;
|
||||
@@ -175,7 +178,7 @@ void lv_do_calibration(){
|
||||
global_config.screen_cal_y_offset = 10.0 - ((float)y1 * global_config.screen_cal_y_mult);
|
||||
|
||||
if (global_config.screen_cal_x_mult == std::numeric_limits<float>::infinity() || global_config.screen_cal_y_mult == std::numeric_limits<float>::infinity()){
|
||||
Serial.println("Calibration failed, please try again");
|
||||
LOG_LN("Calibration failed, please try again");
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
@@ -183,7 +186,7 @@ void lv_do_calibration(){
|
||||
write_global_config();
|
||||
|
||||
lv_obj_clean(lv_scr_act());
|
||||
Serial.printf("Calibration done: X*%.2f + %.2f, Y*%.2f + %.2f\n", global_config.screen_cal_x_mult, global_config.screen_cal_x_offset, global_config.screen_cal_y_mult, global_config.screen_cal_y_offset);
|
||||
LOG_F(("Calibration done: X*%.2f + %.2f, Y*%.2f + %.2f\n", global_config.screen_cal_x_mult, global_config.screen_cal_x_offset, global_config.screen_cal_y_mult, global_config.screen_cal_y_offset))
|
||||
}
|
||||
|
||||
void set_screen_brightness()
|
||||
@@ -208,7 +211,7 @@ void screen_timer_wake()
|
||||
|
||||
// Reset cpu freq
|
||||
setCpuFrequencyMhz(CPU_FREQ_HIGH);
|
||||
Serial.printf("CPU Speed: %d MHz\n", ESP.getCpuFreqMHz());
|
||||
LOG_F(("CPU Speed: %d MHz\n", ESP.getCpuFreqMHz()))
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -220,7 +223,7 @@ void screen_timer_sleep(lv_timer_t *timer)
|
||||
|
||||
// Screen is off, no need to make the cpu run fast, the user won't notice ;)
|
||||
setCpuFrequencyMhz(CPU_FREQ_LOW);
|
||||
Serial.printf("CPU Speed: %d MHz\n", ESP.getCpuFreqMHz());
|
||||
LOG_F(("CPU Speed: %d MHz\n", ESP.getCpuFreqMHz()))
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -252,10 +255,10 @@ void set_screen_timer_period()
|
||||
|
||||
void set_color_scheme()
|
||||
{
|
||||
PRINTER_CONFIG *config = get_current_printer_config();
|
||||
PrinterConfiguration *config = &global_config.printer_config[global_config.printer_index];
|
||||
lv_disp_t *dispp = lv_disp_get_default();
|
||||
lv_color_t main_color = {0};
|
||||
COLOR_DEF color_def = color_defs[config->color_scheme];
|
||||
ColorDefinition color_def = color_defs[config->color_scheme];
|
||||
|
||||
if (color_defs[config->color_scheme].primary_color_light > 0){
|
||||
main_color = lv_palette_lighten(color_def.primary_color, color_def.primary_color_light);
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
#include "lvgl.h"
|
||||
#include "macros_query.h"
|
||||
#include "./data_setup.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <UrlEncode.h>
|
||||
#include "http_client.h"
|
||||
|
||||
static char* macros[64] = {0};
|
||||
static int macros_count = 0;
|
||||
|
||||
static char* power_devices[16] = {0};
|
||||
static bool power_device_states[16] = {0};
|
||||
static unsigned int stored_power_devices_count = 0;
|
||||
|
||||
MACROSQUERY macros_query(PRINTER_CONFIG * config)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, get_full_url("/printer/gcode/help", config), true, 1000);
|
||||
|
||||
int httpCode = client.GET();
|
||||
|
||||
if (httpCode == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
auto result = doc["result"].as<JsonObject>();
|
||||
|
||||
for (int i = 0; i < macros_count; i++){
|
||||
free(macros[i]);
|
||||
}
|
||||
|
||||
macros_count = 0;
|
||||
|
||||
for (JsonPair i : result){
|
||||
const char *key = i.key().c_str();
|
||||
const char *value = i.value().as<String>().c_str();
|
||||
if (strcmp(value, "CYD_SCREEN_MACRO") == 0) {
|
||||
char* macro = (char*)malloc(strlen(key) + 1);
|
||||
strcpy(macro, key);
|
||||
macros[macros_count++] = macro;
|
||||
}
|
||||
}
|
||||
|
||||
return {(const char**)macros, (unsigned int)macros_count};
|
||||
}
|
||||
else {
|
||||
return {NULL, 0};
|
||||
}
|
||||
}
|
||||
|
||||
MACROSQUERY macros_query()
|
||||
{
|
||||
return macros_query(get_current_printer_config());
|
||||
}
|
||||
|
||||
unsigned int macro_count(PRINTER_CONFIG * config)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, get_full_url("/printer/gcode/help", config), true, 1000);
|
||||
|
||||
int httpCode = client.GET();
|
||||
|
||||
if (httpCode == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
auto result = doc["result"].as<JsonObject>();
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
for (JsonPair i : result){
|
||||
const char *value = i.value().as<String>().c_str();
|
||||
if (strcmp(value, "CYD_SCREEN_MACRO") == 0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int macro_count()
|
||||
{
|
||||
return macro_count(get_current_printer_config());
|
||||
}
|
||||
|
||||
POWERQUERY power_devices_query(PRINTER_CONFIG * config)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, get_full_url("/machine/device_power/devices", config), true, 1000);
|
||||
|
||||
int httpCode = client.GET();
|
||||
|
||||
if (httpCode == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
auto result = doc["result"]["devices"].as<JsonArray>();
|
||||
|
||||
for (int i = 0; i < stored_power_devices_count; i++){
|
||||
free(power_devices[i]);
|
||||
}
|
||||
|
||||
stored_power_devices_count = 0;
|
||||
|
||||
for (auto i : result){
|
||||
const char * device_name = i["device"];
|
||||
const char * device_state = i["status"];
|
||||
power_devices[stored_power_devices_count] = (char*)malloc(strlen(device_name) + 1);
|
||||
strcpy(power_devices[stored_power_devices_count], device_name);
|
||||
power_device_states[stored_power_devices_count] = strcmp(device_state, "on") == 0;
|
||||
stored_power_devices_count++;
|
||||
}
|
||||
|
||||
return {(const char**)power_devices, (const bool*)power_device_states, (unsigned int)stored_power_devices_count};
|
||||
}
|
||||
else {
|
||||
return {NULL, NULL, 0};
|
||||
}
|
||||
}
|
||||
|
||||
POWERQUERY power_devices_query()
|
||||
{
|
||||
return power_devices_query(get_current_printer_config());
|
||||
}
|
||||
|
||||
unsigned int power_devices_count(PRINTER_CONFIG * config)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, get_full_url("/machine/device_power/devices", config), true, 1000);
|
||||
|
||||
int httpCode = client.GET();
|
||||
|
||||
if (httpCode == 200){
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
auto result = doc["result"]["devices"].as<JsonArray>();
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
for (auto i : result){
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int power_devices_count()
|
||||
{
|
||||
return power_devices_count(get_current_printer_config());
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool set_power_state(const char* device_name, bool state, PRINTER_CONFIG * config)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, get_full_url("/machine/device_power/device?device=" + urlEncode(device_name) + "&action=" + (state ? "on" : "off"), config), true, 1000);
|
||||
|
||||
return client.POST("") == 200;
|
||||
}
|
||||
|
||||
bool set_power_state(const char* device_name, bool state)
|
||||
{
|
||||
return set_power_state(device_name, state, get_current_printer_config());
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../conf/global_config.h"
|
||||
|
||||
typedef struct {
|
||||
const char** macros;
|
||||
uint32_t count;
|
||||
} MACROSQUERY;
|
||||
|
||||
typedef struct {
|
||||
const char** power_devices;
|
||||
const bool* power_states;
|
||||
uint32_t count;
|
||||
} POWERQUERY;
|
||||
|
||||
MACROSQUERY macros_query(PRINTER_CONFIG * config);
|
||||
MACROSQUERY macros_query();
|
||||
unsigned int macro_count(PRINTER_CONFIG * config);
|
||||
unsigned int macro_count();
|
||||
POWERQUERY power_devices_query(PRINTER_CONFIG * config);
|
||||
POWERQUERY power_devices_query();
|
||||
unsigned int power_devices_count(PRINTER_CONFIG * config);
|
||||
unsigned int power_devices_count();
|
||||
bool set_power_state(const char* device_name, bool state, PRINTER_CONFIG * config);
|
||||
bool set_power_state(const char* device_name, bool state);
|
||||
450
CYD-Klipper/src/core/octoprint/octoprint_printer_integration.cpp
Normal file
450
CYD-Klipper/src/core/octoprint/octoprint_printer_integration.cpp
Normal file
@@ -0,0 +1,450 @@
|
||||
#include "octoprint_printer_integration.hpp"
|
||||
#include "../../conf/global_config.h"
|
||||
#include <HTTPClient.h>
|
||||
#include <UrlEncode.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <list>
|
||||
|
||||
const char* COMMAND_CONNECT = "{\"command\":\"connect\"}";
|
||||
const char* COMMAND_DISCONNECT = "{\"command\":\"disconnect\"}";
|
||||
const char* COMMAND_HOME = "{\"command\":\"home\",\"axes\":[\"x\",\"y\",\"z\"]}";
|
||||
const char* COMMAND_PRINT = "{\"command\":\"select\",\"print\":true}";
|
||||
const char* COMMAND_CANCEL_PRINT = "{\"command\":\"cancel\"}";
|
||||
const char* COMMAND_PAUSE_PRINT = "{\"command\":\"pause\",\"action\":\"pause\"}";
|
||||
const char* COMMAND_RESUME_PRINT = "{\"command\":\"pause\",\"action\":\"resume\"}";
|
||||
const char* COMMAND_EXTRUDE = "{\"command\":\"extrude\",\"amount\":25}";
|
||||
const char* COMMAND_RETRACT = "{\"command\":\"extrude\",\"amount\":-25}";
|
||||
|
||||
void configure_http_client(HTTPClient &client, String url_part, bool stream, int timeout, PrinterConfiguration* printer_config)
|
||||
{
|
||||
client.useHTTP10(stream);
|
||||
|
||||
if (timeout > 0){
|
||||
client.setTimeout(timeout);
|
||||
client.setConnectTimeout(timeout);
|
||||
}
|
||||
|
||||
client.begin("http://" + String(printer_config->printer_host) + ":" + String(printer_config->klipper_port) + url_part);
|
||||
|
||||
if (printer_config->auth_configured) {
|
||||
client.addHeader("X-Api-Key", printer_config->printer_auth);
|
||||
}
|
||||
}
|
||||
|
||||
bool OctoPrinter::get_request(const char* endpoint, int timeout_ms)
|
||||
{
|
||||
HTTPClient client;
|
||||
|
||||
if (timeout_ms <= 0)
|
||||
{
|
||||
timeout_ms = 500;
|
||||
}
|
||||
|
||||
configure_http_client(client, endpoint, false, timeout_ms, printer_config);
|
||||
int result = client.GET();
|
||||
return result >= 200 && result < 300;
|
||||
}
|
||||
|
||||
bool OctoPrinter::post_request(const char* endpoint, const char* body, int timeout_ms)
|
||||
{
|
||||
HTTPClient client;
|
||||
|
||||
if (timeout_ms <= 0)
|
||||
{
|
||||
timeout_ms = 500;
|
||||
}
|
||||
|
||||
LOG_F(("POST >>> %s %s\n", endpoint, body));
|
||||
configure_http_client(client, endpoint, false, timeout_ms, printer_config);
|
||||
|
||||
if (body[0] == '{' || body[0] == '[')
|
||||
{
|
||||
client.addHeader("Content-Type", "application/json");
|
||||
}
|
||||
|
||||
int http_code = client.POST(body);
|
||||
bool result = http_code >= 200 && http_code < 300;
|
||||
LOG_F(("<<< %d\n", http_code));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool OctoPrinter::send_gcode(const char* gcode, bool wait)
|
||||
{
|
||||
char* gcode_copy = (char*)malloc(sizeof(char) * (strlen(gcode) + 1));
|
||||
size_t out_buff_size = sizeof(char) * (strlen(gcode) * 2 + 51);
|
||||
char* out_buff = (char*)malloc(out_buff_size);
|
||||
strcpy(gcode_copy, gcode);
|
||||
JsonDocument doc;
|
||||
JsonArray array = doc["commands"].to<JsonArray>();
|
||||
const char* last_line_start = gcode_copy;
|
||||
|
||||
for (char* iter = gcode_copy;; iter++)
|
||||
{
|
||||
char cur_iter = *iter;
|
||||
if (cur_iter == '\n' || cur_iter == '\0')
|
||||
{
|
||||
if (iter != last_line_start)
|
||||
{
|
||||
*iter = '\0';
|
||||
array.add(last_line_start);
|
||||
}
|
||||
|
||||
last_line_start = iter + 1;
|
||||
}
|
||||
|
||||
if (cur_iter == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (serializeJson(doc, out_buff, out_buff_size) == out_buff_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
free(gcode_copy);
|
||||
bool result = post_request("/api/printer/command", out_buff);
|
||||
free(out_buff);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool OctoPrinter::move_printer(const char* axis, float amount, bool relative)
|
||||
{
|
||||
JsonDocument doc;
|
||||
char out_buff[512];
|
||||
out_buff[0] = tolower(axis[0]);
|
||||
out_buff[1] = '\0';
|
||||
|
||||
doc["command"] = "jog";
|
||||
doc[out_buff] = amount;
|
||||
doc["absolute"] = !relative;
|
||||
|
||||
if (serializeJson(doc, out_buff, 512) >= 512)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return post_request("/api/printer/printhead", out_buff);
|
||||
}
|
||||
|
||||
bool OctoPrinter::execute_feature(PrinterFeatures feature)
|
||||
{
|
||||
switch (feature)
|
||||
{
|
||||
case PrinterFeatureRetryError:
|
||||
if (no_printer)
|
||||
{
|
||||
bool a = post_request("/api/connection", COMMAND_CONNECT);
|
||||
LOG_F(("Retry error: %d\n", a));
|
||||
return a;
|
||||
}
|
||||
case PrinterFeatureHome:
|
||||
return post_request("/api/printer/printhead", COMMAND_HOME);
|
||||
case PrinterFeatureDisableSteppers:
|
||||
return send_gcode("M18");
|
||||
case PrinterFeaturePause:
|
||||
return post_request("/api/job", COMMAND_PAUSE_PRINT);
|
||||
case PrinterFeatureResume:
|
||||
return post_request("/api/job", COMMAND_RESUME_PRINT);
|
||||
case PrinterFeatureStop:
|
||||
return post_request("/api/job", COMMAND_CANCEL_PRINT);
|
||||
case PrinterFeatureCooldown:
|
||||
return set_target_temperature(PrinterTemperatureDeviceNozzle1, 0)
|
||||
&& set_target_temperature(PrinterTemperatureDeviceBed, 0);
|
||||
case PrinterFeatureExtrude:
|
||||
return post_request("/api/printer/tool", COMMAND_EXTRUDE);
|
||||
case PrinterFeatureRetract:
|
||||
return post_request("/api/printer/tool", COMMAND_RETRACT);
|
||||
default:
|
||||
LOG_F(("Unsupported printer feature %d", feature));
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OctoPrinter::connect()
|
||||
{
|
||||
return connection_test_octoprint(printer_config) == OctoConnectionStatus::OctoConnectOk;
|
||||
}
|
||||
|
||||
bool OctoPrinter::fetch()
|
||||
{
|
||||
HTTPClient client;
|
||||
HTTPClient client2;
|
||||
configure_http_client(client, "/api/printer", true, 1000, printer_config);
|
||||
|
||||
int http_code = client.GET();
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
no_printer = false;
|
||||
request_consecutive_fail_count = 0;
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
parse_printer_status(doc);
|
||||
|
||||
doc.clear();
|
||||
configure_http_client(client2, "/api/job", true, 1000, printer_config);
|
||||
if (client2.GET() == 200)
|
||||
{
|
||||
deserializeJson(doc, client2.getStream());
|
||||
parse_job_state(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
printer_data.state = PrinterStateOffline;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (http_code == 409)
|
||||
{
|
||||
no_printer = true;
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
parse_error(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
request_consecutive_fail_count++;
|
||||
LOG_LN("Failed to fetch printer data");
|
||||
|
||||
if (request_consecutive_fail_count >= 5)
|
||||
{
|
||||
printer_data.state = PrinterStateOffline;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PrinterDataMinimal OctoPrinter::fetch_min()
|
||||
{
|
||||
PrinterDataMinimal min = {};
|
||||
min.success = true;
|
||||
min.print_progress = 0;
|
||||
min.power_devices = 0;
|
||||
min.state = PrinterState::PrinterStateOffline;
|
||||
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/api/printer", true, 1000, printer_config);
|
||||
int http_code = client.GET();
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
min.state = parse_printer_state(doc);
|
||||
}
|
||||
else if (http_code == 409)
|
||||
{
|
||||
min.state = PrinterState::PrinterStateError;
|
||||
return min;
|
||||
}
|
||||
else
|
||||
{
|
||||
return min;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/api/job", true, 1000, printer_config);
|
||||
|
||||
if (client.GET() == 200)
|
||||
{
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, client.getStream());
|
||||
min.print_progress = parse_job_state_progress(doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
min.state = PrinterState::PrinterStateError;
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
void OctoPrinter::disconnect()
|
||||
{
|
||||
}
|
||||
|
||||
const char* MACRO_AUTOLEVEL = "Auto-Level (G28+G29)";
|
||||
const char* MACRO_DISCONNECT = "Disconnect printer";
|
||||
|
||||
Macros OctoPrinter::get_macros()
|
||||
{
|
||||
if (printer_data.state == PrinterStatePrinting || printer_data.state == PrinterStateOffline)
|
||||
{
|
||||
Macros macros = {0};
|
||||
macros.success = false;
|
||||
return macros;
|
||||
}
|
||||
|
||||
Macros macros = {0};
|
||||
macros.count = 2;
|
||||
macros.macros = (char **)malloc(sizeof(char *) * macros.count);
|
||||
macros.macros[0] = (char *)malloc(strlen(MACRO_AUTOLEVEL) + 1);
|
||||
strcpy(macros.macros[0], MACRO_AUTOLEVEL);
|
||||
macros.macros[1] = (char *)malloc(strlen(MACRO_DISCONNECT) + 1);
|
||||
strcpy(macros.macros[1], MACRO_DISCONNECT);
|
||||
macros.success = true;
|
||||
return macros;
|
||||
}
|
||||
|
||||
int OctoPrinter::get_macros_count()
|
||||
{
|
||||
return (printer_data.state == PrinterStatePrinting || printer_data.state == PrinterStateOffline) ? 0 : 2;
|
||||
}
|
||||
|
||||
bool OctoPrinter::execute_macro(const char* macro)
|
||||
{
|
||||
if (strcmp(macro, MACRO_AUTOLEVEL) == 0)
|
||||
{
|
||||
return send_gcode("G28\nG29");
|
||||
}
|
||||
else if (strcmp(macro, MACRO_DISCONNECT) == 0)
|
||||
{
|
||||
if (printer_data.state == PrinterStatePrinting || printer_data.state == PrinterStateOffline)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return post_request("/api/connection", COMMAND_DISCONNECT);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PowerDevices OctoPrinter::get_power_devices()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
int OctoPrinter::get_power_devices_count()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool OctoPrinter::set_power_device_state(const char* device_name, bool state)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#define OCTO_FILE_FETCH_LIMIT 20
|
||||
|
||||
Files OctoPrinter::get_files()
|
||||
{
|
||||
LOG_F(("Heap space pre-file-parse: %d bytes\n", esp_get_free_heap_size()));
|
||||
|
||||
Files files_result = {0};
|
||||
HTTPClient client;
|
||||
JsonDocument filter;
|
||||
std::list<OctoFileSystemFile> files;
|
||||
|
||||
filter["files"][0]["path"] = true;
|
||||
filter["files"][0]["date"] = true;
|
||||
filter["files"][0]["origin"] = true;
|
||||
|
||||
auto timer_request = millis();
|
||||
configure_http_client(client, "/api/files?recursive=true", true, 5000, printer_config);
|
||||
|
||||
int http_code = client.GET();
|
||||
auto timer_parse = millis();
|
||||
|
||||
if (http_code == 200)
|
||||
{
|
||||
JsonDocument doc;
|
||||
auto parseResult = deserializeJson(doc, client.getStream(), DeserializationOption::Filter(filter));
|
||||
LOG_F(("Json parse: %s\n", parseResult.c_str()))
|
||||
parse_file_list(doc, files, OCTO_FILE_FETCH_LIMIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
return files_result;
|
||||
}
|
||||
|
||||
files_result.available_files = (char**)malloc(sizeof(char*) * files.size());
|
||||
|
||||
if (files_result.available_files == NULL){
|
||||
LOG_LN("Failed to allocate memory");
|
||||
|
||||
for (auto file : files){
|
||||
free(file.name);
|
||||
}
|
||||
|
||||
return files_result;
|
||||
}
|
||||
|
||||
for (auto file : files){
|
||||
files_result.available_files[files_result.count++] = file.name;
|
||||
}
|
||||
|
||||
files_result.success = true;
|
||||
|
||||
LOG_F(("Heap space post-file-parse: %d bytes\n", esp_get_free_heap_size()))
|
||||
LOG_F(("Got %d files. Request took %dms, parsing took %dms\n", files.size(), timer_parse - timer_request, millis() - timer_parse))
|
||||
return files_result;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool OctoPrinter::start_file(const char* filename)
|
||||
{
|
||||
char buff[512];
|
||||
sprintf(buff, "/api/files/local/%s", filename);
|
||||
return post_request(buff, COMMAND_PRINT);
|
||||
}
|
||||
|
||||
Thumbnail OctoPrinter::get_32_32_png_image_thumbnail(const char* gcode_filename)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool OctoPrinter::set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature)
|
||||
{
|
||||
JsonDocument doc;
|
||||
char out_buff[512];
|
||||
|
||||
doc["command"] = "target";
|
||||
|
||||
if (device == PrinterTemperatureDevice::PrinterTemperatureDeviceNozzle1)
|
||||
{
|
||||
doc["targets"]["tool0"] = temperature;
|
||||
}
|
||||
else
|
||||
{
|
||||
doc["target"] = temperature;
|
||||
}
|
||||
|
||||
if (serializeJson(doc, out_buff, 512) >= 512)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return post_request(device == PrinterTemperatureDevice::PrinterTemperatureDeviceBed ? "/api/printer/bed" : "/api/printer/tool", out_buff);
|
||||
}
|
||||
|
||||
OctoConnectionStatus connection_test_octoprint(PrinterConfiguration* config)
|
||||
{
|
||||
HTTPClient client;
|
||||
configure_http_client(client, "/api/version", false, 1000, config);
|
||||
|
||||
int http_code = client.GET();
|
||||
if (http_code == 200)
|
||||
{
|
||||
return OctoConnectionStatus::OctoConnectOk;
|
||||
}
|
||||
else if (http_code == 401 || http_code == 403)
|
||||
{
|
||||
return OctoConnectionStatus::OctoConnectKeyFail;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OctoConnectionStatus::OctoConnectFail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "../printer_integration.hpp"
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <list>
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
float modified;
|
||||
} OctoFileSystemFile;
|
||||
|
||||
class OctoPrinter : public BasePrinter
|
||||
{
|
||||
protected:
|
||||
bool no_printer = false;
|
||||
unsigned char request_consecutive_fail_count{};
|
||||
|
||||
void parse_printer_status(JsonDocument& in);
|
||||
PrinterState parse_printer_state(JsonDocument& in);
|
||||
void parse_job_state(JsonDocument& in);
|
||||
float parse_job_state_progress(JsonDocument& in);
|
||||
void parse_error(JsonDocument& in);
|
||||
void parse_file_list(JsonDocument &in, std::list<OctoFileSystemFile> &files, int fetch_limit);
|
||||
|
||||
bool get_request(const char* endpoint, int timeout_ms = 1000);
|
||||
void init_ui_panels();
|
||||
|
||||
public:
|
||||
OctoPrinter(int index) : BasePrinter(index)
|
||||
{
|
||||
supported_features = PrinterFeatureHome
|
||||
| PrinterFeatureDisableSteppers
|
||||
| PrinterFeaturePause
|
||||
| PrinterFeatureResume
|
||||
| PrinterFeatureStop
|
||||
| PrinterFeatureExtrude
|
||||
| PrinterFeatureRetract
|
||||
| PrinterFeatureCooldown
|
||||
| PrinterFeatureRetryError;
|
||||
|
||||
supported_temperature_devices = PrinterTemperatureDeviceBed
|
||||
| PrinterTemperatureDeviceNozzle1;
|
||||
|
||||
printer_data.error_screen_features = PrinterFeatureRetryError;
|
||||
|
||||
init_ui_panels();
|
||||
}
|
||||
|
||||
bool post_request(const char* endpoint, const char* body, int timeout_ms = 1000);
|
||||
bool move_printer(const char* axis, float amount, bool relative);
|
||||
bool execute_feature(PrinterFeatures feature);
|
||||
bool connect();
|
||||
bool fetch();
|
||||
PrinterDataMinimal fetch_min();
|
||||
void disconnect();
|
||||
|
||||
Macros get_macros();
|
||||
int get_macros_count();
|
||||
bool execute_macro(const char* macro);
|
||||
|
||||
PowerDevices get_power_devices();
|
||||
int get_power_devices_count();
|
||||
bool set_power_device_state(const char* device_name, bool state);
|
||||
|
||||
Files get_files();
|
||||
bool start_file(const char* filename);
|
||||
|
||||
Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename);
|
||||
bool set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature);
|
||||
|
||||
bool send_gcode(const char* gcode, bool wait = true);
|
||||
};
|
||||
|
||||
enum OctoConnectionStatus {
|
||||
OctoConnectFail = 0,
|
||||
OctoConnectOk = 1,
|
||||
OctoConnectKeyFail = 2,
|
||||
};
|
||||
|
||||
OctoConnectionStatus connection_test_octoprint(PrinterConfiguration* config);
|
||||
111
CYD-Klipper/src/core/octoprint/octoprint_printer_panels.cpp
Normal file
111
CYD-Klipper/src/core/octoprint/octoprint_printer_panels.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "octoprint_printer_integration.hpp"
|
||||
#include "lvgl.h"
|
||||
#include "../../ui/ui_utils.h"
|
||||
#include <stdio.h>
|
||||
#include "../common/constants.h"
|
||||
|
||||
const char* COMMAND_EXTRUDE_MULT = "{\"command\":\"flowrate\",\"factor\":%d}";
|
||||
|
||||
#define OCTO_TIMEOUT_POPUP_MESSAGES 4000
|
||||
|
||||
static void set_fan_speed_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_label_set_text(label, "Fan");
|
||||
}
|
||||
|
||||
static void set_speed_mult_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_label_set_text(label, "Speed");
|
||||
}
|
||||
|
||||
static void set_extruder_mult_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_label_set_text(label, "Flowrate");
|
||||
}
|
||||
|
||||
bool get_range(lv_event_t * e, int min, int max, int* out)
|
||||
{
|
||||
char buff[64];
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
lv_obj_t * kb = (lv_obj_t *)lv_event_get_user_data(e);
|
||||
const char * txt = lv_textarea_get_text(ta);
|
||||
|
||||
if (txt == NULL || *txt == '\0')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int parsed_input = atoi(txt);
|
||||
if (parsed_input < min || parsed_input > max)
|
||||
{
|
||||
sprintf(buff, "Value out of range (%d -> %d)", min, max);
|
||||
lv_create_popup_message(buff, OCTO_TIMEOUT_POPUP_MESSAGES);
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = parsed_input;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_fan_speed(lv_event_t * e)
|
||||
{
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
int actual_fan_speed = fan_percent_to_byte(speed);
|
||||
char buff[16];
|
||||
sprintf(buff, "M106 S%d", actual_fan_speed);
|
||||
((OctoPrinter*)get_current_printer())->send_gcode(buff);
|
||||
}
|
||||
|
||||
FAN_SPEED_COLUMN(set_fan_speed, octo_fan_speed_columns)
|
||||
|
||||
static void open_fan_speed_panel(lv_event_t * e)
|
||||
{
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_fan_speed_text, octo_fan_speed_columns, 3);
|
||||
}
|
||||
|
||||
static void set_speed_mult(lv_event_t * e)
|
||||
{
|
||||
int speed_mult = 0;
|
||||
if (get_range(e, 50, 300, &speed_mult))
|
||||
{
|
||||
char buff[16];
|
||||
sprintf(buff, "M220 S%d", speed_mult);
|
||||
((OctoPrinter*)get_current_printer())->send_gcode(buff);
|
||||
}
|
||||
}
|
||||
|
||||
static void open_speed_mult_keypad(lv_event_t * e)
|
||||
{
|
||||
lv_create_keyboard_text_entry(set_speed_mult, "New speed multiplier %", LV_KEYBOARD_MODE_NUMBER);
|
||||
}
|
||||
|
||||
static void set_extrude_mult(lv_event_t * e)
|
||||
{
|
||||
int extrude_mult = 0;
|
||||
if (get_range(e, 75, 125, &extrude_mult))
|
||||
{
|
||||
char buff[64];
|
||||
sprintf(buff, COMMAND_EXTRUDE_MULT, extrude_mult);
|
||||
((OctoPrinter*)get_current_printer())->post_request("/api/printer/tool", buff);
|
||||
}
|
||||
}
|
||||
|
||||
static void open_extrude_mult_keypad(lv_event_t * e)
|
||||
{
|
||||
lv_create_keyboard_text_entry(set_extrude_mult, "New extrude multiplier %", LV_KEYBOARD_MODE_NUMBER);
|
||||
}
|
||||
|
||||
static PrinterUiPanel klipper_ui_panels[4] {
|
||||
{ .set_label = (void*)set_fan_speed_text, .open_panel = (void*)open_fan_speed_panel },
|
||||
{ .set_label = (void*)set_speed_mult_text, .open_panel = (void*)open_speed_mult_keypad },
|
||||
{ .set_label = (void*)set_extruder_mult_text, .open_panel = (void*)open_extrude_mult_keypad },
|
||||
};
|
||||
|
||||
void OctoPrinter::init_ui_panels()
|
||||
{
|
||||
custom_menus_count = 3;
|
||||
custom_menus = klipper_ui_panels;
|
||||
}
|
||||
170
CYD-Klipper/src/core/octoprint/octoprint_printer_parsers.cpp
Normal file
170
CYD-Klipper/src/core/octoprint/octoprint_printer_parsers.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "../printer_integration.hpp"
|
||||
#include "octoprint_printer_integration.hpp"
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
PrinterState OctoPrinter::parse_printer_state(JsonDocument& in)
|
||||
{
|
||||
JsonObject flags = in["state"]["flags"];
|
||||
bool cancelling = flags["cancelling"];
|
||||
bool closedOrError = flags["closedOrError"];
|
||||
bool error = flags["error"];
|
||||
bool finishing = flags["finishing"];
|
||||
bool operational = flags["operational"];
|
||||
bool paused = flags["paused"];
|
||||
bool pausing = flags["pausing"];
|
||||
bool printing = flags["printing"];
|
||||
bool ready = flags["ready"];
|
||||
bool resuming = flags["resuming"];
|
||||
bool sdReady = flags["sdReady"];
|
||||
|
||||
if (printing || resuming)
|
||||
{
|
||||
return PrinterState::PrinterStatePrinting;
|
||||
}
|
||||
else if (pausing || paused)
|
||||
{
|
||||
return PrinterState::PrinterStatePaused;
|
||||
}
|
||||
else if (cancelling || finishing || ready)
|
||||
{
|
||||
return PrinterState::PrinterStateIdle;
|
||||
}
|
||||
|
||||
return PrinterState::PrinterStateError;
|
||||
}
|
||||
|
||||
void OctoPrinter::parse_printer_status(JsonDocument& in)
|
||||
{
|
||||
const char* text = in["state"]["text"];
|
||||
printer_data.state = parse_printer_state(in);
|
||||
|
||||
if (printer_data.state == PrinterState::PrinterStateError)
|
||||
{
|
||||
if (text != NULL && (printer_data.state_message == NULL || strcmp(printer_data.state_message, text)))
|
||||
{
|
||||
printer_data.state_message = (char *)malloc(strlen(text) + 1);
|
||||
strcpy(printer_data.state_message, text);
|
||||
}
|
||||
}
|
||||
|
||||
JsonObject temperature = in["temperature"];
|
||||
|
||||
if (temperature.containsKey("bed"))
|
||||
{
|
||||
printer_data.temperatures[PrinterTemperatureDeviceIndexBed] = temperature["bed"]["actual"];
|
||||
printer_data.target_temperatures[PrinterTemperatureDeviceIndexBed] = temperature["bed"]["target"];
|
||||
}
|
||||
|
||||
if (temperature.containsKey("tool0"))
|
||||
{
|
||||
printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] = temperature["tool0"]["actual"];
|
||||
printer_data.target_temperatures[PrinterTemperatureDeviceIndexNozzle1] = temperature["tool0"]["target"];
|
||||
}
|
||||
|
||||
printer_data.can_extrude = printer_data.temperatures[PrinterTemperatureDeviceIndexNozzle1] >= MIN_EXTRUDER_EXTRUDE_TEMP;
|
||||
printer_data.homed_axis = true;
|
||||
}
|
||||
|
||||
void OctoPrinter::parse_job_state(JsonDocument& in)
|
||||
{
|
||||
JsonObject job = in["job"];
|
||||
|
||||
if (job.containsKey("file"))
|
||||
{
|
||||
const char* name = job["file"]["name"];
|
||||
|
||||
if (name != NULL && (printer_data.print_filename == NULL || strcmp(printer_data.print_filename, name)))
|
||||
{
|
||||
printer_data.print_filename = (char *)malloc(strlen(name) + 1);
|
||||
strcpy(printer_data.print_filename, name);
|
||||
}
|
||||
}
|
||||
|
||||
if (job.containsKey("filament") && job["filament"].as<JsonObject>() != NULL && job["filament"].containsKey("tool0"))
|
||||
{
|
||||
printer_data.filament_used_mm = job["filament"]["tool0"]["length"];
|
||||
}
|
||||
|
||||
JsonObject progress = in["progress"];
|
||||
float completion = progress["completion"];
|
||||
printer_data.print_progress = completion / 100;
|
||||
printer_data.elapsed_time_s = progress["printTime"];
|
||||
printer_data.printed_time_s = progress["printTime"];
|
||||
printer_data.remaining_time_s = progress["printTimeLeft"];
|
||||
}
|
||||
|
||||
float OctoPrinter::parse_job_state_progress(JsonDocument& in)
|
||||
{
|
||||
float completion = in["progress"]["completion"];
|
||||
return completion / 100;
|
||||
}
|
||||
|
||||
void OctoPrinter::parse_error(JsonDocument& in)
|
||||
{
|
||||
const char* error = in["error"];
|
||||
if (error != NULL)
|
||||
{
|
||||
printer_data.state = PrinterState::PrinterStateError;
|
||||
|
||||
if (printer_data.state_message == NULL || strcmp(printer_data.state_message, error))
|
||||
{
|
||||
printer_data.state_message = (char *)malloc(strlen(error) + 1);
|
||||
strcpy(printer_data.state_message, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctoPrinter::parse_file_list(JsonDocument &in, std::list<OctoFileSystemFile> &files, int fetch_limit)
|
||||
{
|
||||
JsonArray result = in["files"];
|
||||
|
||||
for (JsonObject file : result)
|
||||
{
|
||||
const char *path = file["path"];
|
||||
if (strcmp("local", file["origin"]))
|
||||
{
|
||||
LOG_F(("Skipping non-local file %s\n", path))
|
||||
continue;
|
||||
}
|
||||
|
||||
OctoFileSystemFile f = {0};
|
||||
|
||||
float modified = file["date"];
|
||||
auto file_iter = files.begin();
|
||||
|
||||
while (file_iter != files.end())
|
||||
{
|
||||
if ((*file_iter).modified < modified)
|
||||
break;
|
||||
|
||||
file_iter++;
|
||||
}
|
||||
|
||||
if (file_iter == files.end() && files.size() >= fetch_limit)
|
||||
continue;
|
||||
|
||||
f.name = (char *)malloc(strlen(path) + 1);
|
||||
if (f.name == NULL)
|
||||
{
|
||||
LOG_LN("Failed to allocate memory");
|
||||
continue;
|
||||
}
|
||||
strcpy(f.name, path);
|
||||
f.modified = modified;
|
||||
|
||||
if (file_iter != files.end())
|
||||
files.insert(file_iter, f);
|
||||
else
|
||||
files.push_back(f);
|
||||
|
||||
if (files.size() > fetch_limit)
|
||||
{
|
||||
auto last_entry = files.back();
|
||||
|
||||
if (last_entry.name != NULL)
|
||||
free(last_entry.name);
|
||||
|
||||
files.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
141
CYD-Klipper/src/core/printer_integration.cpp
Normal file
141
CYD-Klipper/src/core/printer_integration.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "printer_integration.hpp"
|
||||
#include "lv_setup.h"
|
||||
#include "screen_driver.h"
|
||||
#include <HardwareSerial.h>
|
||||
|
||||
static char blank[] = { '\0' };
|
||||
static unsigned char current_printer_index = 0;
|
||||
static unsigned char last_announced_printer_index = 0;
|
||||
static unsigned char total_printers;
|
||||
static BasePrinter** registered_printers;
|
||||
static PrinterDataMinimal* minimal_data_copy;
|
||||
static PrinterData* printer_data_copy;
|
||||
|
||||
BasePrinter::BasePrinter(unsigned char index)
|
||||
{
|
||||
config_index = index;
|
||||
printer_config = &global_config.printer_config[index];
|
||||
memset(&printer_data, 0, sizeof(PrinterData));
|
||||
// TODO: Fetch printer config and global config
|
||||
}
|
||||
|
||||
PrinterData* BasePrinter::AnnouncePrinterData()
|
||||
{
|
||||
char* old_state_message = printer_data_copy->state_message;
|
||||
char* old_print_filename = printer_data_copy->print_filename;
|
||||
char* old_popup_message = printer_data_copy->popup_message;
|
||||
PrinterState old_state = printer_data_copy->state;
|
||||
bool no_free = current_printer_index != last_announced_printer_index;
|
||||
|
||||
last_announced_printer_index = current_printer_index;
|
||||
memcpy(printer_data_copy, &printer_data, sizeof(PrinterData));
|
||||
|
||||
if (printer_data_copy->state_message == NULL)
|
||||
{
|
||||
printer_data_copy->state_message = blank;
|
||||
}
|
||||
|
||||
if (printer_data_copy->print_filename == NULL)
|
||||
{
|
||||
printer_data_copy->print_filename = blank;
|
||||
}
|
||||
|
||||
if (printer_data_copy->popup_message == NULL)
|
||||
{
|
||||
printer_data_copy->popup_message = blank;
|
||||
}
|
||||
|
||||
if (old_state_message != printer_data_copy->state_message && old_state_message != NULL && old_state_message != blank && !no_free)
|
||||
{
|
||||
LOG_F(("Freeing state message '%s' (%x)\n", old_state_message, old_state_message));
|
||||
free(old_state_message);
|
||||
}
|
||||
|
||||
if (old_print_filename != printer_data_copy->print_filename && old_print_filename != NULL && old_print_filename != blank && !no_free)
|
||||
{
|
||||
LOG_F(("Freeing print filename '%s' (%x)\n", old_print_filename, old_print_filename));
|
||||
free(old_print_filename);
|
||||
}
|
||||
|
||||
if (old_state != printer_data_copy->state)
|
||||
{
|
||||
lv_msg_send(DATA_PRINTER_STATE, get_current_printer());
|
||||
}
|
||||
|
||||
if (old_popup_message != printer_data_copy->popup_message)
|
||||
{
|
||||
if (old_popup_message != NULL && old_popup_message != blank && !no_free)
|
||||
{
|
||||
LOG_F(("Freeing popup message '%s' (%x)\n", old_popup_message, old_popup_message));
|
||||
free(old_popup_message);
|
||||
}
|
||||
|
||||
if (printer_data_copy->popup_message != NULL && printer_data_copy->popup_message != blank)
|
||||
{
|
||||
lv_msg_send(DATA_PRINTER_POPUP, get_current_printer());
|
||||
}
|
||||
}
|
||||
|
||||
lv_msg_send(DATA_PRINTER_DATA, get_current_printer());
|
||||
return printer_data_copy;
|
||||
}
|
||||
|
||||
void initialize_printers(BasePrinter** printers, unsigned char total)
|
||||
{
|
||||
LOG_F(("Initializing %d printers\n", total))
|
||||
printer_data_copy = (PrinterData*)malloc(sizeof(PrinterData));
|
||||
minimal_data_copy = (PrinterDataMinimal*)malloc(sizeof(PrinterDataMinimal) * total);
|
||||
memset(printer_data_copy, 0, sizeof(PrinterData));
|
||||
memset(minimal_data_copy, 0, sizeof(PrinterDataMinimal) * total);
|
||||
registered_printers = printers;
|
||||
total_printers = total;
|
||||
}
|
||||
|
||||
BasePrinter* get_current_printer()
|
||||
{
|
||||
return get_printer(current_printer_index);
|
||||
}
|
||||
|
||||
BasePrinter* get_printer(int idx)
|
||||
{
|
||||
return registered_printers[idx];
|
||||
}
|
||||
|
||||
bool BasePrinter::supports_feature(PrinterFeatures feature)
|
||||
{
|
||||
return supported_features & feature == feature;
|
||||
}
|
||||
|
||||
int get_current_printer_index()
|
||||
{
|
||||
return current_printer_index;
|
||||
}
|
||||
|
||||
PrinterData* get_current_printer_data()
|
||||
{
|
||||
return printer_data_copy;
|
||||
}
|
||||
|
||||
unsigned int get_printer_count()
|
||||
{
|
||||
return total_printers;
|
||||
}
|
||||
|
||||
void announce_printer_data_minimal(PrinterDataMinimal* printer_data)
|
||||
{
|
||||
memcpy(minimal_data_copy, printer_data, sizeof(PrinterDataMinimal) * total_printers);
|
||||
lv_msg_send(DATA_PRINTER_MINIMAL, get_current_printer());
|
||||
}
|
||||
|
||||
PrinterDataMinimal* get_printer_data_minimal(int idx)
|
||||
{
|
||||
return &(minimal_data_copy[idx]);
|
||||
}
|
||||
|
||||
void set_current_printer(int idx)
|
||||
{
|
||||
current_printer_index = idx;
|
||||
global_config_set_printer(idx);
|
||||
set_color_scheme();
|
||||
set_invert_display();
|
||||
}
|
||||
201
CYD-Klipper/src/core/printer_integration.hpp
Normal file
201
CYD-Klipper/src/core/printer_integration.hpp
Normal file
@@ -0,0 +1,201 @@
|
||||
#pragma once
|
||||
#include "../conf/global_config.h"
|
||||
#include <esp_task_wdt.h>
|
||||
|
||||
#define MIN_EXTRUDER_EXTRUDE_TEMP 175
|
||||
|
||||
enum PrinterFeatures {
|
||||
PrinterFeatureRestart = BIT(0),
|
||||
PrinterFeatureFirmwareRestart = BIT(1),
|
||||
PrinterFeatureHome = BIT(2),
|
||||
PrinterFeatureDisableSteppers = BIT(3),
|
||||
PrinterFeaturePause = BIT(4),
|
||||
PrinterFeatureResume = BIT(5),
|
||||
PrinterFeatureStop = BIT(6),
|
||||
PrinterFeatureEmergencyStop = BIT(7),
|
||||
PrinterFeatureExtrude = BIT(8),
|
||||
PrinterFeatureRetract = BIT(9),
|
||||
PrinterFeatureIgnoreError = BIT(10),
|
||||
PrinterFeatureContinueError = BIT(11),
|
||||
PrinterFeatureCooldown = BIT(12),
|
||||
PrinterFeatureRetryError = BIT(13),
|
||||
};
|
||||
|
||||
inline PrinterFeatures operator|(PrinterFeatures a, PrinterFeatures b)
|
||||
{
|
||||
return static_cast<PrinterFeatures>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
|
||||
enum PrinterTemperatureDevice
|
||||
{
|
||||
PrinterTemperatureDeviceBed = BIT(0),
|
||||
PrinterTemperatureDeviceNozzle1 = BIT(1),
|
||||
PrinterTemperatureDeviceNozzle2 = BIT(2),
|
||||
PrinterTemperatureDeviceNozzle3 = BIT(3),
|
||||
PrinterTemperatureDeviceNozzle4 = BIT(4),
|
||||
PrinterTemperatureDeviceNozzle5 = BIT(5),
|
||||
PrinterTemperatureDeviceNozzle6 = BIT(6),
|
||||
PrinterTemperatureDeviceNozzle7 = BIT(7),
|
||||
PrinterTemperatureDeviceNozzle8 = BIT(8),
|
||||
PrinterTemperatureDeviceChamber = BIT(9),
|
||||
};
|
||||
|
||||
enum PrinterTemperatureDeviceIndex
|
||||
{
|
||||
PrinterTemperatureDeviceIndexBed = 0,
|
||||
PrinterTemperatureDeviceIndexNozzle1 = 1,
|
||||
PrinterTemperatureDeviceIndexNozzle2 = 2,
|
||||
PrinterTemperatureDeviceIndexNozzle3 = 3,
|
||||
PrinterTemperatureDeviceIndexNozzle4 = 4,
|
||||
PrinterTemperatureDeviceIndexNozzle5 = 5,
|
||||
PrinterTemperatureDeviceIndexNozzle6 = 6,
|
||||
PrinterTemperatureDeviceIndexNozzle7 = 7,
|
||||
PrinterTemperatureDeviceIndexNozzle8 = 8,
|
||||
PrinterTemperatureDeviceIndexChamber = 9,
|
||||
};
|
||||
|
||||
inline PrinterTemperatureDevice operator|(PrinterTemperatureDevice a, PrinterTemperatureDevice b)
|
||||
{
|
||||
return static_cast<PrinterTemperatureDevice>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
|
||||
enum PrinterState {
|
||||
PrinterStateOffline = 0,
|
||||
PrinterStateError = 1,
|
||||
PrinterStateIdle = 2,
|
||||
PrinterStatePrinting = 3,
|
||||
PrinterStatePaused = 4,
|
||||
};
|
||||
|
||||
typedef struct _PrinterData {
|
||||
union {
|
||||
struct {
|
||||
bool can_extrude : 1;
|
||||
bool homed_axis : 1;
|
||||
bool absolute_coords : 1;
|
||||
};
|
||||
unsigned char rawState;
|
||||
};
|
||||
PrinterState state;
|
||||
char* state_message;
|
||||
char* popup_message;
|
||||
float temperatures[10];
|
||||
float target_temperatures[10];
|
||||
float position[3];
|
||||
float elapsed_time_s;
|
||||
float printed_time_s;
|
||||
float remaining_time_s;
|
||||
float filament_used_mm;
|
||||
char* print_filename;
|
||||
float print_progress; // 0 -> 1
|
||||
float fan_speed; // 0 -> 1
|
||||
float speed_mult;
|
||||
float extrude_mult;
|
||||
int total_layers;
|
||||
int current_layer;
|
||||
float pressure_advance;
|
||||
float smooth_time;
|
||||
int feedrate_mm_per_s;
|
||||
PrinterFeatures error_screen_features;
|
||||
} PrinterData;
|
||||
|
||||
typedef struct {
|
||||
PrinterState state;
|
||||
float print_progress; // 0 -> 1
|
||||
unsigned int power_devices;
|
||||
bool success;
|
||||
} PrinterDataMinimal;
|
||||
|
||||
typedef struct {
|
||||
char** macros;
|
||||
unsigned int count;
|
||||
bool success;
|
||||
} Macros;
|
||||
|
||||
typedef struct {
|
||||
char** power_devices;
|
||||
bool* power_states;
|
||||
unsigned int count;
|
||||
bool success;
|
||||
} PowerDevices;
|
||||
|
||||
typedef struct {
|
||||
char** available_files;
|
||||
unsigned int count;
|
||||
bool success;
|
||||
} Files;
|
||||
|
||||
typedef struct {
|
||||
void* set_label; // type lv_event_cb_t
|
||||
void* open_panel; // type lv_event_cb_t
|
||||
} PrinterUiPanel;
|
||||
|
||||
typedef struct {
|
||||
bool success;
|
||||
unsigned int size;
|
||||
unsigned char* png;
|
||||
} Thumbnail;
|
||||
|
||||
enum HttpRequestType
|
||||
{
|
||||
HttpPost,
|
||||
HttpGet
|
||||
};
|
||||
|
||||
class BasePrinter
|
||||
{
|
||||
protected:
|
||||
unsigned char config_index{};
|
||||
PrinterData printer_data{};
|
||||
|
||||
public:
|
||||
short popup_message_timeout_s = 10;
|
||||
bool no_confirm_print_file = false;
|
||||
|
||||
PrinterConfiguration* printer_config{};
|
||||
PrinterFeatures supported_features{};
|
||||
PrinterTemperatureDevice supported_temperature_devices{};
|
||||
PrinterUiPanel* custom_menus{};
|
||||
unsigned char custom_menus_count{};
|
||||
|
||||
virtual bool move_printer(const char* axis, float amount, bool relative) = 0;
|
||||
virtual bool execute_feature(PrinterFeatures feature) = 0;
|
||||
virtual bool connect() = 0;
|
||||
virtual bool fetch() = 0;
|
||||
virtual PrinterDataMinimal fetch_min() = 0;
|
||||
virtual void disconnect() = 0;
|
||||
// Free macros externally when done
|
||||
virtual Macros get_macros() = 0;
|
||||
virtual int get_macros_count() = 0;
|
||||
virtual bool execute_macro(const char* macro) = 0;
|
||||
// Free power devices externally when done
|
||||
virtual PowerDevices get_power_devices() = 0;
|
||||
virtual int get_power_devices_count() = 0;
|
||||
virtual bool set_power_device_state(const char* device_name, bool state) = 0;
|
||||
// Free files externally when done
|
||||
virtual Files get_files() = 0;
|
||||
virtual bool start_file(const char* filename) = 0;
|
||||
// Free thumbnail externally when done
|
||||
virtual Thumbnail get_32_32_png_image_thumbnail(const char* gcode_filename) = 0;
|
||||
virtual bool set_target_temperature(PrinterTemperatureDevice device, unsigned int temperature) = 0;
|
||||
|
||||
BasePrinter(unsigned char index);
|
||||
PrinterData* AnnouncePrinterData();
|
||||
bool supports_feature(PrinterFeatures feature);
|
||||
};
|
||||
|
||||
#define DATA_PRINTER_STATE 1
|
||||
#define DATA_PRINTER_DATA 2
|
||||
#define DATA_PRINTER_TEMP_PRESET 3
|
||||
#define DATA_PRINTER_MINIMAL 4
|
||||
#define DATA_PRINTER_POPUP 5
|
||||
|
||||
BasePrinter* get_current_printer();
|
||||
BasePrinter* get_printer(int idx);
|
||||
void initialize_printers(BasePrinter** printers, unsigned char total);
|
||||
PrinterData* get_current_printer_data();
|
||||
unsigned int get_printer_count();
|
||||
void announce_printer_data_minimal(PrinterDataMinimal* printer_data);
|
||||
PrinterDataMinimal* get_printer_data_minimal(int idx);
|
||||
int get_current_printer_index();
|
||||
void set_current_printer(int idx);
|
||||
28
CYD-Klipper/src/core/semaphore.cpp
Normal file
28
CYD-Klipper/src/core/semaphore.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "semaphore.h"
|
||||
#include <UrlEncode.h>
|
||||
#include <esp_task_wdt.h>
|
||||
|
||||
SemaphoreHandle_t freezeRenderThreadSemaphore, freezeRequestThreadSemaphore;
|
||||
|
||||
void semaphore_init(){
|
||||
freezeRenderThreadSemaphore = xSemaphoreCreateMutex();
|
||||
freezeRequestThreadSemaphore = xSemaphoreCreateMutex();
|
||||
xSemaphoreGive(freezeRenderThreadSemaphore);
|
||||
xSemaphoreGive(freezeRequestThreadSemaphore);
|
||||
}
|
||||
|
||||
void freeze_request_thread(){
|
||||
xSemaphoreTake(freezeRequestThreadSemaphore, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void unfreeze_request_thread(){
|
||||
xSemaphoreGive(freezeRequestThreadSemaphore);
|
||||
}
|
||||
|
||||
void freeze_render_thread(){
|
||||
xSemaphoreTake(freezeRenderThreadSemaphore, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void unfreeze_render_thread(){
|
||||
xSemaphoreGive(freezeRenderThreadSemaphore);
|
||||
}
|
||||
11
CYD-Klipper/src/core/semaphore.h
Normal file
11
CYD-Klipper/src/core/semaphore.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
void semaphore_init();
|
||||
|
||||
void freeze_request_thread();
|
||||
void unfreeze_request_thread();
|
||||
|
||||
// Don't use unless you want trouble
|
||||
void freeze_render_thread();
|
||||
// Don't use unless you want trouble
|
||||
void unfreeze_render_thread();
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
size_t bytes_written = Update.write(buff, bytes_read);
|
||||
if (bytes_read != bytes_written)
|
||||
{
|
||||
// Serial.printf("Unexpected error in OTA: %d %d %d\n", bytes_to_read, bytes_read, bytes_written);
|
||||
// LOG_F(("Unexpected error in OTA: %d %d %d\n", bytes_to_read, bytes_read, bytes_written))
|
||||
break;
|
||||
}
|
||||
offset += bytes_written;
|
||||
@@ -212,8 +212,8 @@ public:
|
||||
String CDevice = config["Device"].isNull() ? "" : (const char *)config["Device"];
|
||||
CVersion = config["Version"].isNull() ? "" : (const char *)config["Version"];
|
||||
String CConfig = config["Config"].isNull() ? "" : (const char *)config["Config"];
|
||||
//Serial.printf("Checking %s %s %s %s\n", CBoard.c_str(), CDevice.c_str(), CVersion.c_str(), CConfig.c_str());
|
||||
//Serial.printf("Against %s %s %s %s\n", BoardName.c_str(), DeviceName.c_str(), CurrentVersion, ConfigName.c_str());
|
||||
//LOG_F(("Checking %s %s %s %s\n", CBoard.c_str(), CDevice.c_str(), CVersion.c_str(), CConfig.c_str()))
|
||||
//LOG_F(("Against %s %s %s %s\n", BoardName.c_str(), DeviceName.c_str(), CurrentVersion, ConfigName.c_str()))
|
||||
if ((CBoard.isEmpty() || CBoard == BoardName) &&
|
||||
(CDevice.isEmpty() || CDevice == DeviceName) &&
|
||||
(CConfig.isEmpty() || CConfig == ConfigName))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "core/screen_driver.h"
|
||||
#include "ui/wifi_setup.h"
|
||||
#include "ui/ip_setup.h"
|
||||
#include "ui/serial/serial_console.h"
|
||||
#include "lvgl.h"
|
||||
#include "core/data_setup.h"
|
||||
#include "ui/main_ui.h"
|
||||
@@ -12,11 +13,11 @@
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Hello World");
|
||||
serial_console::greet();
|
||||
load_global_config();
|
||||
screen_setup();
|
||||
lv_setup();
|
||||
Serial.println("Screen init done");
|
||||
LOG_LN("Screen init done");
|
||||
|
||||
wifi_init();
|
||||
ota_init();
|
||||
@@ -31,6 +32,7 @@ void loop(){
|
||||
wifi_ok();
|
||||
data_loop();
|
||||
lv_handler();
|
||||
serial_console::run();
|
||||
|
||||
if (is_ready_for_ota_update())
|
||||
{
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
#include "gcode_img.h"
|
||||
#include "lvgl.h"
|
||||
#include "ui_utils.h"
|
||||
#include <Esp.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "../conf/global_config.h"
|
||||
#include "../core/http_client.h"
|
||||
|
||||
static unsigned char * data_png = NULL;
|
||||
static char img_filename_path[256] = {0};
|
||||
static lv_img_dsc_t img_header = {0};
|
||||
|
||||
bool has_128_128_gcode(const char* filename)
|
||||
{
|
||||
if (filename == NULL){
|
||||
Serial.println("No gcode filename");
|
||||
return false;
|
||||
}
|
||||
|
||||
SETUP_HTTP_CLIENT("/server/files/thumbnails?filename=" + String(filename));
|
||||
|
||||
int httpCode = 0;
|
||||
try {
|
||||
httpCode = client.GET();
|
||||
}
|
||||
catch (...){
|
||||
Serial.println("Exception while fetching gcode img location");
|
||||
return {0};
|
||||
}
|
||||
|
||||
if (httpCode == 200)
|
||||
{
|
||||
String payload = client.getString();
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, payload);
|
||||
auto result = doc["result"].as<JsonArray>();
|
||||
const char* chosen_thumb = NULL;
|
||||
|
||||
for (auto file : result){
|
||||
int width = file["width"];
|
||||
int height = file["height"];
|
||||
int size = file["size"];
|
||||
const char* thumbnail = file["thumbnail_path"];
|
||||
|
||||
if (width != height || width != 32)
|
||||
continue;
|
||||
|
||||
if (strcmp(thumbnail + strlen(thumbnail) - 4, ".png"))
|
||||
continue;
|
||||
|
||||
chosen_thumb = thumbnail;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chosen_thumb != NULL){
|
||||
Serial.printf("Found 32x32 PNG gcode img at %s\n", filename);
|
||||
strcpy(img_filename_path, chosen_thumb);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
lv_obj_t* draw_gcode_img()
|
||||
{
|
||||
clear_img_mem();
|
||||
|
||||
if (img_filename_path[0] == 0){
|
||||
Serial.println("No gcode img path");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SETUP_HTTP_CLIENT_FULL("/server/files/gcodes/" + String(img_filename_path), false, 2000);
|
||||
|
||||
int httpCode = 0;
|
||||
try {
|
||||
httpCode = client.GET();
|
||||
}
|
||||
catch (...){
|
||||
Serial.println("Exception while fetching gcode img");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (httpCode == 200)
|
||||
{
|
||||
size_t len = client.getSize();
|
||||
if (len <= 0)
|
||||
{
|
||||
Serial.println("No gcode img data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data_png = (unsigned char*)malloc(len + 1);
|
||||
if (len != client.getStream().readBytes(data_png, len)){
|
||||
Serial.println("Failed to read gcode img data");
|
||||
clear_img_mem();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&img_header, 0, sizeof(img_header));
|
||||
img_header.header.w = 32;
|
||||
img_header.header.h = 32;
|
||||
img_header.data_size = len;
|
||||
img_header.header.cf = LV_IMG_CF_RAW_ALPHA;
|
||||
img_header.data = data_png;
|
||||
|
||||
lv_obj_t * img = lv_img_create(lv_scr_act());
|
||||
lv_img_set_src(img, &img_header);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_obj_t* show_gcode_img(const char* filename)
|
||||
{
|
||||
if (filename == NULL){
|
||||
Serial.println("No gcode filename");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!has_128_128_gcode(filename)){
|
||||
Serial.println("No 32x32 gcode img found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return draw_gcode_img();
|
||||
}
|
||||
|
||||
void clear_img_mem()
|
||||
{
|
||||
if (data_png != NULL){
|
||||
free(data_png);
|
||||
data_png = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include "lvgl.h"
|
||||
|
||||
lv_obj_t* show_gcode_img(const char* filename);
|
||||
bool has_128_128_gcode(const char* filename);
|
||||
void clear_img_mem();
|
||||
@@ -4,19 +4,20 @@
|
||||
#include <HTTPClient.h>
|
||||
#include "core/data_setup.h"
|
||||
#include "ui_utils.h"
|
||||
#include "../core/macros_query.h"
|
||||
#include "panels/panel.h"
|
||||
#include "../core/http_client.h"
|
||||
#include "switch_printer.h"
|
||||
#include "macros.h"
|
||||
#include "../core/lv_setup.h"
|
||||
|
||||
lv_obj_t * hostEntry;
|
||||
lv_obj_t * portEntry;
|
||||
lv_obj_t * label = NULL;
|
||||
#include "serial/serial_console.h"
|
||||
#include "../core/klipper/klipper_printer_integration.hpp"
|
||||
#include "../core/bambu/bambu_printer_integration.hpp"
|
||||
#include "../core/screen_driver.h"
|
||||
#include "../core/klipper-serial/serial_klipper_printer_integration.hpp"
|
||||
#include "../core/octoprint/octoprint_printer_integration.hpp"
|
||||
|
||||
void show_ip_entry();
|
||||
void show_auth_entry();
|
||||
void choose_printer_type();
|
||||
|
||||
lv_obj_t * main_label;
|
||||
|
||||
/* Create a custom keyboard to allow hostnames or ip addresses (a-z, 0 - 9, and -) */
|
||||
static const char * kb_map[] = {
|
||||
@@ -34,10 +35,10 @@ static const lv_btnmatrix_ctrl_t kb_ctrl[] = {
|
||||
};
|
||||
|
||||
static const char * hex_numpad_map[] = {
|
||||
"1", "2", "3", "f", LV_SYMBOL_BACKSPACE, "\n",
|
||||
"4", "5", "6", "e", LV_SYMBOL_OK, "\n",
|
||||
"7", "8", "9", "d", LV_SYMBOL_LEFT, "\n",
|
||||
"0", "a", "b", "c", LV_SYMBOL_RIGHT, NULL
|
||||
"1", "2", "3", "F", LV_SYMBOL_BACKSPACE, "\n",
|
||||
"4", "5", "6", "E", LV_SYMBOL_OK, "\n",
|
||||
"7", "8", "9", "D", LV_SYMBOL_LEFT, "\n",
|
||||
"0", "A", "B", "C", LV_SYMBOL_RIGHT, NULL
|
||||
};
|
||||
|
||||
static const lv_btnmatrix_ctrl_t hex_numpad_ctrl[] = {
|
||||
@@ -47,30 +48,107 @@ static const lv_btnmatrix_ctrl_t hex_numpad_ctrl[] = {
|
||||
1, 1, 1, 1, LV_KEYBOARD_CTRL_BTN_FLAGS | 1,
|
||||
};
|
||||
|
||||
enum connection_status_t {
|
||||
CONNECT_FAIL = 0,
|
||||
CONNECT_OK = 1,
|
||||
CONNECT_AUTH_REQUIRED = 2,
|
||||
};
|
||||
static void btn_switch_printer(lv_event_t *e){
|
||||
lv_obj_t *btn = lv_event_get_target(e);
|
||||
PrinterConfiguration * config = (PrinterConfiguration*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
|
||||
connection_status_t verify_ip(){
|
||||
SETUP_HTTP_CLIENT_FULL("/printer/info", true, 1000);
|
||||
global_config_set_printer(index);
|
||||
set_color_scheme();
|
||||
set_invert_display();
|
||||
lv_obj_del(lv_obj_get_parent(lv_obj_get_parent(btn)));
|
||||
}
|
||||
|
||||
int httpCode;
|
||||
try {
|
||||
httpCode = client.GET();
|
||||
long last_request = 0;
|
||||
|
||||
if (httpCode == 401)
|
||||
return CONNECT_AUTH_REQUIRED;
|
||||
|
||||
return httpCode == 200 ? CONNECT_OK : CONNECT_FAIL;
|
||||
void serial_check_connection()
|
||||
{
|
||||
if ((millis() - last_request) < 5000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (...) {
|
||||
Serial.println("Failed to connect");
|
||||
return CONNECT_FAIL;
|
||||
|
||||
auto result = connection_test_serial_klipper(&global_config.printer_config[global_config.printer_index]);
|
||||
last_request = millis();
|
||||
|
||||
if (result == KlipperConnectionStatus::ConnectOk)
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].setup_complete = true;
|
||||
strcpy(global_config.printer_config[global_config.printer_index].printer_host, "Serial");
|
||||
write_global_config();
|
||||
}
|
||||
}
|
||||
|
||||
void switch_printer_init() {
|
||||
lv_obj_t * parent = lv_create_empty_panel(lv_scr_act());
|
||||
lv_obj_set_style_bg_opa(parent, LV_OPA_100, 0);
|
||||
lv_obj_align(parent, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
lv_obj_set_size(parent, CYD_SCREEN_WIDTH_PX, CYD_SCREEN_HEIGHT_PX);
|
||||
lv_layout_flex_column(parent);
|
||||
|
||||
lv_obj_set_size(lv_create_empty_panel(parent), 0, 0);
|
||||
|
||||
auto width = CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2;
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(parent);
|
||||
lv_obj_set_size(btn, width, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, destroy_event_user_data, LV_EVENT_CLICKED, parent);
|
||||
|
||||
lv_obj_t * label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_CLOSE " Close");
|
||||
lv_obj_center(label);
|
||||
|
||||
for (int i = 0; i < PRINTER_CONFIG_COUNT; i++){
|
||||
PrinterConfiguration * config = &global_config.printer_config[i];
|
||||
const char* printer_name = (config->printer_name[0] == 0) ? config->printer_host : config->printer_name;
|
||||
|
||||
if (i == global_config.printer_index && config->setup_complete)
|
||||
{
|
||||
lv_create_custom_menu_label(printer_name, parent, "Active");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config->setup_complete) {
|
||||
lv_create_custom_menu_button(printer_name, parent, btn_switch_printer, "Switch", config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void show_switch_printer_screen(lv_event_t * e){
|
||||
switch_printer_init();
|
||||
}
|
||||
|
||||
static void host_update(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
const char* text = lv_textarea_get_text(ta);
|
||||
strcpy(global_config.printer_config[global_config.printer_index].printer_host, text);
|
||||
global_config.printer_config[global_config.printer_index].ip_configured = text[0] != '\0';
|
||||
}
|
||||
|
||||
static void port_update(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
const char* text = lv_textarea_get_text(ta);
|
||||
if (text[0] != '\0')
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].klipper_port = atoi(text);
|
||||
}
|
||||
}
|
||||
|
||||
static void auth_update(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
const char* text = lv_textarea_get_text(ta);
|
||||
strcpy(global_config.printer_config[global_config.printer_index].printer_auth, text);
|
||||
global_config.printer_config[global_config.printer_index].auth_configured = text[0] != '\0';
|
||||
}
|
||||
|
||||
static void return_to_choose_printer_type(lv_event_t * e)
|
||||
{
|
||||
choose_printer_type();
|
||||
}
|
||||
|
||||
static void keyboard_event_ip_entry(lv_event_t * e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
@@ -84,6 +162,14 @@ static void keyboard_event_ip_entry(lv_event_t * e) {
|
||||
{
|
||||
lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_USER_1);
|
||||
}
|
||||
else if (lv_obj_has_flag(ta, LV_OBJ_FLAG_USER_2))
|
||||
{
|
||||
lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_USER_2);
|
||||
}
|
||||
else if (lv_obj_has_flag(ta, LV_OBJ_FLAG_USER_3))
|
||||
{
|
||||
lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_TEXT_LOWER);
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_NUMBER);
|
||||
@@ -100,97 +186,60 @@ static void keyboard_event_ip_entry(lv_event_t * e) {
|
||||
}
|
||||
else if (code == LV_EVENT_READY)
|
||||
{
|
||||
strcpy(get_current_printer_config()->klipper_host, lv_textarea_get_text(hostEntry));
|
||||
get_current_printer_config()->klipper_port = atoi(lv_textarea_get_text(portEntry));
|
||||
PrinterType type = global_config.printer_config[global_config.printer_index].printer_type;
|
||||
|
||||
connection_status_t status = verify_ip();
|
||||
if (status == CONNECT_OK)
|
||||
if (type == PrinterType::PrinterTypeKlipper)
|
||||
{
|
||||
get_current_printer_config()->ip_configured = true;
|
||||
write_global_config();
|
||||
}
|
||||
else if (status == CONNECT_AUTH_REQUIRED)
|
||||
{
|
||||
show_auth_entry();
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_label_set_text(label, "Failed to connect");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void keyboard_event_auth_entry(lv_event_t * e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
lv_obj_t * kb = (lv_obj_t *)lv_event_get_user_data(e);
|
||||
|
||||
if (code == LV_EVENT_READY)
|
||||
{
|
||||
const char * txt = lv_textarea_get_text(ta);
|
||||
int len = strlen(txt);
|
||||
if (len > 0)
|
||||
{
|
||||
get_current_printer_config()->auth_configured = true;
|
||||
strcpy(get_current_printer_config()->klipper_auth, txt);
|
||||
|
||||
if (verify_ip() == CONNECT_OK)
|
||||
KlipperConnectionStatus klipper_status = connection_test_klipper(&global_config.printer_config[global_config.printer_index]);
|
||||
if (klipper_status == KlipperConnectionStatus::ConnectOk)
|
||||
{
|
||||
get_current_printer_config()->ip_configured = true;
|
||||
global_config.printer_config[global_config.printer_index].setup_complete = true;
|
||||
write_global_config();
|
||||
}
|
||||
else
|
||||
else if (klipper_status == KlipperConnectionStatus::ConnectAuthRequired)
|
||||
{
|
||||
lv_label_set_text(label, "Failed to connect");
|
||||
lv_label_set_text(main_label, "Incorrect authorisation");
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_label_set_text(main_label, "Failed to connect");
|
||||
}
|
||||
}
|
||||
else if (type == PrinterType::PrinterTypeBambuLocal)
|
||||
{
|
||||
BambuConnectionStatus bambu_status = connection_test_bambu(&global_config.printer_config[global_config.printer_index]);
|
||||
if (bambu_status == BambuConnectionStatus::BambuConnectOk)
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].setup_complete = true;
|
||||
write_global_config();
|
||||
}
|
||||
else if (bambu_status == BambuConnectionStatus::BambuConnectSNFail)
|
||||
{
|
||||
lv_label_set_text(main_label, "Incorrect serial number");
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_label_set_text(main_label, "Incorrect IP/Access code");
|
||||
}
|
||||
}
|
||||
else if (type == PrinterType::PrinterTypeOctoprint)
|
||||
{
|
||||
OctoConnectionStatus octo_status = connection_test_octoprint(&global_config.printer_config[global_config.printer_index]);
|
||||
if (octo_status == OctoConnectionStatus::OctoConnectOk)
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].setup_complete = true;
|
||||
write_global_config();
|
||||
}
|
||||
else if (octo_status == OctoConnectionStatus::OctoConnectKeyFail)
|
||||
{
|
||||
lv_label_set_text(main_label, "Incorrect API key");
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_label_set_text(main_label, "Failed to connect");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (code == LV_EVENT_CANCEL)
|
||||
{
|
||||
show_ip_entry();
|
||||
}
|
||||
}
|
||||
|
||||
void show_auth_entry()
|
||||
{
|
||||
get_current_printer_config()->klipper_auth[32] = 0;
|
||||
lv_obj_clean(lv_scr_act());
|
||||
|
||||
lv_obj_t * root = lv_create_empty_panel(lv_scr_act());
|
||||
lv_obj_set_size(root, CYD_SCREEN_WIDTH_PX, CYD_SCREEN_HEIGHT_PX);
|
||||
lv_layout_flex_column(root);
|
||||
|
||||
lv_obj_t * top_root = lv_create_empty_panel(root);
|
||||
lv_obj_set_width(top_root, CYD_SCREEN_WIDTH_PX);
|
||||
lv_layout_flex_column(top_root);
|
||||
lv_obj_set_flex_grow(top_root, 1);
|
||||
lv_obj_set_style_pad_all(top_root, CYD_SCREEN_GAP_PX, 0);
|
||||
|
||||
label = lv_label_create(top_root);
|
||||
lv_label_set_text(label, "Enter API Key");
|
||||
lv_obj_set_width(label, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
|
||||
lv_obj_t * keyboard = lv_keyboard_create(root);
|
||||
lv_obj_t * passEntry = lv_textarea_create(top_root);
|
||||
lv_textarea_set_max_length(passEntry, 32);
|
||||
lv_textarea_set_one_line(passEntry, true);
|
||||
|
||||
if (get_current_printer_config()->auth_configured)
|
||||
lv_textarea_set_text(passEntry, get_current_printer_config()->klipper_auth);
|
||||
else
|
||||
lv_textarea_set_text(passEntry, "");
|
||||
|
||||
lv_obj_set_width(passEntry, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
lv_obj_add_event_cb(passEntry, keyboard_event_auth_entry, LV_EVENT_ALL, keyboard);
|
||||
lv_obj_set_flex_grow(passEntry, 1);
|
||||
|
||||
lv_keyboard_set_textarea(keyboard, passEntry);
|
||||
lv_keyboard_set_map(keyboard, LV_KEYBOARD_MODE_USER_2, hex_numpad_map, hex_numpad_ctrl);
|
||||
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_USER_2);
|
||||
}
|
||||
|
||||
void show_ip_entry()
|
||||
@@ -200,58 +249,256 @@ void show_ip_entry()
|
||||
lv_obj_t * root = lv_create_empty_panel(lv_scr_act());
|
||||
lv_obj_set_size(root, CYD_SCREEN_WIDTH_PX, CYD_SCREEN_HEIGHT_PX);
|
||||
lv_layout_flex_column(root);
|
||||
lv_obj_clear_flag(root, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lv_obj_t * top_root = lv_create_empty_panel(root);
|
||||
lv_obj_set_width(top_root, CYD_SCREEN_WIDTH_PX);
|
||||
lv_layout_flex_column(top_root);
|
||||
lv_obj_set_flex_grow(top_root, 1);
|
||||
lv_obj_set_style_pad_all(top_root, CYD_SCREEN_GAP_PX, 0);
|
||||
lv_obj_clear_flag(top_root, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
label = lv_label_create(top_root);
|
||||
lv_label_set_text(label, "Enter Klipper IP/Hostname and Port");
|
||||
lv_obj_set_width(label, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
lv_obj_t * button_row = lv_create_empty_panel(top_root);
|
||||
lv_obj_set_size(button_row, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, LV_SIZE_CONTENT);
|
||||
lv_layout_flex_row(button_row);
|
||||
|
||||
lv_obj_t * textbow_row = lv_create_empty_panel(top_root);
|
||||
lv_obj_set_width(textbow_row, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
lv_obj_set_flex_grow(textbow_row, 1);
|
||||
lv_layout_flex_row(textbow_row);
|
||||
lv_obj_t * button_back = lv_btn_create(button_row);
|
||||
lv_obj_set_height(button_back, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX / 2);
|
||||
lv_obj_set_flex_grow(button_back, 1);
|
||||
lv_obj_add_event_cb(button_back, return_to_choose_printer_type, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
hostEntry = lv_textarea_create(textbow_row);
|
||||
lv_textarea_set_one_line(hostEntry, true);
|
||||
lv_obj_add_flag(hostEntry, LV_OBJ_FLAG_USER_1);
|
||||
lv_textarea_set_max_length(hostEntry, 63);
|
||||
lv_textarea_set_text(hostEntry, "");
|
||||
lv_obj_set_flex_grow(hostEntry, 3);
|
||||
lv_obj_t * label = lv_label_create(button_back);
|
||||
lv_label_set_text(label, LV_SYMBOL_LEFT);
|
||||
lv_obj_center(label);
|
||||
|
||||
portEntry = lv_textarea_create(textbow_row);
|
||||
lv_textarea_set_one_line(portEntry, true);
|
||||
lv_textarea_set_max_length(portEntry, 5);
|
||||
lv_textarea_set_text(portEntry, "80");
|
||||
lv_obj_set_flex_grow(portEntry, 1);
|
||||
|
||||
lv_obj_t * keyboard = lv_keyboard_create(root);
|
||||
lv_keyboard_set_map(keyboard, LV_KEYBOARD_MODE_USER_1, kb_map, kb_ctrl);
|
||||
lv_obj_add_event_cb(hostEntry, keyboard_event_ip_entry, LV_EVENT_ALL, keyboard);
|
||||
lv_obj_add_event_cb(portEntry, keyboard_event_ip_entry, LV_EVENT_ALL, keyboard);
|
||||
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_USER_1);
|
||||
lv_keyboard_set_textarea(keyboard, hostEntry);
|
||||
main_label = lv_label_create(button_row);
|
||||
|
||||
if (global_config.multi_printer_mode)
|
||||
{
|
||||
lv_obj_t * btn = draw_switch_printer_button();
|
||||
lv_obj_set_parent(btn, textbow_row);
|
||||
lv_obj_align(btn, LV_ALIGN_DEFAULT, 0, 0);
|
||||
lv_obj_t * button_switch_printer = lv_btn_create(button_row);
|
||||
lv_obj_set_height(button_switch_printer, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX / 2);
|
||||
lv_obj_set_flex_grow(button_switch_printer, 1);
|
||||
lv_obj_add_event_cb(button_switch_printer, show_switch_printer_screen, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
label = lv_label_create(button_switch_printer);
|
||||
lv_label_set_text(label, LV_SYMBOL_HOME);
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
lv_obj_t * ip_row = lv_create_empty_panel(top_root);
|
||||
lv_obj_set_size(ip_row, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, LV_SIZE_CONTENT);
|
||||
lv_layout_flex_row(ip_row);
|
||||
|
||||
lv_obj_t * host_entry = lv_textarea_create(ip_row);
|
||||
lv_textarea_set_one_line(host_entry, true);
|
||||
lv_obj_add_flag(host_entry, LV_OBJ_FLAG_USER_1);
|
||||
lv_textarea_set_max_length(host_entry, 64);
|
||||
lv_obj_set_flex_grow(host_entry, 2);
|
||||
|
||||
lv_obj_t * port_entry = lv_textarea_create(ip_row);
|
||||
lv_textarea_set_one_line(port_entry, true);
|
||||
lv_obj_set_flex_grow(port_entry, 1);
|
||||
|
||||
lv_obj_t * auth_row = lv_create_empty_panel(top_root);
|
||||
lv_obj_set_size(auth_row, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, LV_SIZE_CONTENT);
|
||||
lv_layout_flex_row(auth_row);
|
||||
|
||||
lv_obj_t * auth_entry = lv_textarea_create(auth_row);
|
||||
lv_textarea_set_one_line(auth_entry, true);
|
||||
lv_obj_add_flag(auth_entry, LV_OBJ_FLAG_USER_2);
|
||||
lv_obj_set_flex_grow(auth_entry, 1);
|
||||
lv_textarea_set_max_length(auth_entry, 32);
|
||||
|
||||
if (global_config.printer_config[global_config.printer_index].ip_configured)
|
||||
{
|
||||
char buff[10] = {0};
|
||||
sprintf(buff, "%d", global_config.printer_config[global_config.printer_index].klipper_port);
|
||||
lv_textarea_set_text(host_entry, global_config.printer_config[global_config.printer_index].printer_host);
|
||||
lv_textarea_set_text(port_entry, buff);
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_textarea_set_text(host_entry, "");
|
||||
|
||||
if (global_config.printer_config[global_config.printer_index].printer_type == PrinterType::PrinterTypeBambuLocal)
|
||||
{
|
||||
lv_textarea_set_text(port_entry, "");
|
||||
global_config.printer_config[global_config.printer_index].klipper_port = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_textarea_set_text(port_entry, "80");
|
||||
global_config.printer_config[global_config.printer_index].klipper_port = 80;
|
||||
}
|
||||
|
||||
global_config.printer_config[global_config.printer_index].printer_host[0] = '\0';
|
||||
|
||||
}
|
||||
|
||||
if (global_config.printer_config[global_config.printer_index].auth_configured)
|
||||
{
|
||||
lv_textarea_set_text(auth_entry, global_config.printer_config[global_config.printer_index].printer_auth);
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_textarea_set_text(auth_entry, "");
|
||||
global_config.printer_config[global_config.printer_index].printer_auth[0] = '\0';
|
||||
}
|
||||
|
||||
lv_obj_add_event_cb(host_entry, host_update, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
lv_obj_add_event_cb(port_entry, port_update, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
lv_obj_add_event_cb(auth_entry, auth_update, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
|
||||
lv_obj_t * keyboard = lv_keyboard_create(root);
|
||||
lv_keyboard_set_map(keyboard, LV_KEYBOARD_MODE_USER_1, kb_map, kb_ctrl);
|
||||
lv_keyboard_set_map(keyboard, LV_KEYBOARD_MODE_USER_2, hex_numpad_map, hex_numpad_ctrl);
|
||||
lv_obj_add_event_cb(host_entry, keyboard_event_ip_entry, LV_EVENT_ALL, keyboard);
|
||||
lv_obj_add_event_cb(port_entry, keyboard_event_ip_entry, LV_EVENT_ALL, keyboard);
|
||||
lv_obj_add_event_cb(auth_entry, keyboard_event_ip_entry, LV_EVENT_ALL, keyboard);
|
||||
lv_keyboard_set_mode(keyboard, LV_KEYBOARD_MODE_USER_1);
|
||||
lv_keyboard_set_textarea(keyboard, host_entry);
|
||||
|
||||
switch (global_config.printer_config[global_config.printer_index].printer_type)
|
||||
{
|
||||
case PrinterType::PrinterTypeKlipper:
|
||||
lv_label_set_text(main_label, "Klipper Setup");
|
||||
lv_textarea_set_max_length(port_entry, 5);
|
||||
lv_textarea_set_placeholder_text(host_entry, "Klipper host");
|
||||
lv_textarea_set_placeholder_text(port_entry, "Port");
|
||||
lv_textarea_set_placeholder_text(auth_entry, "Autorisation key (optional)");
|
||||
break;
|
||||
case PrinterType::PrinterTypeBambuLocal:
|
||||
lv_label_set_text(main_label, "Bambu (Local) Setup");
|
||||
lv_obj_set_flex_grow(port_entry, 4);
|
||||
lv_obj_set_flex_grow(host_entry, 6);
|
||||
lv_textarea_set_max_length(port_entry, 8);
|
||||
lv_textarea_set_placeholder_text(host_entry, "Printer IP");
|
||||
lv_textarea_set_placeholder_text(port_entry, "Access code");
|
||||
lv_textarea_set_placeholder_text(auth_entry, "Printer serial number");
|
||||
break;
|
||||
case PrinterType::PrinterTypeOctoprint:
|
||||
lv_obj_clear_flag(auth_entry, LV_OBJ_FLAG_USER_2);
|
||||
lv_obj_add_flag(auth_entry, LV_OBJ_FLAG_USER_3);
|
||||
lv_textarea_set_max_length(auth_entry, 48);
|
||||
lv_label_set_text(main_label, "Octoprint Setup");
|
||||
lv_textarea_set_max_length(port_entry, 5);
|
||||
lv_textarea_set_placeholder_text(host_entry, "Octoprint Host");
|
||||
lv_textarea_set_placeholder_text(port_entry, "Port");
|
||||
lv_textarea_set_placeholder_text(auth_entry, "API key");
|
||||
break;
|
||||
case PrinterType::PrinterTypeKlipperSerial:
|
||||
lv_label_set_text(main_label, "Klipper (Serial) Setup");
|
||||
lv_obj_del(ip_row);
|
||||
lv_obj_del(auth_row);
|
||||
lv_obj_del(keyboard);
|
||||
|
||||
lv_obj_t * bottom_root = lv_create_empty_panel(top_root);
|
||||
lv_obj_set_width(bottom_root, CYD_SCREEN_WIDTH_PX);
|
||||
lv_obj_set_flex_grow(bottom_root, 1);
|
||||
|
||||
label = lv_label_create(bottom_root);
|
||||
lv_obj_center(label);
|
||||
lv_label_set_text(label, "Connect CYD-Klipper to a host\nrunning the CYD-Klipper server");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void printer_type_klipper(lv_event_t * e)
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].printer_type = PrinterType::PrinterTypeKlipper;
|
||||
show_ip_entry();
|
||||
}
|
||||
|
||||
static void printer_type_bambu_local(lv_event_t * e)
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].printer_type = PrinterType::PrinterTypeBambuLocal;
|
||||
show_ip_entry();
|
||||
}
|
||||
|
||||
static void printer_type_serial_klipper(lv_event_t * e)
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].printer_type = PrinterType::PrinterTypeKlipperSerial;
|
||||
show_ip_entry();
|
||||
}
|
||||
|
||||
static void printer_type_octoprint(lv_event_t * e)
|
||||
{
|
||||
global_config.printer_config[global_config.printer_index].printer_type = PrinterType::PrinterTypeOctoprint;
|
||||
show_ip_entry();
|
||||
}
|
||||
|
||||
static void return_to_wifi_configuration(lv_event_t * e)
|
||||
{
|
||||
global_config.wifi_configuration_skipped = false;
|
||||
write_global_config();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
static inline void create_printer_type_button(lv_obj_t * root, const char * label, lv_event_cb_t event, bool require_wifi = true)
|
||||
{
|
||||
if (require_wifi && !global_config.wifi_configured)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(root);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, event, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label_obj = lv_label_create(btn);
|
||||
lv_label_set_text(label_obj, label);
|
||||
lv_obj_center(label_obj);
|
||||
}
|
||||
|
||||
void choose_printer_type()
|
||||
{
|
||||
lv_obj_t * btn;
|
||||
lv_obj_clean(lv_scr_act());
|
||||
global_config.printer_config[global_config.printer_index].ip_configured = false;
|
||||
global_config.printer_config[global_config.printer_index].auth_configured = false;
|
||||
|
||||
lv_obj_t * root = lv_create_empty_panel(lv_scr_act());
|
||||
lv_obj_set_size(root, CYD_SCREEN_WIDTH_PX, CYD_SCREEN_HEIGHT_PX);
|
||||
lv_layout_flex_column(root);
|
||||
lv_obj_set_flex_grow(root, 1);
|
||||
lv_obj_set_style_pad_all(root, CYD_SCREEN_GAP_PX, 0);
|
||||
lv_obj_clear_flag(root, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lv_obj_t * label = lv_label_create(root);
|
||||
lv_label_set_text(label, "Choose printer type");
|
||||
|
||||
create_printer_type_button(root, "Klipper (Wifi)", printer_type_klipper);
|
||||
create_printer_type_button(root, "Klipper (Serial/USB)", printer_type_serial_klipper, false);
|
||||
create_printer_type_button(root, "Bambu (Wifi, Local) [BETA]", printer_type_bambu_local);
|
||||
create_printer_type_button(root, "Octoprint (Wifi) [BETA]", printer_type_octoprint);
|
||||
|
||||
if (global_config.wifi_configuration_skipped)
|
||||
{
|
||||
create_printer_type_button(root, "Return to WiFi configuration", return_to_wifi_configuration, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ip_init(){
|
||||
if (!get_current_printer_config()->ip_configured)
|
||||
if (!global_config.printer_config[global_config.printer_index].setup_complete)
|
||||
{
|
||||
show_ip_entry();
|
||||
if (global_config.printer_config[global_config.printer_index].printer_type == PrinterType::PrinterTypeNone)
|
||||
{
|
||||
choose_printer_type();
|
||||
}
|
||||
else
|
||||
{
|
||||
show_ip_entry();
|
||||
}
|
||||
}
|
||||
|
||||
while (!get_current_printer_config()->ip_configured)
|
||||
while (!global_config.printer_config[global_config.printer_index].setup_complete)
|
||||
{
|
||||
if (global_config.printer_config[global_config.printer_index].printer_type == PrinterType::PrinterTypeKlipperSerial)
|
||||
{
|
||||
serial_check_connection();
|
||||
}
|
||||
|
||||
lv_handler();
|
||||
serial_console::run();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +1,92 @@
|
||||
#include "macros.h"
|
||||
#include "ui_utils.h"
|
||||
#include <Esp.h>
|
||||
#include "../core/current_printer.h"
|
||||
#include "../core/data_setup.h"
|
||||
#include "../core/semaphore.h"
|
||||
|
||||
PRINTER_CONFIG * curernt_config = NULL;
|
||||
typedef struct {
|
||||
const char* power_device_name;
|
||||
BasePrinter* printer;
|
||||
} DoubleStorage;
|
||||
|
||||
static void btn_press(lv_event_t * e){
|
||||
static void macro_run(lv_event_t * e){
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
const char* macro = (const char*)lv_event_get_user_data(e);
|
||||
Serial.printf("Macro: %s\n", macro);
|
||||
send_gcode(false, macro);
|
||||
LOG_F(("Macro: %s\n", macro))
|
||||
current_printer_execute_macro(macro);
|
||||
}
|
||||
|
||||
void macros_add_macros_to_panel(lv_obj_t * root_panel, MACROSQUERY query)
|
||||
int macros_add_macros_to_panel(lv_obj_t * root_panel, BasePrinter* printer)
|
||||
{
|
||||
for (int i = 0; i < query.count; i++){
|
||||
const char* macro = query.macros[i];
|
||||
lv_create_custom_menu_button(macro, root_panel, btn_press, "Run", (void*)macro);
|
||||
freeze_request_thread();
|
||||
Macros macros = printer->get_macros();
|
||||
unfreeze_request_thread();
|
||||
|
||||
if (!macros.success)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (global_config.sort_macros)
|
||||
{
|
||||
std::sort(macros.macros, macros.macros + macros.count, [](const char *a, const char *b)
|
||||
{ return strcmp(a, b) < 0; });
|
||||
}
|
||||
|
||||
for (int i = 0; i < macros.count; i++)
|
||||
{
|
||||
const char* macro = macros.macros[i];
|
||||
lv_obj_on_destroy_free_data(root_panel, macro);
|
||||
lv_create_custom_menu_button(macro, root_panel, macro_run, "Run", (void*)macro);
|
||||
}
|
||||
|
||||
free(macros.macros);
|
||||
return macros.count;
|
||||
}
|
||||
|
||||
static void power_device_toggle(lv_event_t * e)
|
||||
{
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
const char* power_device_name = (const char*)lv_event_get_user_data(e);
|
||||
Serial.printf("Power Device: %s, State: %d -> %d\n", power_device_name, !checked, checked);
|
||||
DoubleStorage* device = (DoubleStorage*)lv_event_get_user_data(e);
|
||||
LOG_F(("Power Device: %s, State: %d -> %d\n", device->power_device_name, !checked, checked))
|
||||
|
||||
if (curernt_config != NULL)
|
||||
set_power_state(power_device_name, checked, curernt_config);
|
||||
freeze_request_thread();
|
||||
device->printer->set_power_device_state(device->power_device_name, checked);
|
||||
unfreeze_request_thread();
|
||||
}
|
||||
|
||||
void macros_add_power_devices_to_panel(lv_obj_t * root_panel, POWERQUERY query)
|
||||
int macros_add_power_devices_to_panel(lv_obj_t * root_panel, BasePrinter* printer)
|
||||
{
|
||||
for (int i = 0; i < query.count; i++){
|
||||
const char* power_device_name = query.power_devices[i];
|
||||
const bool power_device_state = query.power_states[i];
|
||||
lv_create_custom_menu_switch(power_device_name, root_panel, power_device_toggle, power_device_state, (void*)power_device_name);
|
||||
freeze_request_thread();
|
||||
PowerDevices devices = printer->get_power_devices();
|
||||
unfreeze_request_thread();
|
||||
|
||||
if (!devices.success)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < devices.count; i++)
|
||||
{
|
||||
const char* power_device_name = devices.power_devices[i];
|
||||
const bool power_device_state = devices.power_states[i];
|
||||
DoubleStorage* storage = (DoubleStorage*)malloc(sizeof(DoubleStorage));
|
||||
storage->printer = printer;
|
||||
storage->power_device_name = power_device_name;
|
||||
lv_obj_on_destroy_free_data(root_panel, storage);
|
||||
lv_obj_on_destroy_free_data(root_panel, power_device_name);
|
||||
lv_create_custom_menu_switch(power_device_name, root_panel, power_device_toggle, power_device_state, (void*)storage);
|
||||
}
|
||||
|
||||
free(devices.power_devices);
|
||||
free(devices.power_states);
|
||||
return devices.count;
|
||||
}
|
||||
|
||||
void macros_set_current_config(PRINTER_CONFIG * config)
|
||||
void macros_draw_power_fullscreen(BasePrinter* printer)
|
||||
{
|
||||
curernt_config = config;
|
||||
}
|
||||
|
||||
void macros_draw_power_fullscreen(PRINTER_CONFIG * config)
|
||||
{
|
||||
macros_set_current_config(config);
|
||||
|
||||
lv_obj_t * parent = lv_create_empty_panel(lv_scr_act());
|
||||
lv_obj_set_style_bg_opa(parent, LV_OPA_100, 0);
|
||||
lv_obj_align(parent, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
@@ -67,11 +105,10 @@ void macros_draw_power_fullscreen(PRINTER_CONFIG * config)
|
||||
lv_label_set_text(label, LV_SYMBOL_CLOSE " Close");
|
||||
lv_obj_center(label);
|
||||
|
||||
POWERQUERY power = power_devices_query(config);
|
||||
macros_add_power_devices_to_panel(parent, power);
|
||||
macros_add_power_devices_to_panel(parent, printer);
|
||||
}
|
||||
|
||||
void macros_draw_power_fullscreen()
|
||||
{
|
||||
macros_draw_power_fullscreen(get_current_printer_config());
|
||||
macros_draw_power_fullscreen(get_current_printer());
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "lvgl.h"
|
||||
#include "../core/macros_query.h"
|
||||
#include "../conf/global_config.h"
|
||||
#include "../core/printer_integration.hpp"
|
||||
|
||||
void macros_add_macros_to_panel(lv_obj_t * root_panel, MACROSQUERY query);
|
||||
void macros_add_power_devices_to_panel(lv_obj_t * root_panel, POWERQUERY query);
|
||||
void macros_set_current_config(PRINTER_CONFIG * config);
|
||||
void macros_draw_power_fullscreen(PRINTER_CONFIG * config);
|
||||
int macros_add_macros_to_panel(lv_obj_t * root_panel, BasePrinter* printer);
|
||||
int macros_add_power_devices_to_panel(lv_obj_t * root_panel, BasePrinter* printer);
|
||||
void macros_draw_power_fullscreen(BasePrinter* printer);
|
||||
void macros_draw_power_fullscreen();
|
||||
@@ -2,17 +2,16 @@
|
||||
#include "../core/data_setup.h"
|
||||
#include "../conf/global_config.h"
|
||||
#include "../core/screen_driver.h"
|
||||
#include "../core/printer_integration.hpp"
|
||||
#include "lvgl.h"
|
||||
#include "nav_buttons.h"
|
||||
#include "ui_utils.h"
|
||||
#include "panels/panel.h"
|
||||
#include "../core/macros_query.h"
|
||||
#include "../core/lv_setup.h"
|
||||
#include "switch_printer.h"
|
||||
#include "macros.h"
|
||||
|
||||
void check_if_screen_needs_to_be_disabled(){
|
||||
if (global_config.on_during_print && printer.state == PRINTER_STATE_PRINTING){
|
||||
if (global_config.on_during_print && get_current_printer_data()->state == PrinterState::PrinterStatePrinting){
|
||||
screen_timer_wake();
|
||||
screen_timer_stop();
|
||||
}
|
||||
@@ -24,18 +23,29 @@ void check_if_screen_needs_to_be_disabled(){
|
||||
static void on_state_change(void * s, lv_msg_t * m){
|
||||
check_if_screen_needs_to_be_disabled();
|
||||
|
||||
if (printer.state == PRINTER_STATE_OFFLINE){
|
||||
PrinterData* printer = get_current_printer_data();
|
||||
|
||||
if (printer->state == PrinterState::PrinterStateOffline){
|
||||
nav_buttons_setup(PANEL_CONNECTING);
|
||||
}
|
||||
else if (printer.state == PRINTER_STATE_ERROR){
|
||||
else if (printer->state == PrinterState::PrinterStateError){
|
||||
nav_buttons_setup(PANEL_ERROR);
|
||||
}
|
||||
else {
|
||||
nav_buttons_setup(PANEL_PRINT);
|
||||
else if (printer->state == PrinterState::PrinterStateIdle) {
|
||||
nav_buttons_setup(PANEL_FILES);
|
||||
}
|
||||
else {
|
||||
nav_buttons_setup(PANEL_PROGRESS);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_popup_message(void * s, lv_msg_t * m)
|
||||
{
|
||||
lv_create_popup_message(get_current_printer_data()->popup_message, get_current_printer()->popup_message_timeout_s * 1000);
|
||||
}
|
||||
|
||||
void main_ui_setup(){
|
||||
lv_msg_subscribe(DATA_PRINTER_STATE, on_state_change, NULL);
|
||||
lv_msg_subscribe(DATA_PRINTER_POPUP, on_popup_message, NULL);
|
||||
on_state_change(NULL, NULL);
|
||||
}
|
||||
@@ -1,47 +1,45 @@
|
||||
#include "lvgl.h"
|
||||
#include "panels/panel.h"
|
||||
#include "../core/data_setup.h"
|
||||
#include "nav_buttons.h"
|
||||
#include "ui_utils.h"
|
||||
#include <stdio.h>
|
||||
#include "../conf/global_config.h"
|
||||
#include "../core/printer_integration.hpp"
|
||||
|
||||
static lv_style_t nav_button_style;
|
||||
|
||||
static char temp_buffer[10];
|
||||
static char z_pos_buffer[10];
|
||||
static char time_buffer[10];
|
||||
|
||||
static lv_style_t nav_button_text_style;
|
||||
|
||||
static void update_printer_data_z_pos(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char z_pos_buffer[10];
|
||||
|
||||
sprintf(z_pos_buffer, "Z%.2f", printer.position[2]);
|
||||
sprintf(z_pos_buffer, "Z%.2f", get_current_printer_data()->position[2]);
|
||||
lv_label_set_text(label, z_pos_buffer);
|
||||
}
|
||||
|
||||
static void update_printer_data_temp(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char temp_buffer[10];
|
||||
|
||||
sprintf(temp_buffer, "%.0f/%.0f", printer.extruder_temp, printer.bed_temp);
|
||||
sprintf(temp_buffer, "%.0f/%.0f", get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexNozzle1], get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexBed]);
|
||||
lv_label_set_text(label, temp_buffer);
|
||||
}
|
||||
|
||||
static void update_printer_data_time(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char time_buffer[10];
|
||||
|
||||
if (printer.state == PRINTER_STATE_IDLE){
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStateIdle){
|
||||
lv_label_set_text(label, "Idle");
|
||||
return;
|
||||
}
|
||||
|
||||
if (printer.state == PRINTER_STATE_PAUSED){
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePaused){
|
||||
lv_label_set_text(label, "Paused");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long time = printer.remaining_time_s;
|
||||
unsigned long time = get_current_printer_data()->remaining_time_s;
|
||||
unsigned long hours = time / 3600;
|
||||
unsigned long minutes = (time % 3600) / 60;
|
||||
unsigned long seconds = (time % 3600) % 60;
|
||||
@@ -57,8 +55,35 @@ static void update_printer_data_time(lv_event_t * e){
|
||||
lv_label_set_text(label, time_buffer);
|
||||
}
|
||||
|
||||
static void update_multi_printer_label(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
|
||||
int idle_count = 0;
|
||||
for (int i = 0; i < get_printer_count(); i++)
|
||||
{
|
||||
PrinterDataMinimal* data = get_printer_data_minimal(i);
|
||||
if (data->state == PrinterState::PrinterStateIdle)
|
||||
{
|
||||
idle_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (idle_count > 0)
|
||||
{
|
||||
lv_label_set_text_fmt(label, "%d idle", idle_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_label_set_text(label, "Printer");
|
||||
}
|
||||
}
|
||||
|
||||
static void btn_click_files(lv_event_t * e){
|
||||
nav_buttons_setup(PANEL_PRINT);
|
||||
nav_buttons_setup(PANEL_FILES);
|
||||
}
|
||||
|
||||
static void btn_click_progress(lv_event_t * e){
|
||||
nav_buttons_setup(PANEL_PROGRESS);
|
||||
}
|
||||
|
||||
static void btn_click_move(lv_event_t * e){
|
||||
@@ -115,7 +140,7 @@ void create_button(const char* icon, const char* name, lv_event_cb_t button_clic
|
||||
lv_obj_add_style(label, &nav_button_text_style, 0);
|
||||
}
|
||||
|
||||
void nav_buttons_setup(unsigned char active_panel){
|
||||
void nav_buttons_setup(PANEL_TYPE active_panel){
|
||||
lv_obj_clean(lv_scr_act());
|
||||
lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
@@ -132,17 +157,24 @@ void nav_buttons_setup(unsigned char active_panel){
|
||||
|
||||
#endif
|
||||
|
||||
if (printer.state > PRINTER_STATE_ERROR){
|
||||
if (get_current_printer_data()->state > PrinterState::PrinterStateError){
|
||||
// Files/Print
|
||||
create_button(LV_SYMBOL_COPY, "Idle", btn_click_files, update_printer_data_time, root_panel);
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStateIdle)
|
||||
{
|
||||
create_button(LV_SYMBOL_COPY, "Idle", btn_click_files, update_printer_data_time, root_panel);
|
||||
}
|
||||
else
|
||||
{
|
||||
create_button(LV_SYMBOL_FILE, "Paused", btn_click_progress, update_printer_data_time, root_panel);
|
||||
}
|
||||
|
||||
// Move
|
||||
create_button(printer.state == PRINTER_STATE_PRINTING ? LV_SYMBOL_EDIT : LV_SYMBOL_CHARGE, "Z?", btn_click_move, update_printer_data_z_pos, root_panel);
|
||||
create_button(get_current_printer_data()->state == PrinterState::PrinterStatePrinting ? LV_SYMBOL_EDIT : LV_SYMBOL_CHARGE, "Z?", btn_click_move, update_printer_data_z_pos, root_panel);
|
||||
|
||||
// Extrude/Temp
|
||||
create_button(LV_SYMBOL_WARNING, "?/?", btn_click_extrude, update_printer_data_temp, root_panel);
|
||||
}
|
||||
else if (printer.state == PRINTER_STATE_ERROR) {
|
||||
else if (get_current_printer_data()->state == PrinterState::PrinterStateError) {
|
||||
// Error UI
|
||||
create_button(LV_SYMBOL_WARNING, "Error", btn_click_err, NULL, root_panel);
|
||||
}
|
||||
@@ -157,7 +189,7 @@ void nav_buttons_setup(unsigned char active_panel){
|
||||
if (global_config.multi_printer_mode)
|
||||
{
|
||||
// Printers
|
||||
create_button(LV_SYMBOL_HOME, "Printer", btn_click_printer, NULL, root_panel);
|
||||
create_button(LV_SYMBOL_HOME, "Printer", btn_click_printer, update_multi_printer_label, root_panel);
|
||||
}
|
||||
|
||||
lv_obj_t * panel = lv_create_empty_panel(lv_scr_act());
|
||||
@@ -165,8 +197,8 @@ void nav_buttons_setup(unsigned char active_panel){
|
||||
lv_obj_align(panel, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
|
||||
switch (active_panel){
|
||||
case PANEL_PRINT:
|
||||
print_panel_init(panel);
|
||||
case PANEL_FILES:
|
||||
files_panel_init(panel);
|
||||
break;
|
||||
case PANEL_MOVE:
|
||||
move_panel_init(panel);
|
||||
@@ -192,9 +224,12 @@ void nav_buttons_setup(unsigned char active_panel){
|
||||
case PANEL_CONNECTING:
|
||||
connecting_panel_init(panel);
|
||||
break;
|
||||
case PANEL_PROGRESS:
|
||||
progress_panel_init(panel);
|
||||
break;
|
||||
}
|
||||
|
||||
lv_msg_send(DATA_PRINTER_DATA, &printer);
|
||||
lv_msg_send(DATA_PRINTER_DATA, get_current_printer());
|
||||
}
|
||||
|
||||
void nav_style_setup(){
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#define PANEL_PRINT 0
|
||||
#define PANEL_MOVE 1
|
||||
#define PANEL_TEMP 2
|
||||
#define PANEL_SETTINGS 3
|
||||
#define PANEL_MACROS 4
|
||||
#define PANEL_STATS 5
|
||||
#define PANEL_PRINTER 6
|
||||
#define PANEL_ERROR 7
|
||||
#define PANEL_CONNECTING 8
|
||||
enum PANEL_TYPE {
|
||||
PANEL_FILES = 0,
|
||||
PANEL_MOVE = 1,
|
||||
PANEL_TEMP = 2,
|
||||
PANEL_SETTINGS = 3,
|
||||
PANEL_MACROS = 4,
|
||||
PANEL_STATS = 5,
|
||||
PANEL_PRINTER = 6,
|
||||
PANEL_ERROR = 7,
|
||||
PANEL_CONNECTING = 8,
|
||||
PANEL_PROGRESS = 9,
|
||||
};
|
||||
|
||||
void nav_buttons_setup(unsigned char active_panel);
|
||||
void nav_buttons_setup(PANEL_TYPE active_panel);
|
||||
void nav_style_setup();
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../core/data_setup.h"
|
||||
#include "../conf/global_config.h"
|
||||
#include "ota_setup.h"
|
||||
#include "../core/semaphore.h"
|
||||
|
||||
//const char *ota_url = "https://gist.githubusercontent.com/suchmememanyskill/ece418fe199e155340de6c224a0badf2/raw/0d6762d68bc807cbecc71e40d55b76692397a7b3/update.json"; // Test url
|
||||
const char *ota_url = "https://suchmememanyskill.github.io/CYD-Klipper/OTA.json"; // Prod url
|
||||
@@ -46,7 +47,7 @@ void do_update_callback(int offset, int totallength)
|
||||
|
||||
void ota_do_update(bool variant_automatic)
|
||||
{
|
||||
Serial.println("Starting OTA Update");
|
||||
LOG_LN("Starting OTA Update");
|
||||
lv_obj_clean(lv_scr_act());
|
||||
|
||||
lv_obj_t *panel = lv_create_empty_panel(lv_scr_act());
|
||||
@@ -64,7 +65,7 @@ void ota_do_update(bool variant_automatic)
|
||||
lv_label_set_text(update_label, "0/0");
|
||||
|
||||
if (!variant_automatic) {
|
||||
Serial.println("Freezing Background Tasks");
|
||||
LOG_LN("Freezing Background Tasks");
|
||||
screen_timer_wake();
|
||||
screen_timer_stop();
|
||||
freeze_request_thread();
|
||||
@@ -82,7 +83,7 @@ void ota_init()
|
||||
{
|
||||
//ota_pull.AllowDowngrades(true);
|
||||
int result = ota_pull.CheckForOTAUpdate(ota_url, REPO_VERSION, ESP32OTAPull::ActionType::DONT_DO_UPDATE);
|
||||
Serial.printf("OTA Update Result: %d\n", result);
|
||||
LOG_F(("OTA Update Result: %d\n", result))
|
||||
update_available = result == ESP32OTAPull::UPDATE_AVAILABLE;
|
||||
|
||||
if (global_config.auto_ota_update && update_available)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "panel.h"
|
||||
#include "../../conf/global_config.h"
|
||||
#include "../../core/printer_integration.hpp"
|
||||
|
||||
void connecting_panel_init(lv_obj_t* panel)
|
||||
{
|
||||
lv_obj_t* label = lv_label_create(panel);
|
||||
lv_label_set_text_fmt(label, "Connecting to %s...", (get_current_printer_config()->printer_name[0] == 0) ? get_current_printer_config()->klipper_host : get_current_printer_config()->printer_name);
|
||||
lv_label_set_text_fmt(label, "Connecting to %s...", (get_current_printer()->printer_config->printer_name[0] == 0)
|
||||
? get_current_printer()->printer_config->printer_host
|
||||
: get_current_printer()->printer_config->printer_name);
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
@@ -1,13 +1,42 @@
|
||||
#include "panel.h"
|
||||
#include "../../core/data_setup.h"
|
||||
#include "../../core/current_printer.h"
|
||||
#include "../ui_utils.h"
|
||||
#include "../../core/printer_integration.hpp"
|
||||
|
||||
static void btn_click_restart(lv_event_t * e){
|
||||
send_gcode(false, "RESTART");
|
||||
current_printer_execute_feature(PrinterFeatureRestart);
|
||||
}
|
||||
|
||||
static void btn_click_firmware_restart(lv_event_t * e){
|
||||
send_gcode(false, "FIRMWARE_RESTART");
|
||||
current_printer_execute_feature(PrinterFeatureFirmwareRestart);
|
||||
}
|
||||
|
||||
static void btn_click_error_ignore(lv_event_t * e){
|
||||
current_printer_execute_feature(PrinterFeatureIgnoreError);
|
||||
}
|
||||
|
||||
static void btn_click_error_continue(lv_event_t * e){
|
||||
current_printer_execute_feature(PrinterFeatureContinueError);
|
||||
}
|
||||
|
||||
static void btn_click_error_retry(lv_event_t * e){
|
||||
current_printer_execute_feature(PrinterFeatureRetryError);
|
||||
}
|
||||
|
||||
static void set_state_message_text(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_label_set_text(label, get_current_printer_data()->state_message);
|
||||
}
|
||||
|
||||
void create_button(const char* label, lv_event_cb_t on_click, lv_obj_t * root){
|
||||
lv_obj_t* btn = lv_btn_create(root);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, on_click, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label_obj = lv_label_create(btn);
|
||||
lv_label_set_text(label_obj, label);
|
||||
lv_obj_center(label_obj);
|
||||
}
|
||||
|
||||
void error_panel_init(lv_obj_t* panel)
|
||||
@@ -25,29 +54,37 @@ void error_panel_init(lv_obj_t* panel)
|
||||
lv_obj_set_width(panel_with_text, CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
|
||||
label = lv_label_create(panel_with_text);
|
||||
lv_label_set_text(label, printer.state_message);
|
||||
lv_obj_set_width(label, CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
|
||||
|
||||
lv_obj_add_event_cb(label, set_state_message_text, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_msg_subscribe_obj(DATA_PRINTER_DATA, label, NULL);
|
||||
|
||||
lv_obj_t * button_row = lv_create_empty_panel(panel);
|
||||
lv_obj_set_size(button_row, CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_layout_flex_row(button_row);
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(button_row);
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, btn_click_restart, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
if (get_current_printer_data()->error_screen_features & PrinterFeatureRestart)
|
||||
{
|
||||
create_button("Restart", btn_click_restart, button_row);
|
||||
}
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "Restart");
|
||||
lv_obj_center(label);
|
||||
if (get_current_printer_data()->error_screen_features & PrinterFeatureFirmwareRestart)
|
||||
{
|
||||
create_button("FW Restart", btn_click_firmware_restart, button_row);
|
||||
}
|
||||
|
||||
btn = lv_btn_create(button_row);
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, btn_click_firmware_restart, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
if (get_current_printer_data()->error_screen_features & PrinterFeatureIgnoreError)
|
||||
{
|
||||
create_button("Ignore", btn_click_error_ignore, button_row);
|
||||
}
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "FW Restart");
|
||||
lv_obj_center(label);
|
||||
if (get_current_printer_data()->error_screen_features & PrinterFeatureContinueError)
|
||||
{
|
||||
create_button("Done", btn_click_error_continue, button_row);
|
||||
}
|
||||
|
||||
if (get_current_printer_data()->error_screen_features & PrinterFeatureRetryError)
|
||||
{
|
||||
create_button("Retry", btn_click_error_retry, button_row);
|
||||
}
|
||||
}
|
||||
142
CYD-Klipper/src/ui/panels/files_panel.cpp
Normal file
142
CYD-Klipper/src/ui/panels/files_panel.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "lvgl.h"
|
||||
#include "panel.h"
|
||||
|
||||
#include "../../core/current_printer.h"
|
||||
#include "../../conf/global_config.h"
|
||||
#include <HardwareSerial.h>
|
||||
#include "../ui_utils.h"
|
||||
#include "../../core/lv_setup.h"
|
||||
#include <UrlEncode.h>
|
||||
#include "../../core/printer_integration.hpp"
|
||||
|
||||
const char* selected_file = NULL;
|
||||
|
||||
static void btn_print_file(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * panel = (lv_obj_t*)lv_event_get_user_data(e);
|
||||
lv_obj_del(panel);
|
||||
|
||||
current_printer_start_file(selected_file);
|
||||
}
|
||||
|
||||
static void btn_print_file_verify_instant(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
selected_file = (char*)lv_event_get_user_data(e);
|
||||
current_printer_start_file(selected_file);
|
||||
}
|
||||
|
||||
static void btn_print_file_verify(lv_event_t * e)
|
||||
{
|
||||
if (get_current_printer_data()->state != PrinterState::PrinterStateIdle){
|
||||
return;
|
||||
}
|
||||
|
||||
selected_file = (char*)lv_event_get_user_data(e);
|
||||
|
||||
lv_obj_t * panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_style_pad_hor(panel, CYD_SCREEN_GAP_PX * 2, 0);
|
||||
lv_obj_set_style_pad_ver(panel, CYD_SCREEN_GAP_PX, 0);
|
||||
lv_obj_set_size(panel, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 4, CYD_SCREEN_HEIGHT_PX - CYD_SCREEN_GAP_PX * 3);
|
||||
lv_obj_align(panel, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_layout_flex_column(panel, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
lv_obj_t * label_print_file = lv_label_create(panel);
|
||||
lv_label_set_text(label_print_file, "Print File");
|
||||
|
||||
lv_obj_t * top_panel = lv_create_empty_panel(panel);
|
||||
lv_obj_set_width(top_panel, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(top_panel, 1);
|
||||
lv_layout_flex_row(top_panel, LV_FLEX_ALIGN_CENTER);
|
||||
|
||||
Thumbnail thumbnail = current_printer_get_32_32_png_image_thumbnail(selected_file);
|
||||
lv_obj_t * img = NULL;
|
||||
|
||||
if (thumbnail.success)
|
||||
{
|
||||
lv_img_dsc_t* img_header = (lv_img_dsc_t*)malloc(sizeof(lv_img_dsc_t));
|
||||
lv_obj_on_destroy_free_data(panel, img_header);
|
||||
|
||||
memset(img_header, 0, sizeof(lv_img_dsc_t));
|
||||
img_header->header.w = 32;
|
||||
img_header->header.h = 32;
|
||||
img_header->data_size = thumbnail.size;
|
||||
img_header->header.cf = LV_IMG_CF_RAW_ALPHA;
|
||||
img_header->data = thumbnail.png;
|
||||
|
||||
img = lv_img_create(top_panel);
|
||||
lv_img_set_src(img, img_header);
|
||||
lv_img_set_antialias(img, true);
|
||||
lv_img_set_size_mode(img, LV_IMG_SIZE_MODE_REAL);
|
||||
|
||||
if (global_config.double_size_gcode_img)
|
||||
{
|
||||
lv_img_set_zoom(img, LV_IMG_ZOOM_NONE * 2);
|
||||
}
|
||||
}
|
||||
|
||||
lv_obj_t * label = lv_label_create(top_panel);
|
||||
lv_label_set_text(label, selected_file);
|
||||
lv_obj_set_height(label, LV_SIZE_CONTENT);
|
||||
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_set_flex_grow(label, 1);
|
||||
|
||||
lv_obj_t* buttons_panel = lv_create_empty_panel(panel);
|
||||
lv_layout_flex_row(buttons_panel);
|
||||
lv_obj_set_size(buttons_panel, LV_PCT(100), CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
|
||||
lv_obj_t* btn = lv_btn_create(buttons_panel);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, destroy_event_user_data, LV_EVENT_CLICKED, panel);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_CLOSE " Cancel");
|
||||
lv_obj_center(label);
|
||||
|
||||
btn = lv_btn_create(buttons_panel);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, btn_print_file, LV_EVENT_CLICKED, panel);
|
||||
lv_obj_add_event_cb(btn, destroy_event_user_data, LV_EVENT_CLICKED, panel);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_OK " Print");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
void files_panel_init(lv_obj_t* panel){
|
||||
Files files = current_printer_get_files();
|
||||
|
||||
if (!files.success || files.count <= 0){
|
||||
lv_obj_t * label = lv_label_create(panel);
|
||||
lv_label_set_text(label, "Failed to read files.");
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_t * list = lv_list_create(panel);
|
||||
lv_obj_set_style_radius(list, 0, 0);
|
||||
lv_obj_set_style_border_width(list, 0, 0);
|
||||
lv_obj_set_style_bg_opa(list, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_size(list, CYD_SCREEN_PANEL_WIDTH_PX, CYD_SCREEN_PANEL_HEIGHT_PX);
|
||||
lv_obj_align(list, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
for (int i = 0; i < files.count; i++)
|
||||
{
|
||||
lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_FILE, files.available_files[i]);
|
||||
lv_obj_set_style_bg_opa(btn, LV_OPA_TRANSP, 0);
|
||||
|
||||
if (global_config.full_filenames)
|
||||
{
|
||||
lv_label_set_long_mode(lv_obj_get_child(btn, 1), LV_LABEL_LONG_WRAP);
|
||||
}
|
||||
|
||||
lv_obj_add_event_cb(btn, (get_current_printer()->no_confirm_print_file) ? btn_print_file_verify_instant : btn_print_file_verify, LV_EVENT_CLICKED, (void*)(files.available_files[i]));
|
||||
lv_obj_on_destroy_free_data(btn, files.available_files[i]);
|
||||
}
|
||||
|
||||
// Not deallocating filenames in this scope will cause double allocation, oh well.
|
||||
// TODO: read label text
|
||||
free(files.available_files);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "../macros.h"
|
||||
#include "panel.h"
|
||||
#include "../nav_buttons.h"
|
||||
#include "../../core/data_setup.h"
|
||||
#include "../../conf/global_config.h"
|
||||
#include "../ui_utils.h"
|
||||
#include <HardwareSerial.h>
|
||||
@@ -11,8 +10,6 @@ static void btn_goto_settings(lv_event_t * e){
|
||||
}
|
||||
|
||||
void macros_panel_init(lv_obj_t* panel) {
|
||||
macros_set_current_config(get_current_printer_config());
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(panel);
|
||||
lv_obj_add_event_cb(btn, btn_goto_settings, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
@@ -22,27 +19,32 @@ void macros_panel_init(lv_obj_t* panel) {
|
||||
lv_label_set_text(label, LV_SYMBOL_SETTINGS " Screen Settings");
|
||||
lv_obj_center(label);
|
||||
|
||||
MACROSQUERY macros = macros_query();
|
||||
POWERQUERY power = power_devices_query();
|
||||
|
||||
lv_obj_t * root_panel = lv_create_empty_panel(panel);
|
||||
lv_obj_set_scrollbar_mode(root_panel, LV_SCROLLBAR_MODE_OFF);
|
||||
lv_obj_set_size(root_panel, CYD_SCREEN_PANEL_WIDTH_PX, CYD_SCREEN_PANEL_HEIGHT_PX - CYD_SCREEN_MIN_BUTTON_HEIGHT_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
lv_obj_align(root_panel, LV_ALIGN_TOP_MID, 0, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX + CYD_SCREEN_GAP_PX * 2);
|
||||
lv_layout_flex_column(root_panel);
|
||||
|
||||
macros_add_power_devices_to_panel(root_panel, power);
|
||||
int power_count = macros_add_power_devices_to_panel(root_panel, get_current_printer());
|
||||
int macros_count = macros_add_macros_to_panel(root_panel, get_current_printer());
|
||||
|
||||
if (macros.count == 0){
|
||||
if (macros_count <= 0){
|
||||
label = lv_label_create(root_panel);
|
||||
lv_label_set_text(label, "No macros found.\nMacros with the description\n\"CYD_SCREEN_MACRO\"\nwill show up here.");
|
||||
if (get_current_printer()->printer_config->printer_type == PrinterType::PrinterTypeKlipper
|
||||
|| get_current_printer()->printer_config->printer_type == PrinterType::PrinterTypeKlipperSerial)
|
||||
{
|
||||
lv_label_set_text(label, "No macros found.\nMacros with the description\n\"CYD_SCREEN_MACRO\"\nwill show up here.");
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_label_set_text(label, "No macros found.");
|
||||
}
|
||||
|
||||
|
||||
if (power.count == 0){
|
||||
if (power_count <= 0){
|
||||
lv_layout_flex_column(root_panel, LV_FLEX_ALIGN_CENTER);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
macros_add_macros_to_panel(root_panel, macros);
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "../ui_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <Esp.h>
|
||||
#include "../../core/printer_integration.hpp"
|
||||
#include "../../core/current_printer.h"
|
||||
|
||||
static bool last_homing_state = false;
|
||||
static bool move_edit_mode = false;
|
||||
@@ -21,7 +23,7 @@ char z_offset_labels[6 * OFFSET_LABEL_SIZE] = {0};
|
||||
|
||||
static void calculate_offsets_from_current_printer()
|
||||
{
|
||||
unsigned short* items[] = {get_current_printer_config()->printer_move_x_steps, get_current_printer_config()->printer_move_y_steps, get_current_printer_config()->printer_move_z_steps};
|
||||
unsigned short* items[] = {get_current_printer()->printer_config->printer_move_x_steps, get_current_printer()->printer_config->printer_move_y_steps, get_current_printer()->printer_config->printer_move_z_steps};
|
||||
float* offsets[] = {(float*)x_offsets, (float*)y_offsets, (float*)z_offsets};
|
||||
char * labels[] = {(char*)x_offset_labels, (char*)y_offset_labels, (char*)z_offset_labels};
|
||||
|
||||
@@ -74,8 +76,8 @@ static void keyboard_cb_edit_move_increment(lv_event_t * e)
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned short* items[] = {get_current_printer_config()->printer_move_x_steps, get_current_printer_config()->printer_move_y_steps, get_current_printer_config()->printer_move_z_steps};
|
||||
Serial.printf("Setting increment %d %d %f\n", selected_column, selected_row, increment);
|
||||
unsigned short* items[] = {get_current_printer()->printer_config->printer_move_x_steps, get_current_printer()->printer_config->printer_move_y_steps, get_current_printer()->printer_config->printer_move_z_steps};
|
||||
LOG_F(("Setting increment %d %d %f\n", selected_column, selected_row, increment))
|
||||
items[selected_column][selected_row] = increment * 10;
|
||||
write_global_config();
|
||||
nav_buttons_setup(PANEL_MOVE);
|
||||
@@ -96,7 +98,7 @@ static void edit_move_increment(int column, float* idx)
|
||||
}
|
||||
|
||||
selected_column = column;
|
||||
lv_create_keyboard_text_entry(keyboard_cb_edit_move_increment, "Set increment", LV_KEYBOARD_MODE_NUMBER, CYD_SCREEN_PANEL_WIDTH_PX / 2, 6);
|
||||
lv_create_keyboard_text_entry(keyboard_cb_edit_move_increment, "Set increment", LV_KEYBOARD_MODE_NUMBER, LV_PCT(75), 6);
|
||||
}
|
||||
|
||||
static void x_line_button_press(lv_event_t * e) {
|
||||
@@ -109,7 +111,7 @@ static void x_line_button_press(lv_event_t * e) {
|
||||
}
|
||||
|
||||
float data = *data_pointer;
|
||||
move_printer("X", data, true);
|
||||
current_printer_move_printer("X", data, true);
|
||||
}
|
||||
|
||||
static void y_line_button_press(lv_event_t * e) {
|
||||
@@ -122,7 +124,7 @@ static void y_line_button_press(lv_event_t * e) {
|
||||
}
|
||||
|
||||
float data = *data_pointer;
|
||||
move_printer("Y", data, true);
|
||||
current_printer_move_printer("Y", data, true);
|
||||
}
|
||||
|
||||
static void z_line_button_press(lv_event_t * e) {
|
||||
@@ -135,27 +137,27 @@ static void z_line_button_press(lv_event_t * e) {
|
||||
}
|
||||
|
||||
float data = *data_pointer;
|
||||
move_printer("Z", data, true);
|
||||
current_printer_move_printer("Z", data, true);
|
||||
}
|
||||
|
||||
static void x_pos_update(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char x_pos_buff[12];
|
||||
sprintf(x_pos_buff, "X: %.1f", printer.position[0]);
|
||||
sprintf(x_pos_buff, "X: %.1f", get_current_printer_data()->position[0]);
|
||||
lv_label_set_text(label, x_pos_buff);
|
||||
}
|
||||
|
||||
static void y_pos_update(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char y_pos_buff[12];
|
||||
sprintf(y_pos_buff, "Y: %.1f", printer.position[1]);
|
||||
sprintf(y_pos_buff, "Y: %.1f", get_current_printer_data()->position[1]);
|
||||
lv_label_set_text(label, y_pos_buff);
|
||||
}
|
||||
|
||||
static void z_pos_update(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char z_pos_buff[12];
|
||||
sprintf(z_pos_buff, "Z: %.2f", printer.position[2]);
|
||||
sprintf(z_pos_buff, "Z: %.2f", get_current_printer_data()->position[2]);
|
||||
lv_label_set_text(label, z_pos_buff);
|
||||
}
|
||||
|
||||
@@ -163,17 +165,17 @@ lv_event_cb_t button_callbacks[] = {x_line_button_press, y_line_button_press, z_
|
||||
lv_event_cb_t position_callbacks[] = {x_pos_update, y_pos_update, z_pos_update};
|
||||
|
||||
static void home_button_click(lv_event_t * e) {
|
||||
if (printer.state == PRINTER_STATE_PRINTING)
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePrinting)
|
||||
return;
|
||||
|
||||
send_gcode(false, "G28");
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureHome);
|
||||
}
|
||||
|
||||
static void disable_steppers_click(lv_event_t * e) {
|
||||
if (printer.state == PRINTER_STATE_PRINTING)
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePrinting)
|
||||
return;
|
||||
|
||||
send_gcode(true, "M18");
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureDisableSteppers);
|
||||
}
|
||||
|
||||
static void switch_to_stat_panel(lv_event_t * e) {
|
||||
@@ -194,7 +196,7 @@ static void line_custom_set(const char * axis, const char *text)
|
||||
if (pos < 0 || pos > 500)
|
||||
return;
|
||||
|
||||
move_printer(axis, pos, false);
|
||||
current_printer_move_printer(axis, pos, false);
|
||||
}
|
||||
|
||||
static void x_line_custom_callback(lv_event_t * e) {
|
||||
@@ -213,15 +215,15 @@ static void z_line_custom_callback(lv_event_t * e) {
|
||||
}
|
||||
|
||||
static void x_line_custom(lv_event_t * e) {
|
||||
lv_create_keyboard_text_entry(x_line_custom_callback, "Set X position", LV_KEYBOARD_MODE_NUMBER, CYD_SCREEN_PANEL_WIDTH_PX / 2, 6);
|
||||
lv_create_keyboard_text_entry(x_line_custom_callback, "Set X position", LV_KEYBOARD_MODE_NUMBER, LV_PCT(75), 6);
|
||||
}
|
||||
|
||||
static void y_line_custom(lv_event_t * e) {
|
||||
lv_create_keyboard_text_entry(y_line_custom_callback, "Set Y position", LV_KEYBOARD_MODE_NUMBER, CYD_SCREEN_PANEL_WIDTH_PX / 2, 6);
|
||||
lv_create_keyboard_text_entry(y_line_custom_callback, "Set Y position", LV_KEYBOARD_MODE_NUMBER, LV_PCT(75), 6);
|
||||
}
|
||||
|
||||
static void z_line_custom(lv_event_t * e) {
|
||||
lv_create_keyboard_text_entry(z_line_custom_callback, "Set Z position", LV_KEYBOARD_MODE_NUMBER, CYD_SCREEN_PANEL_WIDTH_PX / 2, 6);
|
||||
lv_create_keyboard_text_entry(z_line_custom_callback, "Set Z position", LV_KEYBOARD_MODE_NUMBER, LV_PCT(75), 6);
|
||||
}
|
||||
|
||||
lv_event_cb_t custom_callbacks[] = {x_line_custom, y_line_custom, z_line_custom};
|
||||
@@ -339,28 +341,28 @@ inline void root_panel_steppers_unlocked(lv_obj_t * root_panel){
|
||||
}
|
||||
|
||||
static void root_panel_state_update(lv_event_t * e){
|
||||
if (last_homing_state == printer.homed_axis)
|
||||
if (last_homing_state == get_current_printer_data()->homed_axis)
|
||||
return;
|
||||
|
||||
lv_obj_t * panel = lv_event_get_target(e);
|
||||
last_homing_state = printer.homed_axis;
|
||||
last_homing_state = get_current_printer_data()->homed_axis;
|
||||
|
||||
lv_obj_clean(panel);
|
||||
|
||||
if (printer.homed_axis)
|
||||
if (get_current_printer_data()->homed_axis)
|
||||
root_panel_steppers_locked(panel);
|
||||
else
|
||||
root_panel_steppers_unlocked(panel);
|
||||
}
|
||||
|
||||
void move_panel_init(lv_obj_t* panel){
|
||||
if (printer.state == PRINTER_STATE_PRINTING){
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePrinting){
|
||||
stats_panel_init(panel);
|
||||
return;
|
||||
}
|
||||
|
||||
calculate_offsets_from_current_printer();
|
||||
last_homing_state = !printer.homed_axis;
|
||||
last_homing_state = !get_current_printer_data()->homed_axis;
|
||||
|
||||
lv_obj_add_event_cb(panel, root_panel_state_update, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_DATA, panel, NULL);
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
#include "lvgl.h"
|
||||
#include "../../core/macros_query.h"
|
||||
|
||||
#define SIZEOF(arr) (sizeof(arr) / sizeof(*arr))
|
||||
|
||||
void settings_panel_init(lv_obj_t* panel);
|
||||
void temp_panel_init(lv_obj_t* panel);
|
||||
void print_panel_init(lv_obj_t* panel);
|
||||
void files_panel_init(lv_obj_t* panel);
|
||||
void move_panel_init(lv_obj_t* panel);
|
||||
void progress_panel_init(lv_obj_t* panel);
|
||||
void macros_panel_init(lv_obj_t* panel);
|
||||
void stats_panel_init(lv_obj_t* panel);
|
||||
void printer_panel_init(lv_obj_t* panel);
|
||||
void error_panel_init(lv_obj_t* panel);
|
||||
void connecting_panel_init(lv_obj_t* panel);
|
||||
void connecting_panel_init(lv_obj_t* panel);
|
||||
|
||||
void settings_section_device(lv_obj_t* panel);
|
||||
@@ -1,111 +0,0 @@
|
||||
#include "lvgl.h"
|
||||
#include "panel.h"
|
||||
#include "../../core/data_setup.h"
|
||||
#include "../../core/files_query.h"
|
||||
#include "../../conf/global_config.h"
|
||||
#include <HardwareSerial.h>
|
||||
#include "../ui_utils.h"
|
||||
#include "../../core/lv_setup.h"
|
||||
#include "../gcode_img.h"
|
||||
#include "../../core/http_client.h"
|
||||
#include <UrlEncode.h>
|
||||
|
||||
FILESYSTEM_FILE* selected_file = NULL;
|
||||
|
||||
static void btn_print_file(lv_event_t * e){
|
||||
lv_obj_t * panel = (lv_obj_t*)lv_event_get_user_data(e);
|
||||
lv_obj_del(panel);
|
||||
|
||||
SETUP_HTTP_CLIENT("/printer/print/start?filename=" + urlEncode(selected_file->name));
|
||||
|
||||
int httpCode = client.POST("");
|
||||
Serial.printf("Print start: HTTP %d\n", httpCode);
|
||||
}
|
||||
|
||||
static void btn_print_file_verify(lv_event_t * e){
|
||||
const auto button_size_mult = 1.3f;
|
||||
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
selected_file = (FILESYSTEM_FILE*)lv_event_get_user_data(e);
|
||||
|
||||
lv_obj_t * panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_style_pad_all(panel, CYD_SCREEN_GAP_PX * 2, 0);
|
||||
lv_obj_set_size(panel, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 4, CYD_SCREEN_HEIGHT_PX - CYD_SCREEN_GAP_PX * 3);
|
||||
lv_obj_align(panel, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
lv_obj_t * label_print_file = lv_label_create(panel);
|
||||
lv_label_set_text(label_print_file, "Print File");
|
||||
lv_obj_align(label_print_file, LV_ALIGN_TOP_LEFT, 0, 0);
|
||||
|
||||
lv_obj_t * label = lv_label_create(panel);
|
||||
lv_label_set_text(label, selected_file->name);
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, -20);
|
||||
lv_obj_set_width(label, CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 10);
|
||||
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
|
||||
|
||||
btn = lv_btn_create(panel);
|
||||
lv_obj_align(btn, LV_ALIGN_BOTTOM_LEFT, 0, 0);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_MIN_BUTTON_WIDTH_PX * button_size_mult, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX * button_size_mult);
|
||||
lv_obj_add_event_cb(btn, destroy_event_user_data, LV_EVENT_CLICKED, panel);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_CLOSE);
|
||||
lv_obj_center(label);
|
||||
|
||||
btn = lv_btn_create(panel);
|
||||
lv_obj_align(btn, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_MIN_BUTTON_WIDTH_PX * button_size_mult, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX * button_size_mult);
|
||||
lv_obj_add_event_cb(btn, btn_print_file, LV_EVENT_CLICKED, panel);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_OK);
|
||||
lv_obj_center(label);
|
||||
|
||||
lv_obj_t* img = show_gcode_img(selected_file->name);
|
||||
|
||||
if (img != NULL){
|
||||
lv_obj_set_parent(img, panel);
|
||||
lv_obj_align(img, LV_ALIGN_TOP_LEFT, 0, 0);
|
||||
|
||||
lv_obj_t * text_center_panel = lv_create_empty_panel(panel);
|
||||
lv_obj_set_size(text_center_panel, CYD_SCREEN_MIN_BUTTON_WIDTH_PX * 2, 32);
|
||||
lv_obj_align(text_center_panel, LV_ALIGN_TOP_LEFT, CYD_SCREEN_GAP_PX + 32, 0);
|
||||
|
||||
lv_obj_set_parent(label_print_file, text_center_panel);
|
||||
lv_obj_align(label_print_file, LV_ALIGN_LEFT_MID, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void print_panel_init(lv_obj_t* panel){
|
||||
if (printer.state == PRINTER_STATE_PRINTING || printer.state == PRINTER_STATE_PAUSED){
|
||||
progress_panel_init(panel);
|
||||
return;
|
||||
}
|
||||
|
||||
clear_img_mem();
|
||||
|
||||
lv_obj_t * list = lv_list_create(panel);
|
||||
lv_obj_set_style_radius(list, 0, 0);
|
||||
lv_obj_set_style_border_width(list, 0, 0);
|
||||
lv_obj_set_style_bg_opa(list, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_size(list, CYD_SCREEN_PANEL_WIDTH_PX, CYD_SCREEN_PANEL_HEIGHT_PX);
|
||||
lv_obj_align(list, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
FILESYSTEM_FILE* files = get_files(25);
|
||||
int count = 0;
|
||||
while (files != NULL && files->name != NULL && count <= 20){
|
||||
lv_obj_t * btn = lv_list_add_btn(list, LV_SYMBOL_FILE, files->name);
|
||||
lv_obj_set_style_bg_opa(btn, LV_OPA_TRANSP, 0);
|
||||
lv_obj_add_event_cb(btn, btn_print_file_verify, LV_EVENT_CLICKED, (void*)files);
|
||||
|
||||
files += 1;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count <= 0){
|
||||
lv_obj_del(list);
|
||||
lv_obj_t * label = lv_label_create(panel);
|
||||
lv_label_set_text(label, "Failed to read files.");
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "../../core/lv_setup.h"
|
||||
#include <stdio.h>
|
||||
#include "../nav_buttons.h"
|
||||
#include "../../core/macros_query.h"
|
||||
#include "../switch_printer.h"
|
||||
#include "../macros.h"
|
||||
|
||||
const char * printer_status[] = {
|
||||
@@ -22,41 +20,32 @@ const static lv_point_t line_points[] = { {0, 0}, {(short int)((CYD_SCREEN_PANEL
|
||||
static void update_printer_name_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
PrinterMinimal * printer = &printer_minimal[index];
|
||||
|
||||
lv_label_set_text(label, config->printer_name[0] == 0 ? config->klipper_host : config->printer_name);
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
BasePrinter* printer = get_printer(config_index);
|
||||
lv_label_set_text(label, printer->printer_config->printer_name[0] == 0 ? printer->printer_config->printer_host : printer->printer_config->printer_name);
|
||||
}
|
||||
|
||||
static void update_printer_status_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
PrinterMinimal * printer = &printer_minimal[index];
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
PrinterDataMinimal* printer = get_printer_data_minimal(config_index);
|
||||
|
||||
if (config == get_current_printer_config())
|
||||
if (config_index == get_current_printer_index())
|
||||
{
|
||||
lv_label_set_text(label, "In Control");
|
||||
return;
|
||||
}
|
||||
|
||||
if (printer->state == PRINTER_STATE_OFFLINE)
|
||||
{
|
||||
lv_label_set_text(label, "Offline");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_label_set_text(label, printer_status[printer->state]);
|
||||
}
|
||||
|
||||
static void update_printer_label_visible_active_printer(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
|
||||
if (config == get_current_printer_config())
|
||||
if (config_index == get_current_printer_index())
|
||||
{
|
||||
lv_label_set_text(label, LV_SYMBOL_WIFI);
|
||||
}
|
||||
@@ -69,14 +58,15 @@ static void update_printer_label_visible_active_printer(lv_event_t * e)
|
||||
static void update_printer_percentage_bar(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * percentage = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
PrinterMinimal * printer = &printer_minimal[index];
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
PrinterDataMinimal* printer = get_printer_data_minimal(config_index);
|
||||
|
||||
if (printer->state != PRINTER_STATE_OFFLINE && (printer->state == PRINTER_STATE_PRINTING || printer->state == PRINTER_STATE_PAUSED)){
|
||||
if (printer->state == PrinterState::PrinterStatePrinting || printer->state == PrinterState::PrinterStatePaused)
|
||||
{
|
||||
lv_bar_set_value(percentage, printer->print_progress * 100, LV_ANIM_OFF);
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
lv_bar_set_value(percentage, 0, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
@@ -84,11 +74,10 @@ static void update_printer_percentage_bar(lv_event_t * e)
|
||||
static void update_printer_percentage_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
PrinterMinimal * printer = &printer_minimal[index];
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
PrinterDataMinimal* printer = get_printer_data_minimal(config_index);
|
||||
|
||||
if (printer->state != PRINTER_STATE_OFFLINE && (printer->state == PRINTER_STATE_PRINTING || printer->state == PRINTER_STATE_PAUSED))
|
||||
if (printer->state == PrinterState::PrinterStatePrinting || printer->state == PrinterState::PrinterStatePaused)
|
||||
{
|
||||
char percentage_buffer[12];
|
||||
sprintf(percentage_buffer, "%.2f%%", printer->print_progress * 100);
|
||||
@@ -103,11 +92,10 @@ static void update_printer_percentage_text(lv_event_t * e)
|
||||
static void update_printer_control_button_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
PrinterMinimal * printer = &printer_minimal[index];
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
PrinterDataMinimal* printer = get_printer_data_minimal(config_index);
|
||||
|
||||
if (printer->power_devices > 0 && (config == get_current_printer_config() || printer->state == PRINTER_STATE_OFFLINE))
|
||||
if (printer->power_devices > 0 && (config_index == get_current_printer_index() || printer->state == PrinterState::PrinterStateOffline))
|
||||
{
|
||||
lv_label_set_text(label, "Power");
|
||||
}
|
||||
@@ -120,9 +108,10 @@ static void update_printer_control_button_text(lv_event_t * e)
|
||||
static void btn_set_secondary_button_text(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
PrinterDataMinimal* printer = get_printer_data_minimal(config_index);
|
||||
|
||||
if (config == get_current_printer_config())
|
||||
if (config_index == get_current_printer_index())
|
||||
{
|
||||
lv_label_set_text(label, LV_SYMBOL_SETTINGS);
|
||||
}
|
||||
@@ -135,11 +124,10 @@ static void btn_set_secondary_button_text(lv_event_t * e)
|
||||
static void btn_enable_control(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
PrinterMinimal * printer = &printer_minimal[index];
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
PrinterDataMinimal* printer = get_printer_data_minimal(config_index);
|
||||
|
||||
if ((config == get_current_printer_config() || printer->state == PRINTER_STATE_OFFLINE) && printer->power_devices <= 0)
|
||||
if ((config_index == get_current_printer_index() || printer->state == PrinterState::PrinterStateOffline) && printer->power_devices <= 0)
|
||||
{
|
||||
// Disable
|
||||
lv_obj_add_state(btn, LV_STATE_DISABLED);
|
||||
@@ -152,7 +140,7 @@ static void btn_enable_control(lv_event_t * e)
|
||||
}
|
||||
}
|
||||
|
||||
PRINTER_CONFIG * keyboard_config = NULL;
|
||||
PrinterConfiguration * keyboard_config = NULL;
|
||||
|
||||
static void keyboard_callback(lv_event_t * e){
|
||||
lv_obj_t * ta = lv_event_get_target(e);
|
||||
@@ -167,51 +155,50 @@ static void keyboard_callback(lv_event_t * e){
|
||||
static void btn_printer_secondary(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * btn = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
|
||||
if (config == get_current_printer_config())
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
BasePrinter* printer = get_printer(config_index);
|
||||
|
||||
if (config_index == get_current_printer_index())
|
||||
{
|
||||
nav_buttons_setup(PANEL_SETTINGS);
|
||||
return;
|
||||
}
|
||||
|
||||
config->ip_configured = false;
|
||||
write_global_config();
|
||||
|
||||
nav_buttons_setup(PANEL_PRINTER);
|
||||
global_config_delete_printer(config_index);
|
||||
}
|
||||
|
||||
static void btn_printer_rename(lv_event_t * e)
|
||||
{
|
||||
keyboard_config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
BasePrinter* printer = get_printer(config_index);
|
||||
keyboard_config = printer->printer_config;
|
||||
lv_create_keyboard_text_entry(keyboard_callback, "Rename Printer", LV_KEYBOARD_MODE_TEXT_LOWER, CYD_SCREEN_WIDTH_PX * 0.75, 24, keyboard_config->printer_name, false);
|
||||
}
|
||||
|
||||
static void btn_printer_activate(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
PrinterMinimal * printer = &printer_minimal[index];
|
||||
int config_index = (int)lv_event_get_user_data(e);
|
||||
PrinterDataMinimal* printer = get_printer_data_minimal(config_index);
|
||||
BasePrinter* printer_full = get_printer(config_index);
|
||||
|
||||
if (printer->power_devices > 0 && (config == get_current_printer_config() || printer->state == PRINTER_STATE_OFFLINE))
|
||||
if (printer->power_devices > 0 && (config_index == get_current_printer_index() || printer->state == PrinterState::PrinterStateOffline))
|
||||
{
|
||||
macros_draw_power_fullscreen(config);
|
||||
macros_draw_power_fullscreen(printer_full);
|
||||
return;
|
||||
}
|
||||
|
||||
switch_printer(index);
|
||||
set_current_printer(config_index);
|
||||
lv_msg_send(DATA_PRINTER_MINIMAL, NULL);
|
||||
}
|
||||
|
||||
static void btn_printer_add(lv_event_t * e)
|
||||
{
|
||||
set_printer_config_index(get_printer_config_free_index());
|
||||
global_config_add_new_printer();
|
||||
}
|
||||
|
||||
void create_printer_ui(PRINTER_CONFIG * config, lv_obj_t * root)
|
||||
void create_printer_ui(int index, lv_obj_t * root)
|
||||
{
|
||||
int index = config - global_config.printer_config;
|
||||
auto width = CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 2;
|
||||
|
||||
lv_obj_t * data_row_name = lv_create_empty_panel(root);
|
||||
@@ -219,16 +206,16 @@ void create_printer_ui(PRINTER_CONFIG * config, lv_obj_t * root)
|
||||
lv_obj_set_size(data_row_name, width, LV_SIZE_CONTENT);
|
||||
|
||||
lv_obj_t * label = lv_label_create(data_row_name);
|
||||
lv_obj_add_event_cb(label, update_printer_name_text, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, config);
|
||||
lv_obj_add_event_cb(label, update_printer_name_text, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, (void*)index);
|
||||
|
||||
label = lv_label_create(data_row_name);
|
||||
lv_obj_add_event_cb(label, update_printer_label_visible_active_printer, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, config);
|
||||
lv_obj_add_event_cb(label, update_printer_label_visible_active_printer, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, (void*)index);
|
||||
|
||||
label = lv_label_create(data_row_name);
|
||||
lv_obj_add_event_cb(label, update_printer_status_text, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, config);
|
||||
lv_obj_add_event_cb(label, update_printer_status_text, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, (void*)index);
|
||||
|
||||
lv_obj_t * progress_row = lv_create_empty_panel(root);
|
||||
lv_layout_flex_row(progress_row);
|
||||
@@ -236,13 +223,13 @@ void create_printer_ui(PRINTER_CONFIG * config, lv_obj_t * root)
|
||||
|
||||
lv_obj_t * progress_bar = lv_bar_create(progress_row);
|
||||
lv_obj_set_flex_grow(progress_bar, 1);
|
||||
lv_obj_add_event_cb(progress_bar, update_printer_percentage_bar, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, progress_bar, config);
|
||||
lv_obj_add_event_cb(progress_bar, update_printer_percentage_bar, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, progress_bar, (void*)index);
|
||||
|
||||
label = lv_label_create(progress_row);
|
||||
lv_obj_set_style_text_font(label, &CYD_SCREEN_FONT_SMALL, 0);
|
||||
lv_obj_add_event_cb(label, update_printer_percentage_text, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, config);
|
||||
lv_obj_add_event_cb(label, update_printer_percentage_text, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, (void*)index);
|
||||
|
||||
lv_obj_t * button_row = lv_create_empty_panel(root);
|
||||
lv_layout_flex_row(button_row);
|
||||
@@ -250,16 +237,16 @@ void create_printer_ui(PRINTER_CONFIG * config, lv_obj_t * root)
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(button_row);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_add_event_cb(btn, btn_printer_secondary, LV_EVENT_CLICKED, config);
|
||||
lv_obj_add_event_cb(btn, btn_printer_secondary, LV_EVENT_CLICKED, (void*)index);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_obj_center(label);
|
||||
lv_obj_add_event_cb(label, btn_set_secondary_button_text, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, config);
|
||||
lv_obj_add_event_cb(label, btn_set_secondary_button_text, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, (void*)index);
|
||||
|
||||
btn = lv_btn_create(button_row);
|
||||
lv_obj_set_flex_grow(btn, 2);
|
||||
lv_obj_add_event_cb(btn, btn_printer_rename, LV_EVENT_CLICKED, config);
|
||||
lv_obj_add_event_cb(btn, btn_printer_rename, LV_EVENT_CLICKED, (void*)index);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "Rename");
|
||||
@@ -267,14 +254,14 @@ void create_printer_ui(PRINTER_CONFIG * config, lv_obj_t * root)
|
||||
|
||||
btn = lv_btn_create(button_row);
|
||||
lv_obj_set_flex_grow(btn, 2);
|
||||
lv_obj_add_event_cb(btn, btn_printer_activate, LV_EVENT_CLICKED, config);
|
||||
lv_obj_add_event_cb(btn, btn_enable_control, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, btn, config);
|
||||
lv_obj_add_event_cb(btn, btn_printer_activate, LV_EVENT_CLICKED, (void*)index);
|
||||
lv_obj_add_event_cb(btn, btn_enable_control, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, btn, (void*)index);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_obj_center(label);
|
||||
lv_obj_add_event_cb(label, update_printer_control_button_text, LV_EVENT_MSG_RECEIVED, config);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, config);
|
||||
lv_obj_add_event_cb(label, update_printer_control_button_text, LV_EVENT_MSG_RECEIVED, (void*)index);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_MINIMAL, label, (void*)index);
|
||||
|
||||
lv_obj_t * line = lv_line_create(root);
|
||||
lv_line_set_points(line, line_points, 2);
|
||||
@@ -292,15 +279,12 @@ void printer_panel_init(lv_obj_t* panel)
|
||||
|
||||
lv_obj_set_size(lv_create_empty_panel(inner_panel), 0, 0);
|
||||
|
||||
for (int i = 0; i < PRINTER_CONFIG_COUNT; i++){
|
||||
PRINTER_CONFIG * config = &global_config.printer_config[i];
|
||||
if (config->ip_configured) {
|
||||
create_printer_ui(&global_config.printer_config[i], inner_panel);
|
||||
}
|
||||
for (int i = 0; i < get_printer_count(); i++){
|
||||
create_printer_ui(i, inner_panel);
|
||||
}
|
||||
|
||||
// Add Printer Button
|
||||
if (get_printer_config_free_index() != -1){
|
||||
if (get_printer_count() < PRINTER_CONFIG_COUNT){
|
||||
lv_obj_t * btn = lv_btn_create(inner_panel);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, btn_printer_add, LV_EVENT_CLICKED, NULL);
|
||||
@@ -311,6 +295,5 @@ void printer_panel_init(lv_obj_t* panel)
|
||||
}
|
||||
|
||||
lv_obj_set_size(lv_create_empty_panel(inner_panel), 0, 0);
|
||||
|
||||
lv_msg_send(DATA_PRINTER_MINIMAL, NULL);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "panel.h"
|
||||
#include "../../core/data_setup.h"
|
||||
#include <stdio.h>
|
||||
#include "../ui_utils.h"
|
||||
#include "../../core/printer_integration.hpp"
|
||||
#include "../../core/current_printer.h"
|
||||
|
||||
char time_buffer[12];
|
||||
|
||||
@@ -15,35 +16,35 @@ char* time_display(unsigned long time){
|
||||
|
||||
static void progress_bar_update(lv_event_t* e){
|
||||
lv_obj_t * bar = lv_event_get_target(e);
|
||||
lv_bar_set_value(bar, printer.print_progress * 100, LV_ANIM_ON);
|
||||
lv_bar_set_value(bar, get_current_printer_data()->print_progress * 100, LV_ANIM_ON);
|
||||
}
|
||||
|
||||
static void update_printer_data_elapsed_time(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_label_set_text(label, time_display(printer.elapsed_time_s));
|
||||
lv_label_set_text(label, time_display(get_current_printer_data()->elapsed_time_s));
|
||||
}
|
||||
|
||||
static void update_printer_data_remaining_time(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
lv_label_set_text(label, time_display(printer.remaining_time_s));
|
||||
lv_label_set_text(label, time_display(get_current_printer_data()->remaining_time_s));
|
||||
}
|
||||
|
||||
static void update_printer_data_stats(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char buff[256] = {0};
|
||||
|
||||
switch (get_current_printer_config()->show_stats_on_progress_panel)
|
||||
switch (get_current_printer()->printer_config->show_stats_on_progress_panel)
|
||||
{
|
||||
case SHOW_STATS_ON_PROGRESS_PANEL_LAYER:
|
||||
sprintf(buff, "Layer %d of %d", printer.current_layer, printer.total_layers);
|
||||
sprintf(buff, "Layer %d of %d", get_current_printer_data()->current_layer, get_current_printer_data()->total_layers);
|
||||
break;
|
||||
case SHOW_STATS_ON_PROGRESS_PANEL_PARTIAL:
|
||||
sprintf(buff, "Position: X%.2f Y%.2f\nFeedrate: %d mm/s\nFilament Used: %.2f m\nLayer %d of %d",
|
||||
printer.position[0], printer.position[1], printer.feedrate_mm_per_s, printer.filament_used_mm / 1000, printer.current_layer, printer.total_layers);
|
||||
get_current_printer_data()->position[0], get_current_printer_data()->position[1], get_current_printer_data()->feedrate_mm_per_s, get_current_printer_data()->filament_used_mm / 1000, get_current_printer_data()->current_layer, get_current_printer_data()->total_layers);
|
||||
break;
|
||||
case SHOW_STATS_ON_PROGRESS_PANEL_ALL:
|
||||
sprintf(buff, "Pressure Advance: %.3f (%.2fs)\nPosition: X%.2f Y%.2f Z%.2f\nFeedrate: %d mm/s\nFilament Used: %.2f m\nFan: %.0f%%\nSpeed: %.0f%%\nFlow: %.0f%%\nLayer %d of %d",
|
||||
printer.pressure_advance, printer.smooth_time, printer.position[0], printer.position[1], printer.position[2], printer.feedrate_mm_per_s, printer.filament_used_mm / 1000, printer.fan_speed * 100, printer.speed_mult * 100, printer.extrude_mult * 100, printer.current_layer, printer.total_layers);
|
||||
get_current_printer_data()->pressure_advance, get_current_printer_data()->smooth_time, get_current_printer_data()->position[0], get_current_printer_data()->position[1], get_current_printer_data()->position[2], get_current_printer_data()->feedrate_mm_per_s, get_current_printer_data()->filament_used_mm / 1000, get_current_printer_data()->fan_speed * 100, get_current_printer_data()->speed_mult * 100, get_current_printer_data()->extrude_mult * 100, get_current_printer_data()->current_layer, get_current_printer_data()->total_layers);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -53,53 +54,63 @@ static void update_printer_data_stats(lv_event_t * e){
|
||||
static void update_printer_data_percentage(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char percentage_buffer[12];
|
||||
sprintf(percentage_buffer, "%.2f%%", printer.print_progress * 100);
|
||||
sprintf(percentage_buffer, "%.2f%%", get_current_printer_data()->print_progress * 100);
|
||||
lv_label_set_text(label, percentage_buffer);
|
||||
}
|
||||
|
||||
static void btn_click_stop(lv_event_t * e){
|
||||
send_gcode(true, "CANCEL_PRINT");
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureStop);
|
||||
}
|
||||
|
||||
static void btn_click_pause(lv_event_t * e){
|
||||
send_gcode(true, "PAUSE");
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeaturePause);
|
||||
}
|
||||
|
||||
static void btn_click_resume(lv_event_t * e){
|
||||
send_gcode(true, "RESUME");
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureResume);
|
||||
}
|
||||
|
||||
static void btn_click_estop(lv_event_t * e){
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureEmergencyStop);
|
||||
}
|
||||
|
||||
void progress_panel_init(lv_obj_t* panel){
|
||||
auto panel_width = CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 3;
|
||||
const auto button_size_mult = 1.3f;
|
||||
|
||||
// Emergency Stop
|
||||
if (global_config.show_estop && (get_current_printer()->supports_feature(PrinterFeatureEmergencyStop))){
|
||||
lv_obj_t * btn = lv_btn_create(panel);
|
||||
lv_obj_add_event_cb(btn, btn_click_estop, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_set_height(btn, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, CYD_SCREEN_GAP_PX);
|
||||
lv_obj_set_style_bg_color(btn, lv_color_hex(0xFF0000), LV_PART_MAIN);
|
||||
|
||||
lv_obj_t * label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_POWER " EMERGENCY STOP");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
lv_obj_t * center_panel = lv_create_empty_panel(panel);
|
||||
lv_obj_set_size(center_panel, panel_width, LV_SIZE_CONTENT);
|
||||
lv_layout_flex_column(center_panel);
|
||||
|
||||
if (get_current_printer_config()->show_stats_on_progress_panel == SHOW_STATS_ON_PROGRESS_PANEL_ALL)
|
||||
// Only align progress bar to top mid if necessary to make room for all extras
|
||||
if (get_current_printer()->printer_config->show_stats_on_progress_panel == SHOW_STATS_ON_PROGRESS_PANEL_ALL && CYD_SCREEN_HEIGHT_PX <= 320)
|
||||
{
|
||||
lv_obj_align(center_panel, LV_ALIGN_TOP_MID, 0, CYD_SCREEN_GAP_PX);
|
||||
lv_obj_align(center_panel, LV_ALIGN_TOP_MID, 0, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX+(3 * CYD_SCREEN_GAP_PX));
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_obj_align(center_panel, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
if (get_current_printer_config()->show_stats_on_progress_panel == SHOW_STATS_ON_PROGRESS_PANEL_LAYER)
|
||||
{
|
||||
lv_obj_t * label = lv_label_create(panel);
|
||||
lv_obj_align(label, LV_ALIGN_TOP_MID, 0, CYD_SCREEN_GAP_PX);
|
||||
lv_obj_set_style_text_font(label, &CYD_SCREEN_FONT_SMALL, 0);
|
||||
lv_obj_add_event_cb(label, update_printer_data_stats, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
lv_msg_subsribe_obj(DATA_PRINTER_DATA, label, NULL);
|
||||
}
|
||||
|
||||
// Filename
|
||||
lv_obj_t * label = lv_label_create(center_panel);
|
||||
lv_label_set_text(label, printer.print_filename);
|
||||
lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_label_set_text(label, get_current_printer_data()->print_filename);
|
||||
if (global_config.full_filenames) lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
|
||||
else lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||
lv_obj_set_width(label, panel_width);
|
||||
|
||||
// Progress Bar
|
||||
@@ -144,7 +155,7 @@ void progress_panel_init(lv_obj_t* panel){
|
||||
lv_obj_center(label);
|
||||
|
||||
// Resume Button
|
||||
if (printer.state == PRINTER_STATE_PAUSED){
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePaused){
|
||||
btn = lv_btn_create(panel);
|
||||
lv_obj_add_event_cb(btn, btn_click_resume, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
@@ -165,7 +176,7 @@ void progress_panel_init(lv_obj_t* panel){
|
||||
lv_obj_align(btn, LV_ALIGN_BOTTOM_RIGHT, -2 * CYD_SCREEN_GAP_PX - CYD_SCREEN_MIN_BUTTON_WIDTH_PX * button_size_mult, -1 * CYD_SCREEN_GAP_PX);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_MIN_BUTTON_WIDTH_PX * button_size_mult, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX * button_size_mult);
|
||||
|
||||
if (get_current_printer_config()->show_stats_on_progress_panel >= SHOW_STATS_ON_PROGRESS_PANEL_PARTIAL)
|
||||
if (get_current_printer()->printer_config->show_stats_on_progress_panel > SHOW_STATS_ON_PROGRESS_PANEL_NONE)
|
||||
{
|
||||
label = lv_label_create(panel);
|
||||
lv_obj_align(label, LV_ALIGN_BOTTOM_LEFT, CYD_SCREEN_GAP_PX, -1 * CYD_SCREEN_GAP_PX);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "../../core/lv_setup.h"
|
||||
#include "../ota_setup.h"
|
||||
#include "../nav_buttons.h"
|
||||
#include "../../core/printer_integration.hpp"
|
||||
|
||||
#ifndef REPO_VERSION
|
||||
#define REPO_VERSION "Unknown"
|
||||
@@ -16,7 +17,7 @@
|
||||
static void invert_color_switch(lv_event_t * e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
get_current_printer_config()->invert_colors = checked;
|
||||
global_config.printer_config[global_config.printer_index].invert_colors = checked;
|
||||
write_global_config();
|
||||
set_invert_display();
|
||||
}
|
||||
@@ -33,13 +34,13 @@ static void reset_click(lv_event_t * e){
|
||||
|
||||
static void reset_wifi_click(lv_event_t * e){
|
||||
global_config.wifi_configured = false;
|
||||
global_config.wifi_configuration_skipped = false;
|
||||
write_global_config();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
static void reset_ip_click(lv_event_t * e){
|
||||
get_current_printer_config()->ip_configured = false;
|
||||
get_current_printer_config()->auth_configured = false;
|
||||
get_current_printer()->printer_config->setup_complete = false;
|
||||
write_global_config();
|
||||
ESP.restart();
|
||||
}
|
||||
@@ -47,7 +48,7 @@ static void reset_ip_click(lv_event_t * e){
|
||||
static void light_mode_switch(lv_event_t * e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
get_current_printer_config()->light_mode = checked;
|
||||
get_current_printer()->printer_config->light_mode = checked;
|
||||
write_global_config();
|
||||
set_color_scheme();
|
||||
}
|
||||
@@ -55,20 +56,20 @@ static void light_mode_switch(lv_event_t * e){
|
||||
static void filament_move_mode_switch(lv_event_t * e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
get_current_printer_config()->custom_filament_move_macros = checked;
|
||||
get_current_printer()->printer_config->custom_filament_move_macros = checked;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void show_stats_on_progress_panel_dropdown(lv_event_t * e){
|
||||
auto selected = lv_dropdown_get_selected(lv_event_get_target(e));
|
||||
get_current_printer_config()->show_stats_on_progress_panel = selected;
|
||||
get_current_printer()->printer_config->show_stats_on_progress_panel = selected;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void theme_dropdown(lv_event_t * e){
|
||||
lv_obj_t * dropdown = lv_event_get_target(e);
|
||||
auto selected = lv_dropdown_get_selected(dropdown);
|
||||
get_current_printer_config()->color_scheme = selected;
|
||||
get_current_printer()->printer_config->color_scheme = selected;
|
||||
set_color_scheme();
|
||||
write_global_config();
|
||||
}
|
||||
@@ -110,6 +111,34 @@ static void disable_m117_messaging_switch(lv_event_t* e){
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void sort_macros_switch(lv_event_t* e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
global_config.sort_macros = checked;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void show_estop_switch(lv_event_t* e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
global_config.show_estop = checked;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void full_filenames_switch(lv_event_t* e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
global_config.full_filenames = checked;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void double_size_gcode_img_switch(lv_event_t* e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
global_config.double_size_gcode_img = checked;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void rotate_screen_switch(lv_event_t* e){
|
||||
auto state = lv_obj_get_state(lv_event_get_target(e));
|
||||
bool checked = (state & LV_STATE_CHECKED == LV_STATE_CHECKED);
|
||||
@@ -150,7 +179,7 @@ const char* estimated_time_options = "Percentage\nInterpolated\nSlicer";
|
||||
|
||||
static void estimated_time_dropdown(lv_event_t * e){
|
||||
lv_obj_t * dropdown = lv_event_get_target(e);
|
||||
get_current_printer_config()->remaining_time_calc_mode = lv_dropdown_get_selected(dropdown);
|
||||
get_current_printer()->printer_config->remaining_time_calc_mode = lv_dropdown_get_selected(dropdown);
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
@@ -161,28 +190,29 @@ void settings_section_theming(lv_obj_t* panel)
|
||||
lv_obj_t * label = lv_label_create(panel);
|
||||
lv_label_set_text(label, "Theming");
|
||||
|
||||
lv_create_custom_menu_dropdown("Theme", panel, theme_dropdown, "Blue\nGreen\nLime\nGrey\nYellow\nOrange\nRed\nPurple", get_current_printer_config()->color_scheme, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
|
||||
#ifndef CYD_SCREEN_DISABLE_INVERT_COLORS
|
||||
lv_create_custom_menu_switch("Invert Colors", panel, invert_color_switch, get_current_printer_config()->invert_colors, NULL, (global_config.multi_printer_mode) ? "Stored per printer"
|
||||
#ifdef CYD_SCREEN_DRIVER_ESP32_2432S028R
|
||||
"\nIntended for the 2.8\" dual USB model screen" : "Intended for the 2.8\" dual USB model screen"
|
||||
#else
|
||||
: NULL
|
||||
#endif
|
||||
);
|
||||
#endif // CYD_SCREEN_DISABLE_INVERT_COLORS
|
||||
|
||||
lv_create_custom_menu_switch("Light Mode", panel, light_mode_switch, get_current_printer_config()->light_mode, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
lv_create_custom_menu_dropdown("Theme", panel, theme_dropdown, "Blue\nGreen\nLime\nGrey\nYellow\nOrange\nRed\nPurple", get_current_printer()->printer_config->color_scheme, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
lv_create_custom_menu_switch("Light Mode", panel, light_mode_switch, get_current_printer()->printer_config->light_mode, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
}
|
||||
|
||||
void settings_section_behaviour(lv_obj_t* panel)
|
||||
{
|
||||
PrinterType printer_type = get_current_printer()->printer_config->printer_type;
|
||||
bool is_klipper = printer_type == PrinterTypeKlipper || printer_type == PrinterTypeKlipperSerial;
|
||||
bool is_octo = printer_type == PrinterTypeOctoprint;
|
||||
bool is_bambu = printer_type == PrinterTypeBambuLocal;
|
||||
|
||||
lv_obj_t * label = lv_label_create(panel);
|
||||
lv_label_set_text(label, "\nBehaviour");
|
||||
|
||||
lv_create_custom_menu_dropdown("Estimated Time", panel, estimated_time_dropdown, estimated_time_options, get_current_printer_config()->remaining_time_calc_mode, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
lv_create_custom_menu_dropdown("Stats in Progress Screen", panel, show_stats_on_progress_panel_dropdown, "None\nLayers\nPartial\nAll", get_current_printer_config()->show_stats_on_progress_panel, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
if (is_klipper)
|
||||
{
|
||||
lv_create_custom_menu_dropdown("Estimated Time", panel, estimated_time_dropdown, estimated_time_options, get_current_printer()->printer_config->remaining_time_calc_mode, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
lv_create_custom_menu_dropdown("Stats in Progress Screen", panel, show_stats_on_progress_panel_dropdown, "None\nLayers\nPartial\nAll", get_current_printer()->printer_config->show_stats_on_progress_panel, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
}
|
||||
else if (is_bambu)
|
||||
{
|
||||
lv_create_custom_menu_dropdown("Stats in Progress Screen", panel, show_stats_on_progress_panel_dropdown, "None\nLayers", get_current_printer()->printer_config->show_stats_on_progress_panel, NULL, PRINTER_SPECIFIC_SETTING);
|
||||
}
|
||||
|
||||
#ifndef CYD_SCREEN_DISABLE_TIMEOUT
|
||||
int wake_timeout_settings_index = 0;
|
||||
@@ -201,13 +231,23 @@ void settings_section_behaviour(lv_obj_t* panel)
|
||||
#endif
|
||||
|
||||
lv_create_custom_menu_switch("Multi Printer Mode", panel, multi_printer_switch, global_config.multi_printer_mode);
|
||||
lv_create_custom_menu_switch("Disable M117 Messaging", panel, disable_m117_messaging_switch, global_config.disable_m117_messaging);
|
||||
lv_create_custom_menu_button("Configure Printer IP", panel, reset_ip_click, "Restart");
|
||||
|
||||
if (is_klipper)
|
||||
{
|
||||
lv_create_custom_menu_switch("Disable M117 Messaging", panel, disable_m117_messaging_switch, global_config.disable_m117_messaging);
|
||||
|
||||
lv_create_custom_menu_switch("Custom Filament Move Macros", panel, filament_move_mode_switch, get_current_printer_config()->custom_filament_move_macros, NULL,
|
||||
global_config.multi_printer_mode
|
||||
? "Calls FILAMENT_RETRACT and\nFILAMENT_EXTRUDE in temperature menu\nwhen enabled. Stored per printer."
|
||||
: "Calls FILAMENT_RETRACT and\nFILAMENT_EXTRUDE in temperature menu\nwhen enabled");
|
||||
lv_create_custom_menu_switch("Custom Filament Move Macros", panel, filament_move_mode_switch, get_current_printer()->printer_config->custom_filament_move_macros, NULL,
|
||||
global_config.multi_printer_mode
|
||||
? "Calls FILAMENT_RETRACT and\nFILAMENT_EXTRUDE in temperature menu\nwhen enabled. Stored per printer."
|
||||
: "Calls FILAMENT_RETRACT and\nFILAMENT_EXTRUDE in temperature menu\nwhen enabled");
|
||||
|
||||
lv_create_custom_menu_switch("Show Emergency Stop", panel, show_estop_switch, global_config.show_estop);
|
||||
}
|
||||
|
||||
lv_create_custom_menu_switch("Sort Macros A->Z", panel, sort_macros_switch, global_config.sort_macros);
|
||||
lv_create_custom_menu_switch("Show Full Filenames", panel, full_filenames_switch, global_config.full_filenames);
|
||||
lv_create_custom_menu_switch("2X Size Gcode Image", panel, double_size_gcode_img_switch, global_config.double_size_gcode_img);
|
||||
lv_create_custom_menu_button("Configure Printer Host", panel, reset_ip_click, "Restart");
|
||||
}
|
||||
|
||||
void settings_section_device(lv_obj_t* panel)
|
||||
@@ -225,6 +265,16 @@ void settings_section_device(lv_obj_t* panel)
|
||||
|
||||
lv_create_custom_menu_dropdown("Brightness", panel, brightness_dropdown, brightness_options, brightness_settings_index);
|
||||
|
||||
#ifndef CYD_SCREEN_DISABLE_INVERT_COLORS
|
||||
lv_create_custom_menu_switch("Invert Colors", panel, invert_color_switch, global_config.printer_config[global_config.printer_index].invert_colors, NULL, (global_config.multi_printer_mode) ? "Stored per printer"
|
||||
#ifdef CYD_SCREEN_DRIVER_ESP32_2432S028R
|
||||
"\nIntended for the 2.8\" dual USB model screen" : "Intended for the 2.8\" dual USB model screen"
|
||||
#else
|
||||
: NULL
|
||||
#endif
|
||||
);
|
||||
#endif // CYD_SCREEN_DISABLE_INVERT_COLORS
|
||||
|
||||
#ifdef CYD_SCREEN_DRIVER_ESP32_2432S028R
|
||||
lv_create_custom_menu_switch("Screen Color Fix", panel, dualusb_screen_fix_switch, global_config.display_mode, NULL, "ONLY for the 2.8\" dual USB model screen");
|
||||
#endif
|
||||
|
||||
@@ -1,172 +1,23 @@
|
||||
#include "panel.h"
|
||||
#include "../ui_utils.h"
|
||||
#include "../../core/data_setup.h"
|
||||
#include "../nav_buttons.h"
|
||||
#include <stdio.h>
|
||||
#include <Esp.h>
|
||||
#include "../../core/printer_integration.hpp"
|
||||
|
||||
static void set_fan_speed_text(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[64];
|
||||
sprintf(data, "Fan: %.0f%%", printer.fan_speed * 100);
|
||||
lv_label_set_text(label, data);
|
||||
static void swap_to_files_menu(lv_event_t * e) {
|
||||
nav_buttons_setup(PANEL_FILES);
|
||||
}
|
||||
|
||||
static void set_fan_speed(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
char gcode[64];
|
||||
sprintf(gcode, "M106 S%d", speed);
|
||||
send_gcode(true, gcode);
|
||||
}
|
||||
|
||||
const char* fan_speeds[] = { "0%", "15%", "25%", "35%" };
|
||||
const int fan_speeds_values[] = { 0, 38, 64, 90 };
|
||||
|
||||
const char* fan_speeds_2[] = { "50%", "75%", "100%"};
|
||||
const int fan_speeds_values_2[] = { 128, 192, 255 };
|
||||
|
||||
lv_button_column_t fan_speed_columns[] = {
|
||||
{ set_fan_speed, fan_speeds, (const void**)fan_speeds_values, 4},
|
||||
{ set_fan_speed, fan_speeds_2, (const void**)fan_speeds_values_2, 3}
|
||||
};
|
||||
|
||||
static void set_zoffset_text(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[64];
|
||||
sprintf(data, "Z Offset: %.03f", printer.gcode_offset[2]);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_zoffset_text_ex(lv_event_t * e) {
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[64];
|
||||
sprintf(data, "Z Offset: %.03f, Z: %.03f", printer.gcode_offset[2], printer.position[2]);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_zoffset(lv_event_t * e){
|
||||
char* offset = (char*)lv_event_get_user_data(e);
|
||||
|
||||
char gcode[64];
|
||||
sprintf(gcode, "SET_GCODE_OFFSET Z_ADJUST=%s MOVE=1", offset);
|
||||
send_gcode(true, gcode);
|
||||
}
|
||||
|
||||
static void set_z(lv_event_t * e){
|
||||
void* ptr = lv_event_get_user_data(e);
|
||||
float value = *(float *)(&ptr);
|
||||
|
||||
if (value < 0) {
|
||||
send_gcode(true, "SET_GCODE_OFFSET Z=0 MOVE=1");
|
||||
return;
|
||||
}
|
||||
|
||||
move_printer("Z", value, false);
|
||||
}
|
||||
|
||||
const char* zoffsets[] = { "-0.01", "-0.025", "-0.05", "-0.2" };
|
||||
const char* zoffsets_2[] = { "+0.01", "+0.025", "+0.05", "+0.2" };
|
||||
const char* zabs[] = { "Z=0", "Z=0.1", "Z=1", "Clear" };
|
||||
const float zabsvalues[] = { 0, 0.1f, 1.0f, -1.0f };
|
||||
|
||||
lv_button_column_t zoffset_columns[] = {
|
||||
{ set_zoffset, zoffsets, (const void**)zoffsets, 4},
|
||||
{ set_zoffset, zoffsets_2, (const void**)zoffsets_2, 4},
|
||||
{ set_z, zabs, (const void**)zabsvalues, 4}
|
||||
};
|
||||
|
||||
static void set_speed_mult_text(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[64];
|
||||
sprintf(data, "Speed: %.0f%%", printer.speed_mult * 100);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_speed_mult(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
char gcode[64];
|
||||
sprintf(gcode, "M220 S%d", speed);
|
||||
send_gcode(true, gcode);
|
||||
}
|
||||
|
||||
static void set_speed_mult_offset(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
float result = printer.speed_mult * 100 + speed;
|
||||
printer.speed_mult = result / 100;
|
||||
char gcode[64];
|
||||
sprintf(gcode, "M220 S%.0f", result);
|
||||
send_gcode(true, gcode);
|
||||
}
|
||||
|
||||
const char* speed_presets[] = { "50%", "100%", "150%", "200%" };
|
||||
const int speed_presets_values[] = { 50, 100, 150, 200 };
|
||||
const char* speed_presets_minus[] = { "-1%", "-5%", "-10%", "-25%" };
|
||||
const int speed_presets_minus_values[] = { -1, -5, -10, -25 };
|
||||
const char* speed_presets_plus[] = { "+1%", "+5%", "+10%", "+25%" };
|
||||
const int speed_presets_plus_values[] = { 1, 5, 10, 25 };
|
||||
|
||||
lv_button_column_t speed_mult_columns[] = {
|
||||
{ set_speed_mult, speed_presets, (const void**)speed_presets_values, 4},
|
||||
{ set_speed_mult_offset, speed_presets_minus, (const void**)speed_presets_minus_values, 4},
|
||||
{ set_speed_mult_offset, speed_presets_plus, (const void**)speed_presets_plus_values, 4}
|
||||
};
|
||||
|
||||
static void set_extrude_mult_text(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char data[64];
|
||||
sprintf(data, "Flow: %.0f%%", printer.extrude_mult * 100);
|
||||
lv_label_set_text(label, data);
|
||||
}
|
||||
|
||||
static void set_extrude_mult(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
char gcode[64];
|
||||
sprintf(gcode, "M221 S%d", speed);
|
||||
send_gcode(true, gcode);
|
||||
}
|
||||
|
||||
static void set_extrude_mult_offset(lv_event_t * e){
|
||||
int speed = (int)lv_event_get_user_data(e);
|
||||
float result = printer.extrude_mult * 100 + speed;
|
||||
printer.extrude_mult = result / 100;
|
||||
char gcode[64];
|
||||
sprintf(gcode, "M221 S%.0f", result);
|
||||
send_gcode(true, gcode);
|
||||
}
|
||||
|
||||
const char* extrude_presets[] = { "95%", "100%", "105%", "110%" };
|
||||
const int extrude_presets_values[] = { 95, 100, 105, 110 };
|
||||
const char* extrude_offset[] = { "+5%", "+1%", "-1%", "-5%" };
|
||||
const int extrude_offset_values[] = { 5, 1, -1, -5 };
|
||||
|
||||
lv_button_column_t extrude_mult_columns[] = {
|
||||
{ set_extrude_mult, extrude_presets, (const void**)extrude_presets_values, 4},
|
||||
{ set_extrude_mult_offset, extrude_offset, (const void**)extrude_offset_values, 4}
|
||||
};
|
||||
|
||||
static void open_fan_speed_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_fan_speed_text, fan_speed_columns, 2);
|
||||
lv_msg_send(DATA_PRINTER_DATA, &printer);
|
||||
}
|
||||
|
||||
static void open_zoffset_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_zoffset_text_ex, zoffset_columns, (printer.state == PRINTER_STATE_IDLE) ? 3 : 2);
|
||||
lv_msg_send(DATA_PRINTER_DATA, &printer);
|
||||
}
|
||||
|
||||
static void open_speed_mult_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_speed_mult_text, speed_mult_columns, 3);
|
||||
lv_msg_send(DATA_PRINTER_DATA, &printer);
|
||||
}
|
||||
|
||||
static void open_extrude_mult_panel(lv_event_t * e){
|
||||
lv_create_fullscreen_button_matrix_popup(lv_scr_act(), set_extrude_mult_text, extrude_mult_columns, 2);
|
||||
lv_msg_send(DATA_PRINTER_DATA, &printer);
|
||||
static void update_data(lv_event_t * e) {
|
||||
lv_msg_send(DATA_PRINTER_DATA, get_current_printer());
|
||||
}
|
||||
|
||||
void create_state_button(lv_obj_t * root, lv_event_cb_t label, lv_event_cb_t button){
|
||||
lv_obj_t * btn = lv_btn_create(root);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_PANEL_WIDTH_PX / 2 - CYD_SCREEN_GAP_PX * 3, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, button, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_add_event_cb(btn, update_data, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label_obj = lv_label_create(btn);
|
||||
lv_obj_add_event_cb(label_obj, label, LV_EVENT_MSG_RECEIVED, NULL);
|
||||
@@ -177,35 +28,35 @@ void create_state_button(lv_obj_t * root, lv_event_cb_t label, lv_event_cb_t but
|
||||
static void label_pos(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char x_pos_buff[32];
|
||||
sprintf(x_pos_buff, "X%.2f Y%.2f", printer.position[0], printer.position[1]);
|
||||
sprintf(x_pos_buff, "X%.2f Y%.2f", get_current_printer_data()->position[0], get_current_printer_data()->position[1]);
|
||||
lv_label_set_text(label, x_pos_buff);
|
||||
}
|
||||
|
||||
static void label_filament_used_m(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char filament_buff[32];
|
||||
sprintf(filament_buff, "%.2f m", printer.filament_used_mm / 1000);
|
||||
sprintf(filament_buff, "%.2f m", get_current_printer_data()->filament_used_mm / 1000);
|
||||
lv_label_set_text(label, filament_buff);
|
||||
}
|
||||
|
||||
static void label_total_layers(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char layers_buff[32];
|
||||
sprintf(layers_buff, "%d of %d", printer.current_layer, printer.total_layers);
|
||||
sprintf(layers_buff, "%d of %d", get_current_printer_data()->current_layer, get_current_printer_data()->total_layers);
|
||||
lv_label_set_text(label, layers_buff);
|
||||
}
|
||||
|
||||
static void label_pressure_advance(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char pressure_buff[32];
|
||||
sprintf(pressure_buff, "%.3f (%.2fs)", printer.pressure_advance, printer.smooth_time);
|
||||
sprintf(pressure_buff, "%.3f (%.2fs)", get_current_printer_data()->pressure_advance, get_current_printer_data()->smooth_time);
|
||||
lv_label_set_text(label, pressure_buff);
|
||||
}
|
||||
|
||||
static void label_feedrate(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
char feedrate_buff[32];
|
||||
sprintf(feedrate_buff, "%d mm/s", printer.feedrate_mm_per_s);
|
||||
sprintf(feedrate_buff, "%d mm/s", get_current_printer_data()->feedrate_mm_per_s);
|
||||
lv_label_set_text(label, feedrate_buff);
|
||||
}
|
||||
|
||||
@@ -236,7 +87,7 @@ void stats_panel_init(lv_obj_t* panel) {
|
||||
|
||||
create_stat_text_block(left_panel, "Position:", label_pos);
|
||||
|
||||
if (printer.state != PRINTER_STATE_IDLE){
|
||||
if (get_current_printer_data()->state != PrinterState::PrinterStateIdle){
|
||||
create_stat_text_block(left_panel, "Filament Used:", label_filament_used_m);
|
||||
create_stat_text_block(left_panel, "Layer:", label_total_layers);
|
||||
}
|
||||
@@ -248,9 +99,20 @@ void stats_panel_init(lv_obj_t* panel) {
|
||||
lv_obj_set_size(right_panel, panel_width, CYD_SCREEN_PANEL_HEIGHT_PX - CYD_SCREEN_GAP_PX * 2);
|
||||
lv_layout_flex_column(right_panel, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_align(right_panel, LV_ALIGN_TOP_RIGHT, -1 * CYD_SCREEN_GAP_PX, CYD_SCREEN_GAP_PX);
|
||||
|
||||
create_state_button(right_panel, set_fan_speed_text, open_fan_speed_panel);
|
||||
create_state_button(right_panel, set_zoffset_text, open_zoffset_panel);
|
||||
create_state_button(right_panel, set_speed_mult_text, open_speed_mult_panel);
|
||||
create_state_button(right_panel, set_extrude_mult_text, open_extrude_mult_panel);
|
||||
|
||||
if (get_current_printer_data()->state >= PrinterState::PrinterStatePrinting){
|
||||
lv_obj_t * btn = lv_btn_create(right_panel);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_PANEL_WIDTH_PX / 2 - CYD_SCREEN_GAP_PX * 3, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, swap_to_files_menu, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "Files");
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
BasePrinter* printer = get_current_printer();
|
||||
for (int i = 0; i < printer->custom_menus_count; i++)
|
||||
{
|
||||
create_state_button(right_panel, (lv_event_cb_t)printer->custom_menus[i].set_label, (lv_event_cb_t)printer->custom_menus[i].open_panel);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "lvgl.h"
|
||||
#include "../../core/data_setup.h"
|
||||
#include "../../conf/global_config.h"
|
||||
#include <HardwareSerial.h>
|
||||
#include "../ui_utils.h"
|
||||
#include "../../core/printer_integration.hpp"
|
||||
#include "../../core/current_printer.h"
|
||||
|
||||
enum temp_target{
|
||||
TARGET_HOTEND,
|
||||
@@ -16,37 +17,43 @@ enum temp_target{
|
||||
};
|
||||
|
||||
static temp_target keyboard_target;
|
||||
static char hotend_buff[40];
|
||||
static char bed_buff[40];
|
||||
|
||||
|
||||
static bool temp_edit_mode = false;
|
||||
lv_obj_t* root_panel;
|
||||
|
||||
static void update_printer_data_hotend_temp(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
sprintf(hotend_buff, "Hotend: %.0f C (Target: %.0f C)", printer.extruder_temp, printer.extruder_target_temp);
|
||||
char hotend_buff[40];
|
||||
sprintf(hotend_buff, "Hotend: %.0f C (Target: %.0f C)",
|
||||
get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexNozzle1],
|
||||
get_current_printer_data()->target_temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexNozzle1]);
|
||||
lv_label_set_text(label, hotend_buff);
|
||||
}
|
||||
|
||||
static void update_printer_data_bed_temp(lv_event_t * e){
|
||||
lv_obj_t * label = lv_event_get_target(e);
|
||||
sprintf(bed_buff, "Bed: %.0f C (Target: %.0f C)", printer.bed_temp, printer.bed_target_temp);
|
||||
char bed_buff[40];
|
||||
sprintf(bed_buff, "Bed: %.0f C (Target: %.0f C)",
|
||||
get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexBed],
|
||||
get_current_printer_data()->target_temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexBed]);
|
||||
lv_label_set_text(label, bed_buff);
|
||||
}
|
||||
|
||||
static short get_temp_preset(int target){
|
||||
switch (target){
|
||||
case TARGET_HOTEND_CONFIG_1:
|
||||
return get_current_printer_config()->hotend_presets[0];
|
||||
return get_current_printer()->printer_config->hotend_presets[0];
|
||||
case TARGET_HOTEND_CONFIG_2:
|
||||
return get_current_printer_config()->hotend_presets[1];
|
||||
return get_current_printer()->printer_config->hotend_presets[1];
|
||||
case TARGET_HOTEND_CONFIG_3:
|
||||
return get_current_printer_config()->hotend_presets[2];
|
||||
return get_current_printer()->printer_config->hotend_presets[2];
|
||||
case TARGET_BED_CONFIG_1:
|
||||
return get_current_printer_config()->bed_presets[0];
|
||||
return get_current_printer()->printer_config->bed_presets[0];
|
||||
case TARGET_BED_CONFIG_2:
|
||||
return get_current_printer_config()->bed_presets[1];
|
||||
return get_current_printer()->printer_config->bed_presets[1];
|
||||
case TARGET_BED_CONFIG_3:
|
||||
return get_current_printer_config()->bed_presets[2];
|
||||
return get_current_printer()->printer_config->bed_presets[2];
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@@ -63,7 +70,7 @@ static void update_temp_preset_label(lv_event_t * e){
|
||||
|
||||
void UpdateConfig(){
|
||||
write_global_config();
|
||||
lv_msg_send(DATA_PRINTER_TEMP_PRESET, &printer);
|
||||
lv_msg_send(DATA_PRINTER_TEMP_PRESET, get_current_printer());
|
||||
}
|
||||
|
||||
static void keyboard_callback(lv_event_t * e){
|
||||
@@ -76,40 +83,36 @@ static void keyboard_callback(lv_event_t * e){
|
||||
if (temp < 0 || temp > 500){
|
||||
return;
|
||||
}
|
||||
|
||||
char gcode[64];
|
||||
|
||||
switch (keyboard_target){
|
||||
case TARGET_HOTEND:
|
||||
sprintf(gcode, "M104 S%d", temp);
|
||||
send_gcode(true, gcode);
|
||||
current_printer_set_target_temperature(PrinterTemperatureDevice::PrinterTemperatureDeviceNozzle1, temp);
|
||||
break;
|
||||
case TARGET_BED:
|
||||
sprintf(gcode, "M140 S%d", temp);
|
||||
send_gcode(true, gcode);
|
||||
current_printer_set_target_temperature(PrinterTemperatureDevice::PrinterTemperatureDeviceBed, temp);
|
||||
break;
|
||||
case TARGET_HOTEND_CONFIG_1:
|
||||
get_current_printer_config()->hotend_presets[0] = temp;
|
||||
get_current_printer()->printer_config->hotend_presets[0] = temp;
|
||||
UpdateConfig();
|
||||
break;
|
||||
case TARGET_HOTEND_CONFIG_2:
|
||||
get_current_printer_config()->hotend_presets[1] = temp;
|
||||
get_current_printer()->printer_config->hotend_presets[1] = temp;
|
||||
UpdateConfig();
|
||||
break;
|
||||
case TARGET_HOTEND_CONFIG_3:
|
||||
get_current_printer_config()->hotend_presets[2] = temp;
|
||||
get_current_printer()->printer_config->hotend_presets[2] = temp;
|
||||
UpdateConfig();
|
||||
break;
|
||||
case TARGET_BED_CONFIG_1:
|
||||
get_current_printer_config()->bed_presets[0] = temp;
|
||||
get_current_printer()->printer_config->bed_presets[0] = temp;
|
||||
UpdateConfig();
|
||||
break;
|
||||
case TARGET_BED_CONFIG_2:
|
||||
get_current_printer_config()->bed_presets[1] = temp;
|
||||
get_current_printer()->printer_config->bed_presets[1] = temp;
|
||||
UpdateConfig();
|
||||
break;
|
||||
case TARGET_BED_CONFIG_3:
|
||||
get_current_printer_config()->bed_presets[2] = temp;
|
||||
get_current_printer()->printer_config->bed_presets[2] = temp;
|
||||
UpdateConfig();
|
||||
break;
|
||||
}
|
||||
@@ -126,28 +129,19 @@ static void show_keyboard_with_bed(lv_event_t * e){
|
||||
}
|
||||
|
||||
static void cooldown_temp(lv_event_t * e){
|
||||
if (printer.state == PRINTER_STATE_PRINTING){
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePrinting){
|
||||
return;
|
||||
}
|
||||
|
||||
send_gcode(true, "M104 S0");
|
||||
send_gcode(true, "M140 S0");
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureCooldown);
|
||||
}
|
||||
|
||||
static void btn_extrude(lv_event_t * e){
|
||||
if (printer.state == PRINTER_STATE_PRINTING){
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePrinting){
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_current_printer_config()->custom_filament_move_macros)
|
||||
{
|
||||
send_gcode(true, "FILAMENT_EXTRUDE");
|
||||
}
|
||||
else
|
||||
{
|
||||
send_gcode(true, "M83");
|
||||
send_gcode(true, "G1 E25 F300");
|
||||
}
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureExtrude);
|
||||
}
|
||||
|
||||
static void set_temp_via_preset(lv_event_t * e){
|
||||
@@ -160,13 +154,10 @@ static void set_temp_via_preset(lv_event_t * e){
|
||||
return;
|
||||
}
|
||||
|
||||
char gcode[64];
|
||||
if (target <= TARGET_HOTEND_CONFIG_3)
|
||||
sprintf(gcode, "M104 S%d", value);
|
||||
else
|
||||
sprintf(gcode, "M140 S%d", value);
|
||||
|
||||
send_gcode(true, gcode);
|
||||
current_printer_set_target_temperature(target <= TARGET_HOTEND_CONFIG_3
|
||||
? PrinterTemperatureDevice::PrinterTemperatureDeviceNozzle1
|
||||
: PrinterTemperatureDevice::PrinterTemperatureDeviceBed
|
||||
, value);
|
||||
}
|
||||
|
||||
static void btn_toggleable_edit(lv_event_t * e){
|
||||
@@ -176,19 +167,11 @@ static void btn_toggleable_edit(lv_event_t * e){
|
||||
}
|
||||
|
||||
static void btn_retract(lv_event_t * e){
|
||||
if (printer.state == PRINTER_STATE_PRINTING){
|
||||
if (get_current_printer_data()->state == PrinterState::PrinterStatePrinting){
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_current_printer_config()->custom_filament_move_macros)
|
||||
{
|
||||
send_gcode(true, "FILAMENT_RETRACT");
|
||||
}
|
||||
else
|
||||
{
|
||||
send_gcode(true, "M83");
|
||||
send_gcode(true, "G1 E-25 F300");
|
||||
}
|
||||
current_printer_execute_feature(PrinterFeatures::PrinterFeatureRetract);
|
||||
}
|
||||
|
||||
static void set_chart_range(lv_event_t * e) {
|
||||
@@ -218,25 +201,25 @@ static void set_chart_range(lv_event_t * e) {
|
||||
static void set_hotend_temp_chart(lv_event_t * e){
|
||||
lv_obj_t * chart = lv_event_get_target(e);
|
||||
lv_chart_series_t * series = (lv_chart_series_t *)lv_event_get_user_data(e);
|
||||
lv_chart_set_next_value(chart, series, printer.extruder_temp);
|
||||
lv_chart_set_next_value(chart, series, get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexNozzle1]);
|
||||
}
|
||||
|
||||
static void set_hotend_target_temp_chart(lv_event_t * e){
|
||||
lv_obj_t * chart = lv_event_get_target(e);
|
||||
lv_chart_series_t * series = (lv_chart_series_t *)lv_event_get_user_data(e);
|
||||
lv_chart_set_next_value(chart, series, printer.extruder_target_temp);
|
||||
lv_chart_set_next_value(chart, series, get_current_printer_data()->target_temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexNozzle1]);
|
||||
}
|
||||
|
||||
static void set_bed_temp_chart(lv_event_t * e){
|
||||
lv_obj_t * chart = lv_event_get_target(e);
|
||||
lv_chart_series_t * series = (lv_chart_series_t *)lv_event_get_user_data(e);
|
||||
lv_chart_set_next_value(chart, series, printer.bed_temp);
|
||||
lv_chart_set_next_value(chart, series, get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexBed]);
|
||||
}
|
||||
|
||||
static void set_bed_target_temp_chart(lv_event_t * e){
|
||||
lv_obj_t * chart = lv_event_get_target(e);
|
||||
lv_chart_series_t * series = (lv_chart_series_t *)lv_event_get_user_data(e);
|
||||
lv_chart_set_next_value(chart, series, printer.bed_target_temp);
|
||||
lv_chart_set_next_value(chart, series, get_current_printer_data()->target_temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexBed]);
|
||||
}
|
||||
|
||||
void create_charts(lv_obj_t * root)
|
||||
@@ -251,13 +234,13 @@ void create_charts(lv_obj_t * root)
|
||||
lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);
|
||||
|
||||
lv_chart_series_t * ser1 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_ORANGE), LV_CHART_AXIS_PRIMARY_Y);
|
||||
lv_chart_set_all_value(chart, ser1, printer.extruder_target_temp);
|
||||
lv_chart_set_all_value(chart, ser1, get_current_printer_data()->target_temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexNozzle1]);
|
||||
lv_chart_series_t * ser2 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
|
||||
lv_chart_set_all_value(chart, ser2, printer.extruder_temp);
|
||||
lv_chart_set_all_value(chart, ser2, get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexNozzle1]);
|
||||
lv_chart_series_t * ser3 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_TEAL), LV_CHART_AXIS_PRIMARY_Y);
|
||||
lv_chart_set_all_value(chart, ser3, printer.bed_target_temp);
|
||||
lv_chart_set_all_value(chart, ser3, get_current_printer_data()->target_temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexBed]);
|
||||
lv_chart_series_t * ser4 = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_BLUE), LV_CHART_AXIS_PRIMARY_Y);
|
||||
lv_chart_set_all_value(chart, ser4, printer.bed_temp);
|
||||
lv_chart_set_all_value(chart, ser4, get_current_printer_data()->temperatures[PrinterTemperatureDeviceIndex::PrinterTemperatureDeviceIndexBed]);
|
||||
|
||||
lv_obj_add_event_cb(chart, set_hotend_target_temp_chart, LV_EVENT_MSG_RECEIVED, ser1);
|
||||
lv_obj_add_event_cb(chart, set_hotend_temp_chart, LV_EVENT_MSG_RECEIVED, ser2);
|
||||
@@ -391,5 +374,5 @@ void temp_panel_init(lv_obj_t * panel){
|
||||
lv_obj_center(label);
|
||||
|
||||
lv_obj_scroll_to_y(root_temp_panel, 9999, LV_ANIM_OFF);
|
||||
lv_msg_send(DATA_PRINTER_TEMP_PRESET, &printer);
|
||||
lv_msg_send(DATA_PRINTER_TEMP_PRESET, get_current_printer());
|
||||
}
|
||||
371
CYD-Klipper/src/ui/serial/serial_commands.cpp
Normal file
371
CYD-Klipper/src/ui/serial/serial_commands.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
#include "serial_commands.h"
|
||||
#include <HardwareSerial.h>
|
||||
#include <Esp.h>
|
||||
#include <cstring>
|
||||
#include "../../conf/global_config.h"
|
||||
#include "../../core/printer_integration.hpp"
|
||||
|
||||
namespace serial_console {
|
||||
|
||||
/* How to add a new command:
|
||||
- add the handler; function signature must be like: void handler(String argv[])
|
||||
- add {"command_name", &handler_name, argc} to commandHandlers
|
||||
(argc = num of args + 1; argv[0] is always the command name)
|
||||
- add the handler signature to serial_command.h
|
||||
- add description to help()
|
||||
- optionally add handling the new preference to sets() and settings() if it modifies global_config
|
||||
*/
|
||||
|
||||
PrinterConfiguration* get_current_printer_config()
|
||||
{
|
||||
return &global_config.printer_config[global_config.printer_index];
|
||||
}
|
||||
|
||||
HANDLER commandHandlers[] = {
|
||||
{"help", &help, 1},
|
||||
{"reset", &reset, 1},
|
||||
{"settings", &settings, 1},
|
||||
{"sets", &sets, 1},
|
||||
{"erase", &erase, 2},
|
||||
{"key", &key, 2},
|
||||
{"touch", &touch, 5},
|
||||
{"ssid", &ssid, 3},
|
||||
{"ip", &ip, 3},
|
||||
{"rotation", &rotation, 2},
|
||||
{"brightness", &brightness, 2},
|
||||
{"printer", &printer, 2},
|
||||
{"debug", &debug, 2},
|
||||
{"echo", &echo, 2}
|
||||
};
|
||||
|
||||
void help(String argv[])
|
||||
{
|
||||
Serial.println("Serial console commands:");
|
||||
Serial.println("");
|
||||
Serial.println("settings - show current settings");
|
||||
Serial.println("sets - show current settings as commands for copy-paste");
|
||||
Serial.println("erase [item] - unconfigure parameter (key|touch|ssid|ip|all)");
|
||||
Serial.println("reset - restart CYD-klipper");
|
||||
Serial.println("touch [xm xo ym yo] - set touchscreen multipliers and offsets");
|
||||
Serial.println("ssid [name pass] - set the network SSID and password to connect to");
|
||||
Serial.println("ip [address port] - set Moonraker address");
|
||||
Serial.println("key [key] - set the Moonraker API key");
|
||||
Serial.println("rotation [on|off] - set rotate screen 180 degrees");
|
||||
Serial.println("brightness [num] - set screen brightness");
|
||||
Serial.println("printer [num|-1] - set active printer#; -1 for multi-printer mode off");
|
||||
Serial.println("debug [on|off] - set printing of debug messages to serial console (not saved)");
|
||||
Serial.println("echo [on|off] - set remote echo (eecchhoo ooffff) (not saved)");
|
||||
Serial.println("help - this help");
|
||||
Serial.println("");
|
||||
Serial.println("Settings are saved immediately but come into effect after reset");
|
||||
Serial.println("Unlike GUI, serial console does not validate if settings");
|
||||
Serial.println("you enter work correctly. This is a double-edged sword.");
|
||||
}
|
||||
|
||||
// this must be here, because serial_console doesn't have a clue about sizeof(commandHandlers) at compile time
|
||||
int find_command(String cmd)
|
||||
{
|
||||
for(int i=0; i < sizeof(commandHandlers) / sizeof(HANDLER); ++i)
|
||||
{
|
||||
if(cmd == commandHandlers[i].name) return i;
|
||||
}
|
||||
Serial.println("Unknown command");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void reset(String argv[])
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void sets(String argv[])
|
||||
{
|
||||
|
||||
Serial.printf("printer %d\n", global_config.multi_printer_mode?global_config.printer_index:-1);
|
||||
|
||||
if(global_config.wifi_configured)
|
||||
{
|
||||
Serial.printf("ssid %s %s\n",global_config.wifi_SSID,
|
||||
#if DISPLAY_SECRETS
|
||||
global_config.wifi_password
|
||||
#else
|
||||
"[redacted]"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("erase ssid\n");
|
||||
}
|
||||
|
||||
if(get_current_printer_config()->ip_configured)
|
||||
{
|
||||
Serial.printf("ip %s %d\n",get_current_printer_config()->printer_host, get_current_printer_config()->klipper_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("erase ip\n");
|
||||
}
|
||||
|
||||
if(get_current_printer_config()->auth_configured)
|
||||
{
|
||||
Serial.printf("key %s\n",
|
||||
#if DISPLAY_SECRETS
|
||||
get_current_printer_config()->printer_auth
|
||||
#else
|
||||
"[redacted]"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("erase key\n");
|
||||
}
|
||||
|
||||
if(global_config.screen_calibrated)
|
||||
{
|
||||
Serial.printf("touch %f %f %f %f\n",
|
||||
global_config.screen_cal_x_mult, global_config.screen_cal_x_offset, global_config.screen_cal_y_mult, global_config.screen_cal_y_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("erase touch\n");
|
||||
}
|
||||
|
||||
Serial.printf("rotation %s\n",global_config.rotate_screen?"on":"off");
|
||||
Serial.printf("brightness %d\n",global_config.brightness);
|
||||
}
|
||||
|
||||
void settings(String argv[])
|
||||
{
|
||||
|
||||
if(get_current_printer_config()->printer_name[0] != 0)
|
||||
{
|
||||
Serial.printf("Current printer# %d name: %s",global_config.printer_index, get_current_printer_config()->printer_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Current printer# %d",global_config.printer_index);
|
||||
}
|
||||
Serial.printf(" Multi-printer mode %s\n",global_config.multi_printer_mode?"enabled":"disabled");
|
||||
|
||||
|
||||
if(global_config.wifi_configured)
|
||||
{
|
||||
Serial.printf("SSID: %s Password: %s\n",global_config.wifi_SSID,
|
||||
#if DISPLAY_SECRETS
|
||||
global_config.wifi_password
|
||||
#else
|
||||
"[redacted]"
|
||||
#endif
|
||||
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Wifi not configured\n");
|
||||
}
|
||||
|
||||
if(get_current_printer_config()->ip_configured)
|
||||
{
|
||||
Serial.printf("Moonraker address: %s:%d\n",get_current_printer_config()->printer_host, get_current_printer_config()->klipper_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Moonraker address not configured\n");
|
||||
}
|
||||
|
||||
if(get_current_printer_config()->auth_configured)
|
||||
{
|
||||
Serial.printf("Moonraker API key: %s\n",
|
||||
#if DISPLAY_SECRETS
|
||||
get_current_printer_config()->printer_auth
|
||||
#else
|
||||
"[redacted]"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Moonraker API key not configured\n");
|
||||
}
|
||||
|
||||
if(global_config.screen_calibrated)
|
||||
{
|
||||
Serial.printf("Screen coefficients: x_screen = %f * x_touch + %f; y_screen = %f * y_touch + %f\n",
|
||||
global_config.screen_cal_x_mult, global_config.screen_cal_x_offset, global_config.screen_cal_y_mult, global_config.screen_cal_y_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Screen not calibrated\n");
|
||||
}
|
||||
|
||||
Serial.printf("Screen orientation: %s\n",global_config.rotate_screen?"rotated":"normal");
|
||||
Serial.printf("Screen brightness: %d\n",global_config.brightness);
|
||||
}
|
||||
|
||||
|
||||
void erase_one(const String arg)
|
||||
{
|
||||
if(arg == "key")
|
||||
{
|
||||
get_current_printer_config()->auth_configured = false;
|
||||
// overwrite the key to make it unrecoverable for 3rd parties
|
||||
memset(get_current_printer_config()->printer_auth,0,64);
|
||||
write_global_config();
|
||||
}
|
||||
else if(arg == "ip")
|
||||
{
|
||||
get_current_printer_config()->setup_complete = false;
|
||||
get_current_printer_config()->ip_configured = false;
|
||||
write_global_config();
|
||||
}
|
||||
else if(arg == "touch")
|
||||
{
|
||||
global_config.screen_calibrated = false;
|
||||
write_global_config();
|
||||
}
|
||||
else if(arg == "ssid")
|
||||
{
|
||||
global_config.wifi_configured = false;
|
||||
// overwrite the pass to make it unrecoverable for 3rd parties
|
||||
memset(global_config.wifi_password,0,64);
|
||||
write_global_config();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Unknown key");
|
||||
}
|
||||
}
|
||||
|
||||
void erase(String argv[])
|
||||
{
|
||||
const String& arg=argv[1];
|
||||
if(arg != "all")
|
||||
{
|
||||
erase_one(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
erase_one("key");
|
||||
erase_one("ip");
|
||||
erase_one("touch");
|
||||
erase_one("ssid");
|
||||
}
|
||||
}
|
||||
|
||||
void key(String argv[])
|
||||
{
|
||||
get_current_printer_config()->auth_configured = true;
|
||||
strncpy(get_current_printer_config()->printer_auth, argv[1].c_str(), sizeof(global_config.printer_config[0].printer_auth));
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
void touch(String argv[])
|
||||
{
|
||||
global_config.screen_cal_x_mult = argv[1].toFloat();
|
||||
global_config.screen_cal_x_offset = argv[2].toFloat();
|
||||
global_config.screen_cal_y_mult = argv[3].toFloat();
|
||||
global_config.screen_cal_y_offset = argv[4].toFloat();
|
||||
global_config.screen_calibrated = true;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
void ssid(String argv[])
|
||||
{
|
||||
strncpy(global_config.wifi_SSID, argv[1].c_str(), sizeof(global_config.wifi_SSID)-1);
|
||||
strncpy(global_config.wifi_password, argv[2].c_str(), sizeof(global_config.wifi_password)-1);
|
||||
global_config.wifi_configured = true;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
void ip(String argv[])
|
||||
{
|
||||
strncpy(get_current_printer_config()->printer_host, argv[1].c_str(), sizeof(global_config.printer_config[0].printer_host)-1);
|
||||
get_current_printer_config()->klipper_port = argv[2].toInt();
|
||||
get_current_printer_config()->ip_configured = true;
|
||||
get_current_printer_config()->setup_complete = true;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
void rotation(String argv[])
|
||||
{
|
||||
if(argv[1] == "on")
|
||||
{
|
||||
global_config.rotate_screen = true;
|
||||
write_global_config();
|
||||
}
|
||||
else if (argv[1] == "off")
|
||||
{
|
||||
global_config.rotate_screen = false;
|
||||
write_global_config();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Rotation can be on or off");
|
||||
}
|
||||
}
|
||||
|
||||
void brightness(String argv[])
|
||||
{
|
||||
global_config.brightness = argv[1].toInt();
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
|
||||
void printer(String argv[])
|
||||
{
|
||||
int ndx = argv[1].toInt();
|
||||
if(ndx <= -1)
|
||||
{
|
||||
global_config.multi_printer_mode = false;
|
||||
set_current_printer(0);
|
||||
}
|
||||
else if( ndx >= 0 && ndx < get_printer_count())
|
||||
{
|
||||
global_config.multi_printer_mode = true;
|
||||
set_current_printer(ndx);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Printer index out of range");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void debug(String argv[])
|
||||
{
|
||||
if(argv[1] == "on")
|
||||
{
|
||||
temporary_config.debug = true;
|
||||
|
||||
}
|
||||
else if (argv[1] == "off")
|
||||
{
|
||||
temporary_config.debug = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("debug can be on or off");
|
||||
}
|
||||
}
|
||||
|
||||
void echo(String argv[])
|
||||
{
|
||||
if(argv[1] == "on")
|
||||
{
|
||||
temporary_config.remote_echo = true;
|
||||
}
|
||||
else if (argv[1] == "off")
|
||||
{
|
||||
temporary_config.remote_echo = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Echo can be on or off");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
29
CYD-Klipper/src/ui/serial/serial_commands.h
Normal file
29
CYD-Klipper/src/ui/serial/serial_commands.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <WString.h>
|
||||
|
||||
namespace serial_console {
|
||||
|
||||
typedef struct _HANDLER {
|
||||
const char* name;
|
||||
void (* function)(String argv[]);
|
||||
int argc;
|
||||
} HANDLER;
|
||||
|
||||
extern HANDLER commandHandlers[];
|
||||
|
||||
void help(String argv[]);
|
||||
void reset(String argv[]);
|
||||
void settings(String argv[]);
|
||||
void sets(String argv[]);
|
||||
void erase(String argv[]);
|
||||
void key(String argv[]);
|
||||
void touch(String argv[]);
|
||||
void ssid(String argv[]);
|
||||
void ip(String argv[]);
|
||||
void rotation(String argv[]);
|
||||
void brightness(String argv[]);
|
||||
void printer(String argv[]);
|
||||
void debug(String argv[]);
|
||||
void echo(String argv[]);
|
||||
|
||||
int find_command(String cmd);
|
||||
}
|
||||
161
CYD-Klipper/src/ui/serial/serial_console.cpp
Normal file
161
CYD-Klipper/src/ui/serial/serial_console.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "serial_commands.h"
|
||||
#include "../../conf/global_config.h"
|
||||
#include <HardwareSerial.h>
|
||||
#include <WString.h>
|
||||
|
||||
#define MAX_COMDLINE_SIZE 80
|
||||
#define MAX_WORDS 6
|
||||
|
||||
namespace serial_console
|
||||
{
|
||||
bool global_disable_serial_console = false;
|
||||
|
||||
/*
|
||||
* read_string_until: Non-blocking replacement for Serial.readStringUntil()..
|
||||
* With delimeter '\n' acts as 'read line'.
|
||||
* If input (line) size exceeds provided buffer's size, that entire input (until next delimeter) is silently discarded.
|
||||
* Serial.available() can return true without \n being ever in the buffer, so we don't trust it here.
|
||||
*/
|
||||
|
||||
bool read_string_until(char delimiter, char *result, int max_len)
|
||||
{
|
||||
static int index = 0;
|
||||
int c; // read character, -1 if none
|
||||
int cnt = 100; // limit on amount of iterations in one go; we're supposed to be non-blocking!
|
||||
|
||||
while ((c = Serial.read()) != -1 && cnt > 0)
|
||||
{
|
||||
--cnt;
|
||||
|
||||
// backspaceF
|
||||
if (c == 8)
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
if(temporary_config.remote_echo) Serial.print("\x08 \x08"); // overwrite last character with space and move cursor 1 back.
|
||||
index--;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(temporary_config.remote_echo) Serial.print((char)c); // echo
|
||||
|
||||
// Buffer overflow handling:
|
||||
// start treating current buffer as invalid:
|
||||
// - stop collecting more data
|
||||
// - return false on delimeter, flushing everything collected,
|
||||
// - restart collection from scratch after delimeter,
|
||||
// - return control as normal.
|
||||
|
||||
if (index >= max_len - 1)
|
||||
{
|
||||
if (c == delimiter) // got delimeter: flush buffer quietly, restart collection.
|
||||
{
|
||||
index = 0;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
continue; // discard any data past the end of the buffer, keep reading
|
||||
}
|
||||
|
||||
result[index++] = c;
|
||||
|
||||
// delimiter was found
|
||||
if (c == delimiter)
|
||||
{
|
||||
result[index] = '\0'; // Null-terminate the string
|
||||
index = 0;
|
||||
return true; // Success: Delimiter found
|
||||
}
|
||||
}
|
||||
|
||||
return false; // still waiting for delimeter
|
||||
}
|
||||
|
||||
// split input into words.
|
||||
// assumes input ends with '\n', also ends parsing if found MAX_WORDS already.
|
||||
int tokenize(String results[], char *input)
|
||||
{
|
||||
int index = 0;
|
||||
int word_count = 0;
|
||||
String word = "";
|
||||
do
|
||||
{
|
||||
if (input[index] == '\t' || (input[index] == ' ' && (index <= 0 || input[index - 1] != '\\')) || input[index] == '\n' || input[index] == '\r' || input[index] == '\0')
|
||||
{
|
||||
if (word.length() > 0)
|
||||
{
|
||||
results[word_count] = word;
|
||||
++word_count;
|
||||
if (word_count >= MAX_WORDS)
|
||||
{
|
||||
return word_count;
|
||||
}
|
||||
word = "";
|
||||
}
|
||||
|
||||
if (input[index] == '\n' || input[index] == '\0')
|
||||
{
|
||||
return word_count;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (input[index] != '\\')
|
||||
{
|
||||
word += input[index];
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
void greet()
|
||||
{
|
||||
Serial.println("CYD-Klipper " REPO_VERSION);
|
||||
Serial.println("Type 'help' for serial console command list");
|
||||
Serial.print("> ");
|
||||
}
|
||||
|
||||
bool verify_arg_count(int got, int expected)
|
||||
{
|
||||
if (got != expected)
|
||||
{
|
||||
Serial.printf("Command expects %d argument%s, %d given.\n", expected - 1, expected == 2 ? "" : "s", got - 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// main "engine": non-blockingly read until newline found, parse, execute.
|
||||
void run()
|
||||
{
|
||||
if (global_disable_serial_console)
|
||||
return;
|
||||
|
||||
static char cmdline[MAX_COMDLINE_SIZE + 1] = {0};
|
||||
if (!read_string_until('\n', cmdline, MAX_COMDLINE_SIZE))
|
||||
return;
|
||||
|
||||
String argv[MAX_WORDS];
|
||||
int argc = tokenize(argv, cmdline);
|
||||
|
||||
if (argc > 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
int cmd_id = find_command(argv[0]);
|
||||
if (cmd_id == -1)
|
||||
break;
|
||||
if (!verify_arg_count(argc, commandHandlers[cmd_id].argc))
|
||||
break;
|
||||
commandHandlers[cmd_id].function(argv);
|
||||
} while (0);
|
||||
}
|
||||
|
||||
Serial.print("> ");
|
||||
}
|
||||
|
||||
}
|
||||
10
CYD-Klipper/src/ui/serial/serial_console.h
Normal file
10
CYD-Klipper/src/ui/serial/serial_console.h
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
namespace serial_console {
|
||||
|
||||
void greet();
|
||||
void run();
|
||||
|
||||
extern bool global_disable_serial_console;
|
||||
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#include "switch_printer.h"
|
||||
#include "../conf/global_config.h"
|
||||
#include "ui_utils.h"
|
||||
#include "../core/http_client.h"
|
||||
#include "../core/lv_setup.h"
|
||||
#include "../core/macros_query.h"
|
||||
#include "../core/screen_driver.h"
|
||||
#include "../core/data_setup.h"
|
||||
|
||||
void switch_printer(int index)
|
||||
{
|
||||
set_printer_config_index(index);
|
||||
set_color_scheme();
|
||||
set_invert_display();
|
||||
printer.slicer_estimated_print_time_s = 0;
|
||||
}
|
||||
|
||||
static void btn_switch_printer(lv_event_t *e){
|
||||
lv_obj_t *btn = lv_event_get_target(e);
|
||||
PRINTER_CONFIG * config = (PRINTER_CONFIG*)lv_event_get_user_data(e);
|
||||
int index = config - global_config.printer_config;
|
||||
|
||||
switch_printer(index);
|
||||
|
||||
lv_obj_del(lv_obj_get_parent(lv_obj_get_parent(btn)));
|
||||
}
|
||||
|
||||
void switch_printer_init() {
|
||||
lv_obj_t * parent = lv_create_empty_panel(lv_scr_act());
|
||||
lv_obj_set_style_bg_opa(parent, LV_OPA_100, 0);
|
||||
lv_obj_align(parent, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
lv_obj_set_size(parent, CYD_SCREEN_WIDTH_PX, CYD_SCREEN_HEIGHT_PX);
|
||||
lv_layout_flex_column(parent);
|
||||
|
||||
lv_obj_set_size(lv_create_empty_panel(parent), 0, 0);
|
||||
|
||||
auto width = CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 2;
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(parent);
|
||||
lv_obj_set_size(btn, width, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_add_event_cb(btn, destroy_event_user_data, LV_EVENT_CLICKED, parent);
|
||||
|
||||
lv_obj_t * label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_CLOSE " Close");
|
||||
lv_obj_center(label);
|
||||
|
||||
for (int i = 0; i < PRINTER_CONFIG_COUNT; i++){
|
||||
PRINTER_CONFIG * config = &global_config.printer_config[i];
|
||||
const char* printer_name = (config->printer_name[0] == 0) ? config->klipper_host : config->printer_name;
|
||||
|
||||
if (config == get_current_printer_config() && config->ip_configured)
|
||||
{
|
||||
lv_create_custom_menu_label(printer_name, parent, "Active");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config->ip_configured) {
|
||||
HTTPClient client;
|
||||
configure_http_client(client, get_full_url("/printer/objects/query?webhooks&print_stats&virtual_sdcard", config), true, 1000);
|
||||
|
||||
|
||||
int httpCode = client.GET();
|
||||
lv_create_custom_menu_button(printer_name, parent, btn_switch_printer, (httpCode == 200) ? "Switch" : "Offline", config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void show_switch_printer_screen(lv_event_t * e){
|
||||
switch_printer_init();
|
||||
}
|
||||
|
||||
lv_obj_t * draw_switch_printer_button()
|
||||
{
|
||||
if (!global_config.multi_printer_mode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(lv_scr_act());
|
||||
lv_obj_set_size(btn, CYD_SCREEN_MIN_BUTTON_WIDTH_PX, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_align(btn, LV_ALIGN_TOP_RIGHT, -CYD_SCREEN_GAP_PX, CYD_SCREEN_GAP_PX);
|
||||
lv_obj_add_event_cb(btn, show_switch_printer_screen, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
lv_obj_t * label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_HOME);
|
||||
lv_obj_center(label);
|
||||
|
||||
return btn;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include "lvgl.h"
|
||||
|
||||
void switch_printer(int index);
|
||||
void switch_printer_init();
|
||||
lv_obj_t * draw_switch_printer_button();
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "ui_utils.h"
|
||||
#include "../core/data_setup.h"
|
||||
#include "../core/lv_setup.h"
|
||||
#include <ErriezCRC32.h>
|
||||
#include "../core/printer_integration.hpp"
|
||||
|
||||
lv_obj_t* lv_create_empty_panel(lv_obj_t* root) {
|
||||
lv_obj_t* panel = lv_obj_create(root);
|
||||
@@ -34,6 +34,17 @@ void destroy_event_user_data(lv_event_t * e){
|
||||
lv_obj_del(obj);
|
||||
}
|
||||
|
||||
void destroy_event_free_data(lv_event_t * e)
|
||||
{
|
||||
void* data = lv_event_get_user_data(e);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void lv_obj_on_destroy_free_data(lv_obj_t * element, const void* ptr)
|
||||
{
|
||||
lv_obj_add_event_cb(element, destroy_event_free_data, LV_EVENT_DELETE, (void*)ptr);
|
||||
}
|
||||
|
||||
void lv_create_fullscreen_button_matrix_popup(lv_obj_t * root, lv_event_cb_t title, lv_button_column_t* columns, int column_count){
|
||||
const auto full_panel_width = CYD_SCREEN_WIDTH_PX - CYD_SCREEN_GAP_PX * 3;
|
||||
const auto full_panel_inner_width = full_panel_width - CYD_SCREEN_GAP_PX * 2 - 4;
|
||||
@@ -79,7 +90,8 @@ void lv_create_fullscreen_button_matrix_popup(lv_obj_t * root, lv_event_cb_t tit
|
||||
|
||||
for (int j = 0; j < columns[i].length; j++){
|
||||
lv_obj_t * btn = lv_btn_create(column);
|
||||
lv_obj_set_size(btn, column_width, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
lv_obj_set_width(btn, column_width);
|
||||
lv_obj_set_flex_grow(btn, 1);
|
||||
lv_obj_add_event_cb(btn, columns[i].event, LV_EVENT_CLICKED, (void*)columns[i].data[j]);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
@@ -107,6 +119,7 @@ void lv_create_keyboard_text_entry(lv_event_cb_t keyboard_callback, const char*
|
||||
lv_obj_set_style_bg_opa(parent, LV_OPA_50, 0);
|
||||
lv_obj_align(parent, LV_ALIGN_TOP_RIGHT, 0, 0);
|
||||
lv_layout_flex_column(parent, LV_FLEX_ALIGN_SPACE_BETWEEN);
|
||||
lv_obj_clear_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
if (contain_in_panel)
|
||||
{
|
||||
@@ -117,7 +130,7 @@ void lv_create_keyboard_text_entry(lv_event_cb_t keyboard_callback, const char*
|
||||
lv_obj_set_size(parent, CYD_SCREEN_WIDTH_PX, CYD_SCREEN_HEIGHT_PX);
|
||||
}
|
||||
|
||||
if (title != nullptr)
|
||||
if (title != nullptr && keyboard_mode != LV_KEYBOARD_MODE_NUMBER)
|
||||
{
|
||||
lv_obj_t * empty_panel = lv_create_empty_panel(parent);
|
||||
lv_obj_set_size(empty_panel, 0, 0);
|
||||
@@ -136,6 +149,12 @@ void lv_create_keyboard_text_entry(lv_event_cb_t keyboard_callback, const char*
|
||||
lv_obj_t * ta = lv_textarea_create(parent);
|
||||
lv_obj_t * keyboard = lv_keyboard_create(parent);
|
||||
|
||||
if (keyboard_mode == LV_KEYBOARD_MODE_NUMBER)
|
||||
{
|
||||
lv_textarea_set_placeholder_text(ta, title);
|
||||
lv_obj_set_height(keyboard, LV_PCT(75));
|
||||
}
|
||||
|
||||
lv_obj_set_width(ta, width);
|
||||
lv_textarea_set_max_length(ta, max_length);
|
||||
lv_textarea_set_one_line(ta, true);
|
||||
@@ -162,8 +181,10 @@ void lv_create_custom_menu_entry(const char* label_text, lv_obj_t* object, lv_ob
|
||||
|
||||
lv_obj_set_parent(object, panel);
|
||||
|
||||
if (set_height)
|
||||
if (set_height)
|
||||
{
|
||||
lv_obj_set_height(object, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
}
|
||||
|
||||
if (comment != NULL)
|
||||
{
|
||||
@@ -223,7 +244,6 @@ void lv_create_custom_menu_label(const char *label_text, lv_obj_t* root_panel, c
|
||||
lv_create_custom_menu_entry(label_text, label, root_panel, false);
|
||||
}
|
||||
|
||||
uint32_t message_hash = 0;
|
||||
lv_timer_t* timer = NULL;
|
||||
|
||||
void on_timer_destroy(lv_event_t * e)
|
||||
@@ -245,15 +265,6 @@ void lv_create_popup_message(const char* message, uint16_t timeout_ms)
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t new_hash = crc32String(message);
|
||||
|
||||
if (new_hash == message_hash)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
message_hash = new_hash;
|
||||
|
||||
lv_obj_t* panel = lv_obj_create(lv_scr_act());
|
||||
lv_obj_set_style_pad_all(panel, CYD_SCREEN_GAP_PX, CYD_SCREEN_GAP_PX);
|
||||
lv_obj_set_size(panel, CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 2, LV_SIZE_CONTENT);
|
||||
@@ -268,7 +279,7 @@ void lv_create_popup_message(const char* message, uint16_t timeout_ms)
|
||||
lv_obj_set_size(label, CYD_SCREEN_PANEL_WIDTH_PX - CYD_SCREEN_GAP_PX * 6, LV_SIZE_CONTENT);
|
||||
lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP);
|
||||
|
||||
timer = lv_timer_create(timer_callback, timeout_ms, panel);
|
||||
timer = lv_timer_create(timer_callback, timeout_ms > 0 ? timeout_ms : 0xFFFFFFFF, panel);
|
||||
}
|
||||
|
||||
lv_obj_t * lv_label_btn_create(lv_obj_t * parent, lv_event_cb_t btn_callback, void* user_data)
|
||||
|
||||
@@ -38,7 +38,8 @@ void lv_layout_flex_column(lv_obj_t* obj, lv_flex_align_t allign = LV_FLEX_ALIGN
|
||||
void lv_layout_flex_row(lv_obj_t* obj, lv_flex_align_t allign = LV_FLEX_ALIGN_START, lv_coord_t pad_column = CYD_SCREEN_GAP_PX, lv_coord_t pad_row = CYD_SCREEN_GAP_PX);
|
||||
void lv_create_fullscreen_button_matrix_popup(lv_obj_t * root, lv_event_cb_t title, lv_button_column_t* columns, int column_count);
|
||||
void destroy_event_user_data(lv_event_t * e);
|
||||
void lv_create_keyboard_text_entry(lv_event_cb_t keyboard_callback, const char* title = NULL, lv_keyboard_mode_t keyboard_mode = LV_KEYBOARD_MODE_NUMBER, lv_coord_t width = CYD_SCREEN_PANEL_WIDTH_PX / 2, uint8_t max_length = 3, const char* fill_text = "", bool contain_in_panel= true);
|
||||
void lv_obj_on_destroy_free_data(lv_obj_t * element, const void* ptr);
|
||||
void lv_create_keyboard_text_entry(lv_event_cb_t keyboard_callback, const char* title = NULL, lv_keyboard_mode_t keyboard_mode = LV_KEYBOARD_MODE_NUMBER, lv_coord_t width = LV_PCT(75), uint8_t max_length = 3, const char* fill_text = "", bool contain_in_panel= true);
|
||||
void lv_create_custom_menu_entry(const char* label_text, lv_obj_t* object, lv_obj_t* root_panel, bool set_height = true, const char * comment = NULL);
|
||||
void lv_create_custom_menu_button(const char *label_text, lv_obj_t* root_panel, lv_event_cb_t on_click, const char *btn_text, void * user_data = NULL, const char * comment = NULL);
|
||||
void lv_create_custom_menu_switch(const char *label_text, lv_obj_t* root_panel, lv_event_cb_t on_toggle, bool state, void * user_data = NULL, const char * comment = NULL);
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include "WiFi.h"
|
||||
#include "../core/data_setup.h"
|
||||
#include "../core/lv_setup.h"
|
||||
#include "serial/serial_console.h"
|
||||
#include "panels/panel.h"
|
||||
#include "../core/semaphore.h"
|
||||
|
||||
void wifi_init_inner();
|
||||
void wifi_pass_entry(const char* ssid);
|
||||
@@ -87,7 +90,7 @@ void wifi_pass_entry(const char* ssid)
|
||||
static void wifi_btn_event_handler(lv_event_t * e){
|
||||
delay(100);
|
||||
char* ssid = (char*)e->user_data;
|
||||
Serial.println(ssid);
|
||||
LOG_LN(ssid);
|
||||
wifi_pass_entry(ssid);
|
||||
}
|
||||
|
||||
@@ -97,7 +100,7 @@ static void wifi_keyboard_cb_manual_ssid(lv_event_t * e){
|
||||
const char * text = lv_textarea_get_text(ta);
|
||||
char * text_copy = (char*)malloc(strlen(text) + 1);
|
||||
strcpy(text_copy, text);
|
||||
Serial.println(text_copy);
|
||||
LOG_LN(text_copy);
|
||||
wifi_pass_entry(text_copy);
|
||||
}
|
||||
|
||||
@@ -105,6 +108,29 @@ static void wifi_btn_manual_ssid(lv_event_t * e){
|
||||
lv_create_keyboard_text_entry(wifi_keyboard_cb_manual_ssid, "Enter SSID Manually", LV_KEYBOARD_MODE_TEXT_LOWER, CYD_SCREEN_WIDTH_PX * 0.75, 31, "", false);
|
||||
}
|
||||
|
||||
static void wifi_btn_skip_setup(lv_event_t * e){
|
||||
global_config.wifi_configuration_skipped = true;
|
||||
write_global_config();
|
||||
}
|
||||
|
||||
static void wifi_btn_settings(lv_event_t * e){
|
||||
lv_obj_clean(lv_scr_act());
|
||||
lv_obj_t * panel = lv_create_empty_panel(lv_scr_act());
|
||||
lv_obj_set_size(panel, CYD_SCREEN_WIDTH_PX, CYD_SCREEN_HEIGHT_PX);
|
||||
lv_layout_flex_column(panel);
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(panel);
|
||||
lv_obj_add_event_cb(btn, reset_btn_event_handler, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_set_style_radius(btn, 0, 0);
|
||||
lv_obj_set_size(btn, LV_PCT(100), CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
|
||||
lv_obj_t * label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "Return to WiFi Setup");
|
||||
lv_obj_center(label);
|
||||
|
||||
settings_section_device(panel);
|
||||
}
|
||||
|
||||
void wifi_init_inner(){
|
||||
WiFi.disconnect();
|
||||
lv_obj_clean(lv_scr_act());
|
||||
@@ -119,7 +145,7 @@ void wifi_init_inner(){
|
||||
WiFi.begin(global_config.wifi_SSID, global_config.wifi_password);
|
||||
}
|
||||
|
||||
Serial.printf("Connecting to %s with a password length of %d\n", global_config.wifi_SSID, strlen(global_config.wifi_password));
|
||||
LOG_F(("Connecting to %s with a password length of %d\n", global_config.wifi_SSID, strlen(global_config.wifi_password)))
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_scr_act());
|
||||
lv_label_set_text(label, "Connecting to WiFi");
|
||||
@@ -161,6 +187,22 @@ void wifi_init_inner(){
|
||||
lv_obj_set_flex_grow(label, 1);
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(top_row);
|
||||
lv_obj_add_event_cb(btn, wifi_btn_settings, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_MIN_BUTTON_WIDTH_PX, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, LV_SYMBOL_SETTINGS);
|
||||
lv_obj_center(label);
|
||||
|
||||
btn = lv_btn_create(top_row);
|
||||
lv_obj_add_event_cb(btn, wifi_btn_skip_setup, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_MIN_BUTTON_WIDTH_PX * 1.5, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
|
||||
label = lv_label_create(btn);
|
||||
lv_label_set_text(label, "Skip");
|
||||
lv_obj_center(label);
|
||||
|
||||
btn = lv_btn_create(top_row);
|
||||
lv_obj_add_event_cb(btn, wifi_btn_manual_ssid, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_set_size(btn, CYD_SCREEN_MIN_BUTTON_WIDTH_PX, CYD_SCREEN_MIN_BUTTON_HEIGHT_PX);
|
||||
|
||||
@@ -215,24 +257,30 @@ const int print_freq = 1000;
|
||||
int print_timer = 0;
|
||||
|
||||
void wifi_init(){
|
||||
if (global_config.wifi_configuration_skipped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
wifi_init_inner();
|
||||
|
||||
while (!global_config.wifi_configured || WiFi.status() != WL_CONNECTED){
|
||||
while (!global_config.wifi_configuration_skipped && (!global_config.wifi_configured || WiFi.status() != WL_CONNECTED)){
|
||||
if (millis() - print_timer > print_freq){
|
||||
print_timer = millis();
|
||||
Serial.printf("WiFi Status: %s\n", errs[WiFi.status()]);
|
||||
LOG_F(("WiFi Status: %s\n", errs[WiFi.status()]))
|
||||
}
|
||||
|
||||
lv_handler();
|
||||
serial_console::run();
|
||||
}
|
||||
}
|
||||
|
||||
ulong start_time_recovery = 0;
|
||||
|
||||
void wifi_ok(){
|
||||
if (WiFi.status() != WL_CONNECTED){
|
||||
Serial.println("WiFi Connection Lost. Reconnecting...");
|
||||
if (global_config.wifi_configured && WiFi.status() != WL_CONNECTED){
|
||||
LOG_LN("WiFi Connection Lost. Reconnecting...");
|
||||
freeze_request_thread();
|
||||
WiFi.disconnect();
|
||||
delay(5000); // Wait for the WiFi to disconnect
|
||||
@@ -250,9 +298,9 @@ void wifi_ok(){
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED){
|
||||
delay(1000);
|
||||
Serial.printf("WiFi Status: %s\n", errs[WiFi.status()]);
|
||||
LOG_F(("WiFi Status: %s\n", errs[WiFi.status()]))
|
||||
if (millis() - start_time_recovery > 15000){
|
||||
Serial.println("WiFi Connection failed to reconnect. Restarting...");
|
||||
LOG_LN("WiFi Connection failed to reconnect. Restarting...");
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ A ESP32-2432S028R is required to run this project. You can find out where to buy
|
||||
- Execute predefined gcode macros
|
||||
- Toggle Moonraker power devices
|
||||
- OTA updates
|
||||
- Serial console over USB (115200 8n1, echo off, LF/LF)
|
||||
|
||||
### Install
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
TT {
|
||||
font-family: 'Terminal', monospace;
|
||||
background-color: #080a0b;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #181a1b;
|
||||
color: white;
|
||||
@@ -27,7 +32,7 @@
|
||||
color: #F44;
|
||||
}
|
||||
|
||||
.install {
|
||||
.configure {
|
||||
margin-bottom: 300px;
|
||||
}
|
||||
|
||||
@@ -67,7 +72,7 @@
|
||||
<section class="main">
|
||||
<h2>CYD-Klipper <span class="iconify" data-icon="mdi-printer-3d" style="color: #F44;"></span></h2>
|
||||
<p>An implementation of a Klipper status display on an ESP32 + screen.<br>Uses Moonraker to fetch data.<br><a href="https://github.com/suchmememanyskill/CYD-Klipper">Source code is available on GitHub</a>.</p>
|
||||
|
||||
|
||||
<section class="changelog">
|
||||
<h3 id="changelog-header"><span class="iconify" data-icon="mdi-hammer-wrench" style="color: lightgray;"></span> Changelog <span id="changelog-header-version"></span></h3>
|
||||
<p id="changelog-body"></p>
|
||||
@@ -94,8 +99,18 @@
|
||||
<option value="esp32-3248S035C-V">ESP32-3248S035 (3.5" Capacitive) Vertical Orientation</option>
|
||||
<option value="esp32-4827S043C-SD">ESP32-4827S043 (4.3" 480x270 Capacitive)</option>
|
||||
<option value="esp32-8048S043C-SD">ESP32-8048S043 (4.3" 800x480 Capacitive)</option>
|
||||
<option value="esp32-8048S043C-SD-alt">ESP32-8048S043 Alt (4.3" 800x480 Capacitive)</option>
|
||||
<option value="esp32-CROWPANEL-28R">ESP32-CROWPANEL-28R (2.8" Resistive)</option>
|
||||
</select>
|
||||
<span id="install-btn"></span>
|
||||
</section>
|
||||
|
||||
<section class="configure">
|
||||
<h3><span class="iconify" data-icon="mdi-wrench" style="color: cyan; filter: drop-shadow(0 0 0.75rem blue);"></span> Config</h3>
|
||||
<p> After installing CYD-Klipper, you can configure it using its touchscreen, or serial console. To use the serial console,
|
||||
click 'Connect', select the serial port, select "LOGS & CONSOLE" and reset the board without holding BOOT.<br>
|
||||
Type <tt>help</tt> for list of available commands. You're interested in <tt>ssid</tt>, <tt>ip</tt> and <tt>key</tt>. (while you <i>can</i> set <tt>touch</tt>, it's really better done using the touchscreen.)
|
||||
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</body>
|
||||
|
||||
25
ci.py
25
ci.py
@@ -4,12 +4,23 @@ CYD_PORTS = [
|
||||
"esp32-3248S035C",
|
||||
"esp32-2432S028R",
|
||||
"esp32-2432S032C-SD",
|
||||
"esp32-8048S043C-SD",
|
||||
"esp32-8048S043C-SD",
|
||||
"esp32-8048S043C-SD-alt",
|
||||
"esp32-2432S024C-SD",
|
||||
"esp32-4827S043C-SD",
|
||||
"esp32-3248S035C-V",
|
||||
#"esp32-4827S043R-SD",
|
||||
"esp32-CROWPANEL-28R",
|
||||
"esp32-CROWPANEL-35C",
|
||||
]
|
||||
|
||||
ESP_S3_CHIPS = [
|
||||
"esp32-8048S043C-SD",
|
||||
"esp32-8048S043C-SD-alt",
|
||||
"esp32-4827S043C-SD",
|
||||
"esp32-CROWPANEL-35C",
|
||||
]
|
||||
|
||||
BASE_DIR = os.getcwd()
|
||||
|
||||
def get_manifest(base_path : str, device_name : str):
|
||||
@@ -19,7 +30,7 @@ def get_manifest(base_path : str, device_name : str):
|
||||
"new_install_prompt_erase": True,
|
||||
"builds": [
|
||||
{
|
||||
"chipFamily": "ESP32",
|
||||
"chipFamily": "ESP32-S3" if device_name in ESP_S3_CHIPS else "ESP32",
|
||||
"parts": [
|
||||
{
|
||||
"path": f"{base_path}/bootloader.bin",
|
||||
@@ -71,7 +82,10 @@ for port in CYD_PORTS:
|
||||
|
||||
shutil.copy(os.path.join(os.path.expanduser("~"), ".platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin"), f"{port_path}/boot_app0.bin")
|
||||
os.chdir(port_path)
|
||||
subprocess.run(["python3", "-m", "esptool", "--chip", "esp32", "merge_bin", "-o", "merged_firmware.bin", "--flash_mode", "dio", "--flash_freq", "40m", "--flash_size", "4MB", "0x1000", "bootloader.bin", "0x8000", "partitions.bin", "0xe000", "boot_app0.bin", "0x10000", "firmware.bin"], check=True)
|
||||
if (port in ESP_S3_CHIPS):
|
||||
subprocess.run(["python3", "-m", "esptool", "--chip", "esp32s3", "merge_bin", "-o", "merged_firmware.bin", "--flash_mode", "qio", "--flash_freq", "80m", "--flash_size", "16MB", "0x1000", "bootloader.bin", "0x8000", "partitions.bin", "0xe000", "boot_app0.bin", "0x10000", "firmware.bin"], check=True)
|
||||
else:
|
||||
subprocess.run(["python3", "-m", "esptool", "--chip", "esp32", "merge_bin", "-o", "merged_firmware.bin", "--flash_mode", "dio", "--flash_freq", "40m", "--flash_size", "4MB", "0x1000", "bootloader.bin", "0x8000", "partitions.bin", "0xe000", "boot_app0.bin", "0x10000", "firmware.bin"], check=True)
|
||||
|
||||
os.chdir(BASE_DIR)
|
||||
|
||||
@@ -81,7 +95,10 @@ for port in CYD_PORTS:
|
||||
add_configuration(port)
|
||||
|
||||
os.chdir(BASE_DIR)
|
||||
shutil.copytree("./out", "./_site/out")
|
||||
out_dir = "./_site/out"
|
||||
if os.path.exists(out_dir):
|
||||
shutil.rmtree(out_dir)
|
||||
shutil.copytree("./out", out_dir)
|
||||
|
||||
with open("./_site/OTA.json", "w") as f:
|
||||
json.dump({"Configurations": configurations}, f)
|
||||
|
||||
39
serial/README.md
Normal file
39
serial/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Serial connection
|
||||
|
||||
This section elaborates on how the host side (linux) should be set up to handle incoming CYD-Klipper requests.
|
||||
|
||||
## Install (Linux)
|
||||
|
||||
1. Log into your host running klipper
|
||||
1. Cd into a folder where CYD-Klipper will live, for example your home folder
|
||||
- To enter your home folder, type `cd ~`
|
||||
1. `git clone https://github.com/suchmememanyskill/CYD-Klipper`
|
||||
1. `cd CYD-Klipper/serial`
|
||||
1. `chmod a+x install.sh`
|
||||
1. `./install.sh`
|
||||
|
||||
## Uninstall (Linux)
|
||||
1. Log into your host running klipper
|
||||
1. Cd into the folder where CYD-Klipper is installed
|
||||
1. `cd serial`
|
||||
1. `chmod a+x uninstall.sh`
|
||||
1. `./uninstall.sh`
|
||||
|
||||
## Configuration
|
||||
|
||||
The installer creates a systemd service in `~/.config/systemd/user/cyd-klipper-serial.service`. If manual configuration is needed (for example, if moonraker runs on another port or another host, or if the esp32 could not be found), you can edit this file to add environment variables.
|
||||
|
||||
To add an environemnt variable in a systemd unit file, inside the `[Service]` section, write `Environment="KEY=VALUE"`, where KEY is the environemnt variable's name, and VALUE is the environment variable's value.
|
||||
|
||||
After editing the cyd-klipper-serial.service file, run `systemctl --user daemon-reload` then `systemctl --user restart cyd-klipper-serial`
|
||||
|
||||
| Name | Description | Default Value |
|
||||
| --- | --- | --- |
|
||||
|KLIPPER_PROTOCOL|Protocol used. `http` or `https`|`http`|
|
||||
|KLIPPER_HOST|The IP or hostname the Moonraker server runs on|`localhost`|
|
||||
|KLIPPER_PORT|The port of the Moonraker webserver|[`80`, `7125`]|
|
||||
|ESP32_SERIAL|Path to the serial device, like `/dev/ttyUSB0`|None, see below
|
||||
|
||||
By default, a connection to moonraker is attempted to `http://localhost:80` and `http://localhost:7125`. If no connection can be made, the script refuses to continue. The script will indefinitely attempt to re-connect. See the logs generated for more information.
|
||||
|
||||
By default, ESP32 devices are attempted to be located on the system. If too many are located, or none are located, the script refuses to continue. If one is found, an attempt is made to connect to the device. See the logs generated for more information.
|
||||
34
serial/install.sh
Normal file
34
serial/install.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "Please do not run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
chmod a+x ./run.sh
|
||||
|
||||
# Install dependencies
|
||||
python3 -m venv ./env
|
||||
source ./env/bin/activate
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
# Create systemd unit file
|
||||
mkdir -p ~/.config/systemd/user
|
||||
echo "[Unit]" > ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "Description=CYD Klipper serial server" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "After=network.target" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "[Service]" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "ExecStart=$(pwd)/run.sh" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "WorkingDirectory=$(pwd)" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "Restart=always" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "[Install]" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
echo "WantedBy=multi-user.target" >> ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
|
||||
# Start the service
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable cyd-klipper-serial
|
||||
systemctl --user start cyd-klipper-serial
|
||||
2
serial/requirements.txt
Normal file
2
serial/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
pyserial
|
||||
requests
|
||||
4
serial/run.sh
Normal file
4
serial/run.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
source ./env/bin/activate
|
||||
python3 serial_server.py
|
||||
182
serial/serial_server.py
Normal file
182
serial/serial_server.py
Normal file
@@ -0,0 +1,182 @@
|
||||
import serial
|
||||
import requests
|
||||
import os
|
||||
import serial.tools.list_ports
|
||||
import time
|
||||
|
||||
SERIAL_PORT = 'COM6'
|
||||
BAUD_RATE = 115200
|
||||
PROTOCOL = "http"
|
||||
HOSTNAME = 'localhost'
|
||||
PORT = 80
|
||||
|
||||
def test_request(protocol : str, hostname : str, port : int) -> bool:
|
||||
try:
|
||||
print(f"Sending test request to {hostname}:{port}")
|
||||
response = requests.get(f"{protocol}://{hostname}:{port}/printer/info")
|
||||
return response.status_code == 200
|
||||
except requests.exceptions.RequestException:
|
||||
return False
|
||||
|
||||
def find_klipper_host() -> bool:
|
||||
global PROTOCOL, HOSTNAME, PORT
|
||||
|
||||
protocol = PROTOCOL
|
||||
host = HOSTNAME
|
||||
port = PORT
|
||||
|
||||
if "KLIPPER_PROTOCOL" in os.environ:
|
||||
protocol = os.environ["KLIPPER_PROTOCOL"]
|
||||
|
||||
if "KLIPPER_HOST" in os.environ:
|
||||
host = os.environ["KLIPPER_HOST"]
|
||||
|
||||
if "KLIPPER_PORT" in os.environ:
|
||||
port = int(os.environ["KLIPPER_PORT"])
|
||||
|
||||
if test_request(protocol, host, port):
|
||||
HOSTNAME = host
|
||||
PORT = port
|
||||
return True
|
||||
|
||||
port = 80
|
||||
|
||||
if test_request(protocol, host, port):
|
||||
HOSTNAME = host
|
||||
PORT = port
|
||||
return True
|
||||
|
||||
port = 7125
|
||||
|
||||
if test_request(protocol, host, port):
|
||||
HOSTNAME = host
|
||||
PORT = port
|
||||
return True
|
||||
|
||||
print("Could not find Klipper host. Please specify the hostname and port using the KLIPPER_HOST and KLIPPER_PORT environment variables.")
|
||||
return False
|
||||
|
||||
def find_esp32() -> bool:
|
||||
global SERIAL_PORT
|
||||
|
||||
if "ESP32_SERIAL" in os.environ:
|
||||
SERIAL_PORT = os.environ["ESP32_SERIAL"]
|
||||
|
||||
if os.path.exists(SERIAL_PORT):
|
||||
return True
|
||||
else:
|
||||
print(f"Specified serial port {SERIAL_PORT} does not exist.")
|
||||
|
||||
possible_devices = []
|
||||
|
||||
for port in serial.tools.list_ports.comports():
|
||||
if port.vid == 0x10C4 and port.pid == 0xEA60:
|
||||
possible_devices.append(port)
|
||||
elif port.vid == 0x1A86 and port.pid == 0x7523:
|
||||
possible_devices.append(port)
|
||||
|
||||
if len(possible_devices) == 1:
|
||||
SERIAL_PORT = possible_devices[0].device
|
||||
return True
|
||||
elif len(possible_devices) > 1:
|
||||
print("Multiple ESP32 devices found. Please specify the serial port using the ESP32_SERIAL environment variable.")
|
||||
return False
|
||||
else:
|
||||
print("No ESP32 devices found. Please specify the serial port using the ESP32_SERIAL environment variable.")
|
||||
return False
|
||||
|
||||
# --------- #
|
||||
|
||||
ser : serial.Serial = None
|
||||
|
||||
def truncuate(text : str, length : int = 50):
|
||||
length = length - 3
|
||||
if len(text) > length:
|
||||
return text[:length] + "..."
|
||||
return text
|
||||
|
||||
def write(text : str, write : bool):
|
||||
if write:
|
||||
ser.write((text + "\n").encode('utf-8'))
|
||||
print(f"<<< {truncuate(text)}")
|
||||
else:
|
||||
print(f"(Ignored) <<< {truncuate(text)}")
|
||||
|
||||
def main():
|
||||
while True:
|
||||
# Read a line from the serial port
|
||||
line = ser.readline().decode('utf-8').strip()
|
||||
if line.startswith("HTTP_REQUEST") or line.startswith("HTTP_BINARY"):
|
||||
print(f">>> {line}")
|
||||
# Parse the parameters
|
||||
try:
|
||||
parts = line.split(' ', 3)
|
||||
timeout_ms, request_type, url_path = int(parts[1]), parts[2], parts[3]
|
||||
|
||||
ignore_timeout = timeout_ms <= 0
|
||||
binary = line.startswith("HTTP_BINARY")
|
||||
|
||||
if ignore_timeout:
|
||||
timeout_ms = 1000;
|
||||
|
||||
# Construct the full URL
|
||||
full_url = f"{PROTOCOL}://{HOSTNAME}:{PORT}{url_path}"
|
||||
|
||||
# Make the HTTP request based on the type
|
||||
response = None
|
||||
if request_type.upper() == "GET":
|
||||
response = requests.get(full_url, timeout=timeout_ms / 1000)
|
||||
elif request_type.upper() == "POST":
|
||||
response = requests.post(full_url, timeout=timeout_ms / 1000)
|
||||
else:
|
||||
write("400 Unsupported request type", not ignore_timeout)
|
||||
continue
|
||||
|
||||
# Send response back over serial
|
||||
if response != None:
|
||||
if binary:
|
||||
if response.status_code != 200:
|
||||
write("00000000", not ignore_timeout)
|
||||
else:
|
||||
length = len(response.content)
|
||||
ser.write(f"{length:>08}".encode('utf-8'))
|
||||
ser.write(response.content)
|
||||
print(f"<<< (Binary data of {length} bytes)")
|
||||
else:
|
||||
status_code = response.status_code
|
||||
body = response.text.replace('\n', ' ') # Trim and sanitize body for serial
|
||||
message = f"{status_code} {body}"
|
||||
write(message, not ignore_timeout)
|
||||
except (IndexError, ValueError) as e:
|
||||
write(f"400 Malformed request {str(e)}", not ignore_timeout)
|
||||
except requests.exceptions.ReadTimeout as e:
|
||||
print("Request timed out.")
|
||||
pass
|
||||
except requests.exceptions.RequestException as e:
|
||||
write("500 Request failed", not ignore_timeout)
|
||||
else:
|
||||
print(f"[LOG] {line}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
while True:
|
||||
try:
|
||||
if not find_klipper_host():
|
||||
time.sleep(5);
|
||||
continue
|
||||
|
||||
if not find_esp32():
|
||||
time.sleep(5);
|
||||
continue
|
||||
|
||||
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1)
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
print("\nExiting script.")
|
||||
ser.close()
|
||||
break;
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {str(e)}")
|
||||
ser.close()
|
||||
print("Retrying in 5 seconds...")
|
||||
time.sleep(5)
|
||||
|
||||
13
serial/uninstall.sh
Normal file
13
serial/uninstall.sh
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "Please do not run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
systemctl --user stop cyd-klipper-serial
|
||||
systemctl --user disable cyd-klipper-serial
|
||||
|
||||
rm ~/.config/systemd/user/cyd-klipper-serial.service
|
||||
|
||||
systemctl --user daemon-reload
|
||||
6
test_printer/config.json
Normal file
6
test_printer/config.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"instancesDB": "json",
|
||||
"instances": [
|
||||
{ "hostname": "localhost", "port": 7125 }
|
||||
]
|
||||
}
|
||||
14
test_printer/docker-compose.yml
Normal file
14
test_printer/docker-compose.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
printer:
|
||||
container_name: printer
|
||||
ports:
|
||||
- "7125:7125"
|
||||
- "8110:8110"
|
||||
image: ghcr.io/mainsail-crew/virtual-klipper-printer:master
|
||||
webui:
|
||||
container_name: mainsail
|
||||
volumes:
|
||||
- ./config.json:/usr/share/nginx/html/config.json:ro
|
||||
ports:
|
||||
- 6969:80
|
||||
image: ghcr.io/mainsail-crew/mainsail
|
||||
Reference in New Issue
Block a user