Skip to content

Commit

Permalink
Add a hacky screenshot API available in debug mode and update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
Lyrkan committed Apr 30, 2023
1 parent 9da28a8 commit e1ddd4d
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 13 deletions.
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@

<p align="center"><i>Control Panel for K40 laser cutters/engravers</i></p>

[![GitHub license](https://img.shields.io/github/license/Naereen/StrapDown.js.svg)](https://github.com/Lyrkan/K40-Control-Panel/blob/master/LICENSE) ![Build status](https://github.com/Lyrkan/K40-Control-Panel/actions/workflows/build-main.yml/badge.svg) [![GitHub release](https://img.shields.io/github/release/Lyrkan/K40-Control-Panel.svg)](https://github.com/Lyrkan/K40-Control-Panel/releases/)
<p align="center">
<img width="240" height="160" src="images/screenshot-status.jpg">
<img width="240" height="160" src="images/screenshot-controls.jpg">
<img width="240" height="160" src="images/screenshot-bed.jpg">
</p>

<p align="center">
<a title="License" href="https://github.com/Lyrkan/K40-Control-Panel/blob/master/LICENSE"><img src="https://img.shields.io/github/license/Lyrkan/K40-Control-Panel.svg"></a>
<img alt="Build status" src="https://github.com/Lyrkan/K40-Control-Panel/actions/workflows/build-main.yml/badge.svg">
<a title="Last release"><img src="https://img.shields.io/github/release/Lyrkan/K40-Control-Panel.svg"></a>
</p>

## Overview

Expand Down Expand Up @@ -77,3 +87,66 @@ You can also take a `.bin` file and upload it through the ElegantOTA interface a
## Wiring

Coming soon™

## Status API

A status API is available at `http://<YOUR_PANEL_IP>/status`.
It should return a JSON object looking like this:

```json
{
"firmware": {
"version": "9da28a82",
"build_date": "Apr 30 2023 18:31:43"
},
"sensors": {
"voltages": {
"v1": 4.900000095,
"v2": 12.10000038,
"v3": 18
},
"cooling": {
"flow": 5.619999886,
"temp": 18.89999962
},
"lids": {
"front": "opened",
"back": "closed"
},
"flame_sensor": {
"triggered": false
}
},
"alerts": {
"voltages": true,
"cooling": false,
"lids": true,
"flame_sensor": false
},
"relays": {
"laser": false,
"air_assist": true,
"cooling": true,
"alarm": false,
"lights": true,
"beam_preview": true
},
"system": {
"chip": {
"model": "ESP32-D0WDQ5",
"revision": 1
},
"heap": {
"free": 80268,
"total": 257148
},
"cpu": {
"freq_mhz": 240,
"load_percent": {
"core_0": 0,
"core_1": 0.100000001
}
}
}
}
```
Binary file added images/screenshot-bed.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/screenshot-controls.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/screenshot-status.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 6 additions & 4 deletions include/LGFX/LGFX.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#define LGFX_USE_V1
#include <LovyanGFX.hpp>

#include "UI/display.h"

class LGFX : public lgfx::LGFX_Device {

lgfx::Panel_ILI9488 _panel_instance;
Expand Down Expand Up @@ -37,8 +39,8 @@ class LGFX : public lgfx::LGFX_Device {
cfg.pin_cs = 15;
cfg.pin_rst = -1;
cfg.pin_busy = -1;
cfg.panel_width = 320;
cfg.panel_height = 480;
cfg.panel_width = DISPLAY_SCREEN_HEIGHT;
cfg.panel_height = DISPLAY_SCREEN_WIDTH;
cfg.offset_x = 0;
cfg.offset_y = 0;
cfg.offset_rotation = 0;
Expand All @@ -56,9 +58,9 @@ class LGFX : public lgfx::LGFX_Device {
auto cfg = _touch_instance.config();

cfg.x_min = 0;
cfg.x_max = 319;
cfg.x_max = DISPLAY_SCREEN_HEIGHT - 1;
cfg.y_min = 0;
cfg.y_max = 479;
cfg.y_max = DISPLAY_SCREEN_WIDTH - 1;
cfg.pin_int = -1;
cfg.bus_shared = true;
cfg.offset_rotation = 0;
Expand Down
7 changes: 7 additions & 0 deletions include/UI/display.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef UI_DISPLAY_H
#define UI_DISPLAY_H

#define DISPLAY_SCREEN_WIDTH 480
#define DISPLAY_SCREEN_HEIGHT 320

#endif
6 changes: 6 additions & 0 deletions include/api.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#ifndef API_H
#define API_H

#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <ESPAsyncWebServer.h>

#ifdef DEBUG
extern SemaphoreHandle_t api_snapshot_mutex;
#endif

void api_init(AsyncWebServer *server);

#endif
2 changes: 1 addition & 1 deletion src/UI/menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void ui_menu_button_event_handler(lv_event_t *e) {

void ui_menu_init() {
ui_menu_panel = lv_obj_create(lv_layer_top());
lv_obj_set_width(ui_menu_panel, 480);
lv_obj_set_width(ui_menu_panel, lv_pct(100));
lv_obj_set_height(ui_menu_panel, MENU_HEIGHT);
lv_obj_set_style_radius(ui_menu_panel, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(ui_menu_panel, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
Expand Down
75 changes: 75 additions & 0 deletions src/api.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h>
#include <lvgl.h>
#include <math.h>

#include "K40/alerts.h"
#include "K40/cooling.h"
#include "K40/lids.h"
#include "K40/voltage_probes.h"
#include "K40/relays.h"
#include "UI/display.h"
#include "api.h"
#include "cpu_monitor.h"
#include "macros.h"
#include "queues.h"

#ifdef DEBUG
SemaphoreHandle_t api_snapshot_mutex = xSemaphoreCreateMutex();
#endif

void api_init(AsyncWebServer *server) {
server->on("/status", HTTP_GET, [](AsyncWebServerRequest *request) {
DynamicJsonDocument state(1024);
Expand Down Expand Up @@ -100,4 +109,70 @@ void api_init(AsyncWebServer *server) {
serializeJsonPretty(state, serializedState);
request->send(200, "application/json", serializedState);
});

#ifdef DEBUG
server->on("/screenshot", HTTP_GET, [](AsyncWebServerRequest *request) {
lv_obj_t *current_screen = lv_scr_act();

request->sendChunked(
"application/octet-stream",
[current_screen](uint8_t *buffer, size_t max_len, size_t index) -> size_t {
uint8_t bytes_per_pixel = 4;
unsigned int current_pixel_index = index / bytes_per_pixel;
if (current_pixel_index >= DISPLAY_SCREEN_HEIGHT * DISPLAY_SCREEN_WIDTH) {
return 0;
}

unsigned int row = current_pixel_index / DISPLAY_SCREEN_WIDTH;
unsigned int column = (current_pixel_index % DISPLAY_SCREEN_WIDTH);
unsigned int remaining_columns = DISPLAY_SCREEN_WIDTH - column;
unsigned int max_pixels = min(max_len / bytes_per_pixel, remaining_columns);

lv_area_t snapshot_area = {
.x1 = (lv_coord_t)column,
.y1 = (lv_coord_t)row,
.x2 = (lv_coord_t)(column + max_pixels - 1),
.y2 = (lv_coord_t)row,
};

lv_disp_t *obj_disp = lv_obj_get_disp(current_screen);
lv_disp_drv_t driver;
lv_disp_drv_init(&driver);

driver.hor_res = lv_disp_get_hor_res(obj_disp);
driver.ver_res = lv_disp_get_hor_res(obj_disp);
lv_disp_drv_use_generic_set_px_cb(&driver, LV_IMG_CF_TRUE_COLOR_ALPHA);

lv_disp_t fake_disp;
lv_memset_00(&fake_disp, sizeof(lv_disp_t));
fake_disp.driver = &driver;

lv_draw_ctx_t *draw_ctx = (lv_draw_ctx_t *)lv_mem_alloc(obj_disp->driver->draw_ctx_size);
if (draw_ctx == NULL)
return 0;

obj_disp->driver->draw_ctx_init(fake_disp.driver, draw_ctx);
fake_disp.driver->draw_ctx = draw_ctx;
draw_ctx->clip_area = &snapshot_area;
draw_ctx->buf_area = &snapshot_area;
draw_ctx->buf = (void *)buffer;
driver.draw_ctx = draw_ctx;

xSemaphoreTake(api_snapshot_mutex, portMAX_DELAY);
lv_disp_t *refr_ori = _lv_refr_get_disp_refreshing();
_lv_refr_set_disp_refreshing(&fake_disp);

lv_obj_redraw(draw_ctx, current_screen);
lv_obj_redraw(draw_ctx, lv_layer_top());
lv_obj_redraw(draw_ctx, lv_layer_sys());

_lv_refr_set_disp_refreshing(refr_ori);
obj_disp->driver->draw_ctx_deinit(fake_disp.driver, draw_ctx);
lv_mem_free(draw_ctx);
xSemaphoreGive(api_snapshot_mutex);

return max_pixels * bytes_per_pixel;
});
});
#endif
}
21 changes: 14 additions & 7 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
#include "K40/relays.h"
#include "K40/voltage_probes.h"
#include "UI/screens/status.h"
#include "UI/display.h"
#include "UI/ui.h"
#include "api.h"
#include "cpu_monitor.h"
#include "settings.h"
#include "wifi.h"

#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320

static AsyncWebServer server(80);
static LGFX tft;
static uint16_t touch_calibration_data[] = {274, 3922, 312, 255, 3845, 3918, 3814, 242};
Expand Down Expand Up @@ -112,7 +110,7 @@ void setup() {
Serial.begin(115200);

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[SCREEN_WIDTH * 10];
static lv_color_t buf[DISPLAY_SCREEN_WIDTH * 10];
static lv_disp_drv_t disp_drv;
static lv_indev_drv_t indev_drv;

Expand All @@ -126,10 +124,10 @@ void setup() {
tft.setColorDepth(24);

lv_init();
lv_disp_draw_buf_init(&draw_buf, buf, NULL, SCREEN_WIDTH * 10);
lv_disp_draw_buf_init(&draw_buf, buf, NULL, DISPLAY_SCREEN_WIDTH * 10);
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = SCREEN_WIDTH;
disp_drv.ver_res = SCREEN_HEIGHT;
disp_drv.hor_res = DISPLAY_SCREEN_WIDTH;
disp_drv.ver_res = DISPLAY_SCREEN_HEIGHT;
disp_drv.flush_cb = display_flush_cb;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
Expand Down Expand Up @@ -211,7 +209,16 @@ void setup() {
* UI update loop
*/
void loop() {
#ifdef DEBUG
xSemaphoreTake(api_snapshot_mutex, portMAX_DELAY);
#endif

ui_update();
lv_timer_handler();

#ifdef DEBUG
xSemaphoreGive(api_snapshot_mutex);
#endif

delay(5);
}

0 comments on commit e1ddd4d

Please sign in to comment.