Прошло 2 года.
This commit is contained in:
4
lib/epdiy/examples/calibration_helper/CMakeLists.txt
Normal file
4
lib/epdiy/examples/calibration_helper/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(vcom_calibration_helper)
|
||||
@@ -0,0 +1,3 @@
|
||||
set(app_sources "main.c")
|
||||
|
||||
idf_component_register(SRCS ${app_sources} REQUIRES epdiy)
|
||||
42
lib/epdiy/examples/calibration_helper/main/main.c
Normal file
42
lib/epdiy/examples/calibration_helper/main/main.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Simple helper program enabling EPD power to allow for easier VCOM calibration.
|
||||
*
|
||||
* This is only needed for boards V5 or lower!
|
||||
**/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "epdiy.h"
|
||||
|
||||
// choose the default demo board depending on the architecture
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define DEMO_BOARD epd_board_v6
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define DEMO_BOARD epd_board_v7
|
||||
#endif
|
||||
|
||||
void enable_vcom() {
|
||||
epd_init(&DEMO_BOARD, &ED097TC2, EPD_LUT_64K);
|
||||
ESP_LOGI("main", "waiting for one second before poweron...");
|
||||
vTaskDelay(1000);
|
||||
ESP_LOGI("main", "enabling VCOMM...");
|
||||
epd_poweron();
|
||||
ESP_LOGI(
|
||||
"main",
|
||||
"VCOMM enabled. You can now adjust the on-board trimmer to the VCOM value specified on the "
|
||||
"display."
|
||||
);
|
||||
while (1) {
|
||||
vTaskDelay(1000);
|
||||
};
|
||||
}
|
||||
|
||||
void app_main() {
|
||||
enable_vcom();
|
||||
}
|
||||
1500
lib/epdiy/examples/calibration_helper/sdkconfig.defaults.esp32
Normal file
1500
lib/epdiy/examples/calibration_helper/sdkconfig.defaults.esp32
Normal file
File diff suppressed because it is too large
Load Diff
1455
lib/epdiy/examples/calibration_helper/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/calibration_helper/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
4
lib/epdiy/examples/demo/CMakeLists.txt
Normal file
4
lib/epdiy/examples/demo/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(firmware)
|
||||
21
lib/epdiy/examples/demo/Makefile
Normal file
21
lib/epdiy/examples/demo/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
FONT_DIR ?= /usr/share/fonts/TTF
|
||||
FONTCONVERT ?= ../../scripts/fontconvert.py
|
||||
IMGCONVERT ?= ../../scripts/imgconvert.py
|
||||
|
||||
.PHONY: fonts
|
||||
fonts: \
|
||||
main/firasans_20.h \
|
||||
main/firasans_12.h \
|
||||
main/img_zebra.h \
|
||||
main/img_board.h \
|
||||
main/img_giraffe.h \
|
||||
main/img_beach.h
|
||||
|
||||
main/firasans_%.h: $(FONTCONVERT)
|
||||
python3 $(FONTCONVERT) --compress FiraSans_$* $* $(FONT_DIR)/FiraSans-Regular.ttf $(FONT_DIR)/Symbola.ttf > $@
|
||||
|
||||
main/img_%.h: files/%.jpg
|
||||
python3 $(IMGCONVERT) -i $< -o $@ -n img_$*
|
||||
|
||||
clean:
|
||||
rm main/*.h
|
||||
BIN
lib/epdiy/examples/demo/files/beach.jpg
Normal file
BIN
lib/epdiy/examples/demo/files/beach.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
BIN
lib/epdiy/examples/demo/files/board.jpg
Normal file
BIN
lib/epdiy/examples/demo/files/board.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
BIN
lib/epdiy/examples/demo/files/giraffe.jpg
Normal file
BIN
lib/epdiy/examples/demo/files/giraffe.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
BIN
lib/epdiy/examples/demo/files/zebra.jpg
Normal file
BIN
lib/epdiy/examples/demo/files/zebra.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
4
lib/epdiy/examples/demo/main/CMakeLists.txt
Normal file
4
lib/epdiy/examples/demo/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(app_sources "main.c")
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
idf_component_register(SRCS ${app_sources} REQUIRES epdiy)
|
||||
8087
lib/epdiy/examples/demo/main/firasans_12.h
Normal file
8087
lib/epdiy/examples/demo/main/firasans_12.h
Normal file
File diff suppressed because it is too large
Load Diff
13383
lib/epdiy/examples/demo/main/firasans_20.h
Normal file
13383
lib/epdiy/examples/demo/main/firasans_20.h
Normal file
File diff suppressed because it is too large
Load Diff
11254
lib/epdiy/examples/demo/main/img_beach.h
Normal file
11254
lib/epdiy/examples/demo/main/img_beach.h
Normal file
File diff suppressed because it is too large
Load Diff
8667
lib/epdiy/examples/demo/main/img_board.h
Normal file
8667
lib/epdiy/examples/demo/main/img_board.h
Normal file
File diff suppressed because it is too large
Load Diff
9214
lib/epdiy/examples/demo/main/img_zebra.h
Normal file
9214
lib/epdiy/examples/demo/main/img_zebra.h
Normal file
File diff suppressed because it is too large
Load Diff
271
lib/epdiy/examples/demo/main/main.c
Normal file
271
lib/epdiy/examples/demo/main/main.c
Normal file
@@ -0,0 +1,271 @@
|
||||
/* Simple firmware for a ESP32 displaying a static image on an EPaper Screen.
|
||||
*
|
||||
* Write an image into a header file using a 3...2...1...0 format per pixel,
|
||||
* for 4 bits color (16 colors - well, greys.) MSB first. At 80 MHz, screen
|
||||
* clears execute in 1.075 seconds and images are drawn in 1.531 seconds.
|
||||
*/
|
||||
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_sleep.h>
|
||||
#include <esp_timer.h>
|
||||
#include <esp_types.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <epdiy.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "firasans_12.h"
|
||||
#include "firasans_20.h"
|
||||
#include "img_beach.h"
|
||||
#include "img_board.h"
|
||||
#include "img_zebra.h"
|
||||
|
||||
#define WAVEFORM EPD_BUILTIN_WAVEFORM
|
||||
|
||||
// choose the default demo board depending on the architecture
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define DEMO_BOARD epd_board_v6
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define DEMO_BOARD epd_board_v7
|
||||
#endif
|
||||
|
||||
EpdiyHighlevelState hl;
|
||||
|
||||
void idf_setup() {
|
||||
epd_init(&DEMO_BOARD, &ED097TC2, EPD_LUT_64K);
|
||||
// Set VCOM for boards that allow to set this in software (in mV).
|
||||
// This will print an error if unsupported. In this case,
|
||||
// set VCOM using the hardware potentiometer and delete this line.
|
||||
epd_set_vcom(1560);
|
||||
|
||||
hl = epd_hl_init(WAVEFORM);
|
||||
|
||||
// Default orientation is EPD_ROT_LANDSCAPE
|
||||
epd_set_rotation(EPD_ROT_LANDSCAPE);
|
||||
|
||||
printf(
|
||||
"Dimensions after rotation, width: %d height: %d\n\n",
|
||||
epd_rotated_display_width(),
|
||||
epd_rotated_display_height()
|
||||
);
|
||||
|
||||
// The display bus settings for V7 may be conservative, you can manually
|
||||
// override the bus speed to tune for speed, i.e., if you set the PSRAM speed
|
||||
// to 120MHz.
|
||||
// epd_set_lcd_pixel_clock_MHz(17);
|
||||
|
||||
heap_caps_print_heap_info(MALLOC_CAP_INTERNAL);
|
||||
heap_caps_print_heap_info(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
void delay(uint32_t millis) {
|
||||
vTaskDelay(millis / portTICK_PERIOD_MS);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void checkError(enum EpdDrawError err) {
|
||||
if (err != EPD_DRAW_SUCCESS) {
|
||||
ESP_LOGE("demo", "draw error: %X", err);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_progress_bar(int x, int y, int width, int percent, uint8_t* fb) {
|
||||
const uint8_t white = 0xFF;
|
||||
const uint8_t black = 0x0;
|
||||
|
||||
EpdRect border = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = 20,
|
||||
};
|
||||
epd_fill_rect(border, white, fb);
|
||||
epd_draw_rect(border, black, fb);
|
||||
|
||||
EpdRect bar = {
|
||||
.x = x + 5,
|
||||
.y = y + 5,
|
||||
.width = (width - 10) * percent / 100,
|
||||
.height = 10,
|
||||
};
|
||||
|
||||
epd_fill_rect(bar, black, fb);
|
||||
|
||||
checkError(epd_hl_update_area(&hl, MODE_DU, epd_ambient_temperature(), border));
|
||||
}
|
||||
|
||||
void idf_loop() {
|
||||
// select the font based on display width
|
||||
const EpdFont* font;
|
||||
if (epd_width() < 1000) {
|
||||
font = &FiraSans_12;
|
||||
} else {
|
||||
font = &FiraSans_20;
|
||||
}
|
||||
|
||||
uint8_t* fb = epd_hl_get_framebuffer(&hl);
|
||||
|
||||
epd_poweron();
|
||||
epd_clear();
|
||||
int temperature = epd_ambient_temperature();
|
||||
epd_poweroff();
|
||||
|
||||
printf("current temperature: %d\n", temperature);
|
||||
|
||||
epd_fill_circle(30, 30, 15, 0, fb);
|
||||
int cursor_x = epd_rotated_display_width() / 2;
|
||||
int cursor_y = epd_rotated_display_height() / 2 - 100;
|
||||
|
||||
EpdFontProperties font_props = epd_font_properties_default();
|
||||
font_props.flags = EPD_DRAW_ALIGN_CENTER;
|
||||
|
||||
char srotation[32];
|
||||
sprintf(srotation, "Loading demo...\nRotation: %d", epd_get_rotation());
|
||||
|
||||
epd_write_string(font, srotation, &cursor_x, &cursor_y, fb, &font_props);
|
||||
|
||||
int bar_x = epd_rotated_display_width() / 2 - 200;
|
||||
int bar_y = epd_rotated_display_height() / 2;
|
||||
|
||||
epd_poweron();
|
||||
checkError(epd_hl_update_screen(&hl, MODE_GL16, temperature));
|
||||
epd_poweroff();
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
epd_poweron();
|
||||
draw_progress_bar(bar_x, bar_y, 400, i * 10, fb);
|
||||
epd_poweroff();
|
||||
}
|
||||
|
||||
cursor_x = epd_rotated_display_width() / 2;
|
||||
cursor_y = epd_rotated_display_height() / 2 + 100;
|
||||
|
||||
epd_write_string(
|
||||
font, "Just kidding,\n this is a demo animation 😉", &cursor_x, &cursor_y, fb, &font_props
|
||||
);
|
||||
epd_poweron();
|
||||
checkError(epd_hl_update_screen(&hl, MODE_GL16, temperature));
|
||||
epd_poweroff();
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
epd_poweron();
|
||||
draw_progress_bar(bar_x, bar_y, 400, 50 - i * 10, fb);
|
||||
epd_poweroff();
|
||||
vTaskDelay(1);
|
||||
}
|
||||
|
||||
cursor_y = epd_rotated_display_height() / 2 + 200;
|
||||
cursor_x = epd_rotated_display_width() / 2;
|
||||
|
||||
EpdRect clear_area = {
|
||||
.x = 0,
|
||||
.y = epd_rotated_display_height() / 2 + 100,
|
||||
.width = epd_rotated_display_width(),
|
||||
.height = 300,
|
||||
};
|
||||
|
||||
epd_fill_rect(clear_area, 0xFF, fb);
|
||||
|
||||
epd_write_string(
|
||||
font, "Now let's look at some pictures.", &cursor_x, &cursor_y, fb, &font_props
|
||||
);
|
||||
epd_poweron();
|
||||
checkError(epd_hl_update_screen(&hl, MODE_GL16, temperature));
|
||||
epd_poweroff();
|
||||
|
||||
delay(1000);
|
||||
|
||||
epd_hl_set_all_white(&hl);
|
||||
|
||||
EpdRect zebra_area = {
|
||||
.x = epd_rotated_display_width() / 2 - img_zebra_width / 2,
|
||||
.y = epd_rotated_display_height() / 2 - img_zebra_height / 2,
|
||||
.width = img_zebra_width,
|
||||
.height = img_zebra_height,
|
||||
};
|
||||
|
||||
epd_draw_rotated_image(zebra_area, img_zebra_data, fb);
|
||||
epd_poweron();
|
||||
checkError(epd_hl_update_screen(&hl, MODE_GC16, temperature));
|
||||
epd_poweroff();
|
||||
|
||||
delay(5000);
|
||||
|
||||
EpdRect board_area = {
|
||||
.x = epd_rotated_display_width() / 2 - img_board_width / 2,
|
||||
.y = epd_rotated_display_height() / 2 - img_board_height / 2,
|
||||
.width = img_board_width,
|
||||
.height = img_board_height,
|
||||
};
|
||||
|
||||
epd_draw_rotated_image(board_area, img_board_data, fb);
|
||||
cursor_x = epd_rotated_display_width() / 2;
|
||||
cursor_y = board_area.y;
|
||||
font_props.flags |= EPD_DRAW_BACKGROUND;
|
||||
epd_write_string(font, "↓ Thats the V2 board. ↓", &cursor_x, &cursor_y, fb, &font_props);
|
||||
|
||||
epd_poweron();
|
||||
checkError(epd_hl_update_screen(&hl, MODE_GC16, temperature));
|
||||
epd_poweroff();
|
||||
|
||||
delay(5000);
|
||||
epd_hl_set_all_white(&hl);
|
||||
|
||||
EpdRect border_rect = {
|
||||
.x = 20,
|
||||
.y = 20,
|
||||
.width = epd_rotated_display_width() - 40,
|
||||
.height = epd_rotated_display_height() - 40,
|
||||
};
|
||||
epd_draw_rect(border_rect, 0, fb);
|
||||
|
||||
cursor_x = 50;
|
||||
cursor_y = 100;
|
||||
|
||||
epd_write_default(
|
||||
font,
|
||||
"➸ 16 color grayscale\n"
|
||||
"➸ ~250ms - 1700ms for full frame draw 🚀\n"
|
||||
"➸ Use with 6\" or 9.7\" EPDs\n"
|
||||
"➸ High-quality font rendering ✎🙋\n"
|
||||
"➸ Partial update\n"
|
||||
"➸ Arbitrary transitions with vendor waveforms",
|
||||
&cursor_x,
|
||||
&cursor_y,
|
||||
fb
|
||||
);
|
||||
|
||||
EpdRect img_beach_area = {
|
||||
.x = 0,
|
||||
.y = epd_rotated_display_height() - img_beach_height,
|
||||
.width = img_beach_width,
|
||||
.height = img_beach_height,
|
||||
};
|
||||
|
||||
epd_draw_rotated_image(img_beach_area, img_beach_data, fb);
|
||||
|
||||
epd_poweron();
|
||||
checkError(epd_hl_update_screen(&hl, MODE_GC16, temperature));
|
||||
epd_poweroff();
|
||||
|
||||
printf("going to sleep...\n");
|
||||
epd_deinit();
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
void app_main() {
|
||||
idf_setup();
|
||||
|
||||
while (1) {
|
||||
idf_loop();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
30
lib/epdiy/examples/demo/main/main.ino
Normal file
30
lib/epdiy/examples/demo/main/main.ino
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* This is the Arduino wrapper for the "Demo" example.
|
||||
* Please go to the main.c for the main example file.
|
||||
*
|
||||
* This example was developed for the ESP IoT Development Framework (IDF).
|
||||
* You can still use this code in the Arduino IDE, but it may not look
|
||||
* and feel like a classic Arduino sketch.
|
||||
* If you are looking for an example with Arduino look-and-feel,
|
||||
* please check the other examples.
|
||||
*/
|
||||
|
||||
// Important: These are C functions, so they must be declared with C linkage!
|
||||
extern "C" {
|
||||
void idf_setup();
|
||||
void idf_loop();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
if (psramInit()) {
|
||||
Serial.println("\nThe PSRAM is correctly initialized");
|
||||
} else {
|
||||
Serial.println("\nPSRAM does not work");
|
||||
}
|
||||
|
||||
idf_setup();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
idf_loop();
|
||||
}
|
||||
0
lib/epdiy/examples/demo/sdkconfig.defaults
Normal file
0
lib/epdiy/examples/demo/sdkconfig.defaults
Normal file
1500
lib/epdiy/examples/demo/sdkconfig.defaults.esp32
Normal file
1500
lib/epdiy/examples/demo/sdkconfig.defaults.esp32
Normal file
File diff suppressed because it is too large
Load Diff
1455
lib/epdiy/examples/demo/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/demo/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
4
lib/epdiy/examples/dragon/CMakeLists.txt
Normal file
4
lib/epdiy/examples/dragon/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(dragon_example)
|
||||
7
lib/epdiy/examples/dragon/README.md
Normal file
7
lib/epdiy/examples/dragon/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
A demo showing a Full-Screen Image
|
||||
==================================
|
||||
|
||||
*The image size is chosen to fit a 1200 * 825 display!*
|
||||
|
||||
Image by David REVOY / CC BY (https://creativecommons.org/licenses/by/3.0)
|
||||
https://commons.wikimedia.org/wiki/File:Durian_-_Sintel-wallpaper-dragon.jpg
|
||||
BIN
lib/epdiy/examples/dragon/cc_dragon.jpg
Normal file
BIN
lib/epdiy/examples/dragon/cc_dragon.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 212 KiB |
3
lib/epdiy/examples/dragon/main/CMakeLists.txt
Normal file
3
lib/epdiy/examples/dragon/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
set(app_sources "main.c")
|
||||
|
||||
idf_component_register(SRCS ${app_sources} REQUIRES epdiy)
|
||||
30942
lib/epdiy/examples/dragon/main/dragon.h
Normal file
30942
lib/epdiy/examples/dragon/main/dragon.h
Normal file
File diff suppressed because it is too large
Load Diff
50
lib/epdiy/examples/dragon/main/main.c
Normal file
50
lib/epdiy/examples/dragon/main/main.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Simple firmware for a ESP32 displaying a static image on an EPaper Screen */
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "dragon.h"
|
||||
#include "epd_highlevel.h"
|
||||
#include "epdiy.h"
|
||||
|
||||
EpdiyHighlevelState hl;
|
||||
|
||||
// choose the default demo board depending on the architecture
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define DEMO_BOARD epd_board_v6
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define DEMO_BOARD epd_board_v7
|
||||
#endif
|
||||
|
||||
void idf_loop() {
|
||||
EpdRect dragon_area = { .x = 0, .y = 0, .width = dragon_width, .height = dragon_height };
|
||||
|
||||
int temperature = 25;
|
||||
|
||||
epd_poweron();
|
||||
epd_fullclear(&hl, temperature);
|
||||
|
||||
epd_copy_to_framebuffer(dragon_area, dragon_data, epd_hl_get_framebuffer(&hl));
|
||||
|
||||
enum EpdDrawError _err = epd_hl_update_screen(&hl, MODE_GC16, temperature);
|
||||
epd_poweroff();
|
||||
|
||||
vTaskDelay(1000);
|
||||
}
|
||||
|
||||
void idf_setup() {
|
||||
epd_init(&DEMO_BOARD, &ED097TC2, EPD_LUT_64K);
|
||||
epd_set_vcom(1560);
|
||||
hl = epd_hl_init(EPD_BUILTIN_WAVEFORM);
|
||||
}
|
||||
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
void app_main() {
|
||||
idf_setup();
|
||||
|
||||
while (1) {
|
||||
idf_loop();
|
||||
};
|
||||
}
|
||||
#endif
|
||||
30
lib/epdiy/examples/dragon/main/main.ino
Normal file
30
lib/epdiy/examples/dragon/main/main.ino
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* This is the Arduino wrapper for the "Demo" example.
|
||||
* Please go to the main.c for the main example file.
|
||||
*
|
||||
* This example was developed for the ESP IoT Development Framework (IDF).
|
||||
* You can still use this code in the Arduino IDE, but it may not look
|
||||
* and feel like a classic Arduino sketch.
|
||||
* If you are looking for an example with Arduino look-and-feel,
|
||||
* please check the other examples.
|
||||
*/
|
||||
|
||||
// Important: These are C functions, so they must be declared with C linkage!
|
||||
extern "C" {
|
||||
void idf_setup();
|
||||
void idf_loop();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
if (psramInit()) {
|
||||
Serial.println("\nThe PSRAM is correctly initialized");
|
||||
} else {
|
||||
Serial.println("\nPSRAM does not work");
|
||||
}
|
||||
|
||||
idf_setup();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
idf_loop();
|
||||
}
|
||||
0
lib/epdiy/examples/dragon/sdkconfig.defaults
Normal file
0
lib/epdiy/examples/dragon/sdkconfig.defaults
Normal file
1500
lib/epdiy/examples/dragon/sdkconfig.defaults.esp32
Normal file
1500
lib/epdiy/examples/dragon/sdkconfig.defaults.esp32
Normal file
File diff suppressed because it is too large
Load Diff
1455
lib/epdiy/examples/dragon/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/dragon/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
4
lib/epdiy/examples/fb_mode_test/CMakeLists.txt
Normal file
4
lib/epdiy/examples/fb_mode_test/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.10.0)
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(firmware)
|
||||
4
lib/epdiy/examples/fb_mode_test/main/CMakeLists.txt
Normal file
4
lib/epdiy/examples/fb_mode_test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
set(app_sources "main.c")
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
idf_component_register(SRCS ${app_sources} REQUIRES epdiy)
|
||||
223
lib/epdiy/examples/fb_mode_test/main/main.c
Normal file
223
lib/epdiy/examples/fb_mode_test/main/main.c
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Visual tests for framebuffer modes that are not commonly used by the high-level API.
|
||||
* Currently, includes 2 pixel per byte (ppB) with static origin color and 8ppB with static origin
|
||||
* color.
|
||||
*
|
||||
* After running this, you should see two identical test images, with a "ladder" of black triangles
|
||||
* next to a black rectangle with a ladder of white triangles on it.
|
||||
*/
|
||||
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_sleep.h>
|
||||
#include <esp_timer.h>
|
||||
#include <esp_types.h>
|
||||
#include <esp_assert.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <epdiy.h>
|
||||
|
||||
#include "epd_display.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define WAVEFORM EPD_BUILTIN_WAVEFORM
|
||||
|
||||
// choose the default demo board depending on the architecture
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define DEMO_BOARD epd_board_v6
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define DEMO_BOARD epd_board_v7
|
||||
#endif
|
||||
|
||||
// Singular framebuffer to use for all of the tests.
|
||||
// Allocated for 2ppB, the least compact that we test here.
|
||||
uint8_t* framebuffer;
|
||||
int fb_size;
|
||||
|
||||
static inline void checkError(enum EpdDrawError err) {
|
||||
if (err != EPD_DRAW_SUCCESS) {
|
||||
ESP_LOGE("demo", "draw error: %X", err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the screen to white and resets the framebuffer.
|
||||
*/
|
||||
void clear() {
|
||||
epd_poweron();
|
||||
epd_clear();
|
||||
epd_poweroff();
|
||||
memset(framebuffer, 0xFF, fb_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear an example area on the screen to white, does not reset the framebuffer.
|
||||
*/
|
||||
void clear_area(EpdRect clear_area) {
|
||||
epd_poweron();
|
||||
epd_clear_area(clear_area);
|
||||
epd_poweroff();
|
||||
memset(framebuffer, 0xFF, fb_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw triangles at varying alignments into the framebuffer in 8ppB mode.
|
||||
* start_line, start_column specify the start position.
|
||||
* The bits that belong to a triangle are flipped, i.e., it is drawn at the
|
||||
* inverse color to the background it is drawn onto.
|
||||
*/
|
||||
void draw_8bpp_triangles(int start_line, int start_column) {
|
||||
start_column /= 8;
|
||||
int line_bytes = epd_width() / 8;
|
||||
|
||||
for (int align = 0; align < 16; align++) {
|
||||
for (int height = 0; height < 16; height++) {
|
||||
for (int len = 0; len <= height; len++) {
|
||||
int line = (start_line + 16 * align + height);
|
||||
int column = align + len;
|
||||
uint8_t* line_address = framebuffer + (line_bytes * line);
|
||||
*(line_address + start_column + column / 8) ^= 1 << (column % 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw triangles at varying alignments into the framebuffer in 2ppB mode.
|
||||
* start_line, start_column specify the start position.
|
||||
* color specifies the color to draw in.
|
||||
*/
|
||||
void draw_2bpp_triangles(int start_line, int start_column, uint8_t color) {
|
||||
int height = 16;
|
||||
|
||||
for (int align = 0; align < 16; align++) {
|
||||
int x0 = start_column + align;
|
||||
int y0 = start_line + height * align;
|
||||
int x1 = x0;
|
||||
int y1 = y0 + height - 1;
|
||||
int x2 = x0 + height - 1;
|
||||
int y2 = y0 + height - 1;
|
||||
|
||||
epd_fill_triangle(x0, y0, x1, y1, x2, y2, color, framebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void test_8ppB() {
|
||||
EpdRect area = epd_full_screen();
|
||||
enum EpdDrawMode mode;
|
||||
|
||||
// bytes in a line in 8ppB mode
|
||||
int line_bytes = epd_width() / 8;
|
||||
|
||||
int start_line = 100;
|
||||
|
||||
// draw differently aligned black triangles to check for uniformity
|
||||
draw_8bpp_triangles(start_line, 80);
|
||||
|
||||
int black_start_column = 160;
|
||||
|
||||
// draw a black area
|
||||
for (int line = 0; line < 300; line++) {
|
||||
uint8_t* line_address = framebuffer + (line_bytes * (start_line + line));
|
||||
memset(line_address + black_start_column / 8, 0, 32);
|
||||
}
|
||||
|
||||
// update the display. In the first update, white pixels are no-opps,
|
||||
// in the second update, black pixels are no-ops.
|
||||
epd_poweron();
|
||||
mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_WHITE;
|
||||
checkError(epd_draw_base(area, framebuffer, area, mode, 25, NULL, NULL, &epdiy_ED047TC2));
|
||||
epd_poweroff();
|
||||
|
||||
// draw white triangles on the black background
|
||||
draw_8bpp_triangles(start_line, black_start_column + 16);
|
||||
|
||||
epd_poweron();
|
||||
mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_BLACK;
|
||||
checkError(epd_draw_base(area, framebuffer, area, mode, 25, NULL, NULL, &epdiy_ED047TC2));
|
||||
epd_poweroff();
|
||||
}
|
||||
|
||||
void test_2ppB() {
|
||||
EpdRect area = epd_full_screen();
|
||||
enum EpdDrawMode mode;
|
||||
int start_column = 500;
|
||||
int start_line = 100;
|
||||
|
||||
// draw differently aligned black triangles to check for uniformity
|
||||
draw_2bpp_triangles(start_line, start_column, 0);
|
||||
|
||||
int black_start_column = start_column + 60;
|
||||
|
||||
// draw a black area
|
||||
EpdRect black_area = { .x = black_start_column, .y = 100, .width = 256, .height = 300 };
|
||||
epd_fill_rect(black_area, 0, framebuffer);
|
||||
|
||||
// Do not overdraw the 8ppB image
|
||||
uint8_t* drawn_columns = malloc(epd_width() / 2);
|
||||
assert(drawn_columns != NULL);
|
||||
memset(drawn_columns, 0, epd_width() / 2);
|
||||
memset(drawn_columns + start_column / 2, 255, (epd_width() - start_column) / 2);
|
||||
|
||||
// update the display. In the first update, white pixels are no-opps,
|
||||
// in the second update, black pixels are no-ops.
|
||||
epd_poweron();
|
||||
mode = MODE_PACKING_2PPB | MODE_DU | PREVIOUSLY_WHITE;
|
||||
checkError(
|
||||
epd_draw_base(area, framebuffer, area, mode, 25, NULL, drawn_columns, &epdiy_ED047TC2)
|
||||
);
|
||||
epd_poweroff();
|
||||
|
||||
// draw white triangles on the black background
|
||||
draw_2bpp_triangles(start_line, black_start_column + 16, 255);
|
||||
|
||||
epd_poweron();
|
||||
mode = MODE_PACKING_2PPB | MODE_DU | PREVIOUSLY_BLACK;
|
||||
checkError(
|
||||
epd_draw_base(area, framebuffer, area, mode, 25, NULL, drawn_columns, &epdiy_ED047TC2)
|
||||
);
|
||||
epd_poweroff();
|
||||
|
||||
free(drawn_columns);
|
||||
}
|
||||
|
||||
void app_main() {
|
||||
epd_init(&DEMO_BOARD, &ED060XC3, EPD_OPTIONS_DEFAULT);
|
||||
|
||||
// Set VCOM for boards that allow to set this in software (in mV).
|
||||
// This will print an error if unsupported. In this case,
|
||||
// set VCOM using the hardware potentiometer and delete this line.
|
||||
epd_set_vcom(2100);
|
||||
|
||||
epd_set_lcd_pixel_clock_MHz(10);
|
||||
|
||||
fb_size = epd_width() * epd_height() / 2;
|
||||
framebuffer = heap_caps_aligned_alloc(16, fb_size, MALLOC_CAP_SPIRAM);
|
||||
|
||||
clear();
|
||||
|
||||
test_8ppB();
|
||||
|
||||
memset(framebuffer, 0xFF, fb_size);
|
||||
|
||||
test_2ppB();
|
||||
|
||||
// Clear at different positions
|
||||
EpdRect area = { .x = 100, .y = epd_height() - 200, .width = 80, .height = 100 };
|
||||
clear_area(area);
|
||||
area.width += 1;
|
||||
area.x += 100;
|
||||
clear_area(area);
|
||||
area.x += 101;
|
||||
clear_area(area);
|
||||
|
||||
printf("going to sleep...\n");
|
||||
epd_deinit();
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
0
lib/epdiy/examples/fb_mode_test/sdkconfig.defaults
Normal file
0
lib/epdiy/examples/fb_mode_test/sdkconfig.defaults
Normal file
1500
lib/epdiy/examples/fb_mode_test/sdkconfig.defaults.esp32
Normal file
1500
lib/epdiy/examples/fb_mode_test/sdkconfig.defaults.esp32
Normal file
File diff suppressed because it is too large
Load Diff
1455
lib/epdiy/examples/fb_mode_test/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/fb_mode_test/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
4
lib/epdiy/examples/grayscale_test/CMakeLists.txt
Normal file
4
lib/epdiy/examples/grayscale_test/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(grayscale_example)
|
||||
3
lib/epdiy/examples/grayscale_test/main/CMakeLists.txt
Normal file
3
lib/epdiy/examples/grayscale_test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
set(app_sources "main.c")
|
||||
|
||||
idf_component_register(SRCS ${app_sources} REQUIRES epdiy)
|
||||
81
lib/epdiy/examples/grayscale_test/main/main.c
Normal file
81
lib/epdiy/examples/grayscale_test/main/main.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Test program for displaying a grayscale pattern.
|
||||
*
|
||||
* Use this to calibrate grayscale timings for new displays or test alternative waveforms.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "epd_highlevel.h"
|
||||
#include "epdiy.h"
|
||||
|
||||
// choose the default demo board depending on the architecture
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define DEMO_BOARD epd_board_v6
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define DEMO_BOARD epd_board_v7
|
||||
#endif
|
||||
|
||||
#define WAVEFORM EPD_BUILTIN_WAVEFORM
|
||||
|
||||
EpdiyHighlevelState hl;
|
||||
|
||||
void write_grayscale_pattern(bool direction, uint8_t* fb) {
|
||||
int ep_width = epd_width();
|
||||
uint8_t grayscale_line[ep_width / 2];
|
||||
if (direction) {
|
||||
for (uint32_t i = 0; i < ep_width / 2; i++) {
|
||||
uint8_t segment = i / (ep_width / 16 / 2);
|
||||
grayscale_line[i] = (segment << 4) | segment;
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < ep_width / 2; i++) {
|
||||
uint8_t segment = (ep_width / 2 - i - 1) / (ep_width / 16 / 2);
|
||||
grayscale_line[i] = (segment << 4) | segment;
|
||||
}
|
||||
}
|
||||
for (uint32_t y = 0; y < epd_height(); y++) {
|
||||
memcpy(fb + ep_width / 2 * y, grayscale_line, ep_width / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint8_t* fb = epd_hl_get_framebuffer(&hl);
|
||||
|
||||
write_grayscale_pattern(false, fb);
|
||||
|
||||
int temperature = 25; // epd_ambient_temperature();
|
||||
|
||||
epd_poweron();
|
||||
epd_clear();
|
||||
enum EpdDrawError err = epd_hl_update_screen(&hl, MODE_GC16, temperature);
|
||||
epd_poweroff();
|
||||
|
||||
vTaskDelay(5000);
|
||||
|
||||
write_grayscale_pattern(true, fb);
|
||||
|
||||
epd_poweron();
|
||||
err = epd_hl_update_screen(&hl, MODE_GC16, temperature);
|
||||
if (err != EPD_DRAW_SUCCESS) {
|
||||
printf("Error in epd_hl_update_screen:%d\n", err);
|
||||
}
|
||||
epd_poweroff();
|
||||
|
||||
vTaskDelay(100000);
|
||||
}
|
||||
|
||||
void IRAM_ATTR app_main() {
|
||||
epd_init(&DEMO_BOARD, &ED097TC2, EPD_LUT_64K);
|
||||
epd_set_vcom(1560);
|
||||
hl = epd_hl_init(WAVEFORM);
|
||||
|
||||
while (1) {
|
||||
loop();
|
||||
};
|
||||
}
|
||||
1500
lib/epdiy/examples/grayscale_test/sdkconfig.defaults.esp32
Normal file
1500
lib/epdiy/examples/grayscale_test/sdkconfig.defaults.esp32
Normal file
File diff suppressed because it is too large
Load Diff
1455
lib/epdiy/examples/grayscale_test/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/grayscale_test/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
6
lib/epdiy/examples/http-server/CMakeLists.txt
Normal file
6
lib/epdiy/examples/http-server/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(http-server)
|
||||
34
lib/epdiy/examples/http-server/README.md
Normal file
34
lib/epdiy/examples/http-server/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# HTTP server
|
||||
|
||||
Runs an HTTP server that will draw images on the screen.
|
||||
Useful for setting up a small digital frame that can be remotely controlled.
|
||||
|
||||
## Config
|
||||
1. In `main/server.h`, edit `WIFI_SSID` and `WIFI_PASSWORD` to match your wifi config
|
||||
2. In `main/main.c`, edit `n_epd_setup` to refer to the right EPD screen
|
||||
|
||||
## Running
|
||||
flash (`idf.py flash`), then connect the EPDiy to a power source (computer is fine).
|
||||
The endpoints are:
|
||||
1. `GET /`, prints the screen temp / height / width as headers
|
||||
2. `POST /clear`, clears the screen
|
||||
3. `POST /draw`, expects:
|
||||
1. a body that is a binary stream already encoded to EPDiy's standards (like the one in `dragon.h`).
|
||||
2. Headers `width`, `height`
|
||||
3. Optional headers `x`,`y` (default to 0)
|
||||
4. Optional header `clear`, if set to nonzero integer will force-clear the screen before drawing
|
||||
|
||||
## Helper script
|
||||
`send_image.py` is a friendlier client.
|
||||
```bash
|
||||
$ ./send_image.py ESP_IP info
|
||||
EpdInfo(width=1024, height=768, temperature=20)
|
||||
|
||||
$ ./send_image.py ESP_IP clear
|
||||
# Clears the screen
|
||||
|
||||
$ ./send_image.y ESP_IP draw /tmp/spooder-man.png
|
||||
# Draws on screen
|
||||
```
|
||||
Thanks to argparse, all arguments are visible with `--help`.
|
||||
Requires `requests` and `PIL` (or Pillow)
|
||||
4
lib/epdiy/examples/http-server/component.mk
Normal file
4
lib/epdiy/examples/http-server/component.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
8
lib/epdiy/examples/http-server/main/CMakeLists.txt
Normal file
8
lib/epdiy/examples/http-server/main/CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
set(
|
||||
app_sources "epd.c" "server.c" "main.c"
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
SRCS ${app_sources}
|
||||
REQUIRES epdiy esp_wifi nvs_flash esp_http_server esp_netif
|
||||
)
|
||||
44
lib/epdiy/examples/http-server/main/epd.c
Normal file
44
lib/epdiy/examples/http-server/main/epd.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "epd.h"
|
||||
|
||||
static EpdiyHighlevelState hl;
|
||||
static EpdData data;
|
||||
|
||||
static inline void checkError(enum EpdDrawError err) {
|
||||
if (err != EPD_DRAW_SUCCESS) {
|
||||
ESP_LOGE("demo", "draw error: %X", err);
|
||||
}
|
||||
}
|
||||
|
||||
EpdData n_epd_data() {
|
||||
return data;
|
||||
}
|
||||
|
||||
void n_epd_setup(const EpdDisplay_t* display) {
|
||||
epd_init(&epd_board_v7, display, EPD_LUT_64K);
|
||||
epd_set_vcom(1560);
|
||||
hl = epd_hl_init(EPD_BUILTIN_WAVEFORM);
|
||||
epd_set_rotation(EPD_ROT_LANDSCAPE);
|
||||
data.width = epd_rotated_display_width();
|
||||
data.height = epd_rotated_display_height();
|
||||
data.temperature = epd_ambient_temperature();
|
||||
}
|
||||
|
||||
void n_epd_clear() {
|
||||
epd_poweron();
|
||||
epd_fullclear(&hl, data.temperature);
|
||||
epd_poweroff();
|
||||
}
|
||||
|
||||
void n_epd_draw(uint8_t* content, int x, int y, int width, int height) {
|
||||
uint8_t* fb = epd_hl_get_framebuffer(&hl);
|
||||
EpdRect area = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
epd_draw_rotated_image(area, content, fb);
|
||||
epd_poweron();
|
||||
checkError(epd_hl_update_screen(&hl, MODE_GC16, data.temperature));
|
||||
epd_poweroff();
|
||||
}
|
||||
17
lib/epdiy/examples/http-server/main/epd.h
Normal file
17
lib/epdiy/examples/http-server/main/epd.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef EPD_H
|
||||
#define EPD_H
|
||||
|
||||
#include "epdiy.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int temperature;
|
||||
} EpdData;
|
||||
|
||||
EpdData n_epd_data();
|
||||
void n_epd_setup();
|
||||
void n_epd_clear();
|
||||
void n_epd_draw(uint8_t* content, int x, int y, int width, int height);
|
||||
#endif /* EPD_H */
|
||||
149
lib/epdiy/examples/http-server/main/main.c
Normal file
149
lib/epdiy/examples/http-server/main/main.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "server.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "epd.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define WRITE_HEADER(req, buffer, name, format, src) \
|
||||
sprintf(buffer, format, src); \
|
||||
ESP_ERROR_CHECK(httpd_resp_set_hdr(req, name, buffer));
|
||||
static esp_err_t http_index(httpd_req_t* req) {
|
||||
EpdData data = n_epd_data();
|
||||
char width[20], height[20], temperature[20];
|
||||
WRITE_HEADER(req, width, "width", "%d", data.width);
|
||||
WRITE_HEADER(req, height, "height", "%d", data.height);
|
||||
WRITE_HEADER(req, temperature, "temperature", "%d", data.temperature);
|
||||
const char* response = "Hello! Check headers\n";
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
httpd_resp_set_status(req, "200");
|
||||
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t http_clear(httpd_req_t* req) {
|
||||
ESP_LOGI(__FUNCTION__, "Clear\n");
|
||||
n_epd_clear();
|
||||
const char* response = "Cleared\n";
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
httpd_resp_set_status(req, "200");
|
||||
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t http_draw(httpd_req_t* req) {
|
||||
// optional headers: x,y. Default to 0
|
||||
// required headers: height, width
|
||||
// Content should be a stream of special bytes - we're reading 4 bits at a time.
|
||||
int x, y, width, height, clear;
|
||||
char header[20];
|
||||
memset(header, 0, 20);
|
||||
if (httpd_req_get_hdr_value_str(req, "clear", header, 20) == ESP_OK) {
|
||||
sscanf(header, "%d", &clear);
|
||||
} else {
|
||||
clear = 0;
|
||||
}
|
||||
if (httpd_req_get_hdr_value_str(req, "x", header, 20) == ESP_OK) {
|
||||
sscanf(header, "%d", &x);
|
||||
} else {
|
||||
x = 0;
|
||||
}
|
||||
if (httpd_req_get_hdr_value_str(req, "y", header, 20) == ESP_OK) {
|
||||
sscanf(header, "%d", &y);
|
||||
} else {
|
||||
y = 0;
|
||||
}
|
||||
if (httpd_req_get_hdr_value_str(req, "width", header, 20) == ESP_OK) {
|
||||
sscanf(header, "%d", &width);
|
||||
} else {
|
||||
char response[60];
|
||||
sprintf(response, "Missing header width");
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
httpd_resp_set_status(req, "400");
|
||||
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
if (httpd_req_get_hdr_value_str(req, "height", header, 20) == ESP_OK) {
|
||||
sscanf(header, "%d", &height);
|
||||
} else {
|
||||
char response[60];
|
||||
sprintf(response, "Missing header height");
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
httpd_resp_set_status(req, "400");
|
||||
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// READING STREAM
|
||||
int req_size = req->content_len;
|
||||
char* content = (char*)heap_caps_malloc(req_size, MALLOC_CAP_SPIRAM);
|
||||
if (content == NULL) {
|
||||
char msg[50];
|
||||
sprintf(msg, "Failed to allocate %d chars\n", req_size);
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, msg);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int current_pos = 0;
|
||||
int amount_recieved;
|
||||
while ((amount_recieved = httpd_req_recv(req, (content + current_pos), req_size)) > 0) {
|
||||
ESP_LOGI(__FUNCTION__, "Read %d bytes\n", amount_recieved);
|
||||
current_pos += amount_recieved;
|
||||
}
|
||||
if (amount_recieved < 0) {
|
||||
char msg[50];
|
||||
heap_caps_free(content);
|
||||
ESP_LOGE(msg, "Failed to read byets. Error code %d\n", amount_recieved);
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, msg);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ESP_LOGI(__FUNCTION__, "Done reading %d bytes out of %d\n", current_pos, req_size);
|
||||
|
||||
if (clear) {
|
||||
n_epd_clear();
|
||||
}
|
||||
n_epd_draw(((uint8_t*)content), x, y, width, height);
|
||||
heap_caps_free(content);
|
||||
|
||||
// Done reading
|
||||
char response[100];
|
||||
sprintf(
|
||||
response, "x %d, y %d, width %d, height %d, byte count %d\n", x, y, width, height, req_size
|
||||
);
|
||||
httpd_resp_set_type(req, "text/plain");
|
||||
httpd_resp_set_status(req, "200");
|
||||
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void register_paths(httpd_handle_t server) {
|
||||
{
|
||||
httpd_uri_t uri
|
||||
= { .uri = "/", .method = HTTP_GET, .handler = http_index, .user_ctx = NULL };
|
||||
httpd_register_uri_handler(server, &uri);
|
||||
}
|
||||
{
|
||||
httpd_uri_t uri
|
||||
= { .uri = "/clear", .method = HTTP_POST, .handler = http_clear, .user_ctx = NULL };
|
||||
httpd_register_uri_handler(server, &uri);
|
||||
}
|
||||
{
|
||||
httpd_uri_t uri
|
||||
= { .uri = "/draw", .method = HTTP_POST, .handler = http_draw, .user_ctx = NULL };
|
||||
httpd_register_uri_handler(server, &uri);
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
// Initialize NVS, needed for wifi
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
httpd_handle_t server = get_server();
|
||||
if (server != NULL) {
|
||||
register_paths(server);
|
||||
}
|
||||
n_epd_setup(&SCREEN_MODEL);
|
||||
}
|
||||
46
lib/epdiy/examples/http-server/main/server.c
Normal file
46
lib/epdiy/examples/http-server/main/server.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "server.h"
|
||||
|
||||
httpd_handle_t get_server(void);
|
||||
|
||||
static void wifi_init_sta(void) {
|
||||
// Initialize the ESP-NETIF
|
||||
esp_netif_init();
|
||||
esp_event_loop_create_default();
|
||||
|
||||
// Create default event loop
|
||||
esp_netif_create_default_wifi_sta();
|
||||
|
||||
// Initialize the Wi-Fi driver
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
// Set Wi-Fi mode to station
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
|
||||
// Configure Wi-Fi connection
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = WIFI_SSID,
|
||||
.password = WIFI_PASSWORD,
|
||||
},
|
||||
};
|
||||
|
||||
// Set the Wi-Fi configuration
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
ESP_ERROR_CHECK(esp_wifi_connect());
|
||||
}
|
||||
|
||||
httpd_handle_t start_webserver(void) {
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.lru_purge_enable = true;
|
||||
|
||||
httpd_handle_t server = NULL;
|
||||
ESP_ERROR_CHECK(httpd_start(&server, &config));
|
||||
return server;
|
||||
}
|
||||
|
||||
httpd_handle_t get_server(void) {
|
||||
wifi_init_sta();
|
||||
return start_webserver();
|
||||
}
|
||||
19
lib/epdiy/examples/http-server/main/server.h
Normal file
19
lib/epdiy/examples/http-server/main/server.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_http_server.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
httpd_handle_t get_server(void);
|
||||
|
||||
#endif /* SERVER_H */
|
||||
9
lib/epdiy/examples/http-server/main/settings.h
Normal file
9
lib/epdiy/examples/http-server/main/settings.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#define WIFI_SSID "best ssid" // Replace with your Wi-Fi SSID
|
||||
#define WIFI_PASSWORD "great password much wow" // Replace with your Wi-Fi password
|
||||
|
||||
#define SCREEN_MODEL ED060XC3
|
||||
|
||||
#endif /* SETTINGS_H */
|
||||
0
lib/epdiy/examples/http-server/sdkconfig.defaults
Normal file
0
lib/epdiy/examples/http-server/sdkconfig.defaults
Normal file
1500
lib/epdiy/examples/http-server/sdkconfig.defaults.esp32
Normal file
1500
lib/epdiy/examples/http-server/sdkconfig.defaults.esp32
Normal file
File diff suppressed because it is too large
Load Diff
1455
lib/epdiy/examples/http-server/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/http-server/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
107
lib/epdiy/examples/http-server/send_image.py
Executable file
107
lib/epdiy/examples/http-server/send_image.py
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import requests
|
||||
from typing import NamedTuple
|
||||
import PIL
|
||||
import PIL.Image
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("hostname")
|
||||
subparsers = parser.add_subparsers(dest="command")
|
||||
clear_parser = subparsers.add_parser("clear")
|
||||
draw_parser = subparsers.add_parser("draw")
|
||||
draw_parser.add_argument("-c", "--clear", action="store_true")
|
||||
draw_parser.add_argument("file")
|
||||
info_praser = subparsers.add_parser("info")
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def clear(hostname):
|
||||
requests.post(f"http://{hostname}/clear").raise_for_status()
|
||||
|
||||
|
||||
class EpdInfo(NamedTuple):
|
||||
width: int
|
||||
height: int
|
||||
temperature: int
|
||||
|
||||
@classmethod
|
||||
def from_response(cls, resp):
|
||||
return cls(
|
||||
width=int(resp.headers["width"]),
|
||||
height=int(resp.headers["height"]),
|
||||
temperature=int(resp.headers["temperature"]),
|
||||
)
|
||||
|
||||
|
||||
class Dimensions(NamedTuple):
|
||||
width: int
|
||||
height: int
|
||||
|
||||
|
||||
def info(hostname):
|
||||
resp = requests.get(f"http://{hostname}")
|
||||
resp.raise_for_status()
|
||||
return EpdInfo.from_response(resp)
|
||||
|
||||
|
||||
def image_refit(image: PIL.Image, bounder: Dimensions) -> PIL.Image:
|
||||
bounder_ratio = bounder.width / bounder.height
|
||||
image_width, image_height = image.size
|
||||
|
||||
image_width_by_height = int(image_height * bounder_ratio)
|
||||
image_height_by_width = int(image_width / bounder_ratio)
|
||||
if image_width > image_width_by_height:
|
||||
new_dimensions = Dimensions(image_width_by_height, image_height)
|
||||
else:
|
||||
new_dimensions = Dimensions(image_width, image_height_by_width)
|
||||
return PIL.ImageOps.fit(image, new_dimensions)
|
||||
|
||||
|
||||
def convert_8bit_to_4bit(bytestring):
|
||||
fourbit = []
|
||||
for i in range(0, len(bytestring), 2):
|
||||
first_nibble = int(bytestring[i] / 17)
|
||||
second_nibble = int(bytestring[i + 1] / 17)
|
||||
fourbit += [first_nibble << 4 | second_nibble]
|
||||
fourbit = bytes(fourbit)
|
||||
return fourbit
|
||||
|
||||
|
||||
def draw(hostname, filename, clear):
|
||||
inf = info(hostname)
|
||||
img = PIL.Image.open(filename)
|
||||
img = image_refit(img, Dimensions(width=inf.width, height=inf.height))
|
||||
img = img.resize((inf.width, inf.height))
|
||||
img = img.convert("L")
|
||||
img_bytes = convert_8bit_to_4bit(img.tobytes())
|
||||
requests.post(
|
||||
f"http://{hostname}/draw",
|
||||
headers={
|
||||
"width": str(inf.width),
|
||||
"height": str(inf.height),
|
||||
"x": "0",
|
||||
"y": "0",
|
||||
"clear": "1" if clear else "0",
|
||||
},
|
||||
data=img_bytes,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
if args.command == "clear":
|
||||
clear(args.hostname)
|
||||
elif args.command == "info":
|
||||
print(info(args.hostname))
|
||||
elif args.command == "draw":
|
||||
draw(args.hostname, args.file, args.clear)
|
||||
else:
|
||||
raise Exception(f"Unknown command {args.command}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
5
lib/epdiy/examples/lilygo-t5-47-epd-platformio/.gitignore
vendored
Normal file
5
lib/epdiy/examples/lilygo-t5-47-epd-platformio/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
6
lib/epdiy/examples/lilygo-t5-47-epd-platformio/README.md
Normal file
6
lib/epdiy/examples/lilygo-t5-47-epd-platformio/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# LilyGo T5 4.7 Inch Example
|
||||
|
||||
This is an example project to kick-start you using the LilyGo T5 4.7 inch EPaper display.
|
||||
|
||||
It also incorporates a few deepsleep methods to show how to use deepsleep to effectively save battery.
|
||||
Additionally, it inherits and modifies the battery calculation code provided in examples by the manufacturer.
|
||||
File diff suppressed because it is too large
Load Diff
46
lib/epdiy/examples/lilygo-t5-47-epd-platformio/lib/README
Normal file
46
lib/epdiy/examples/lilygo-t5-47-epd-platformio/lib/README
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
@@ -0,0 +1,39 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[common_env_data]
|
||||
framework = arduino
|
||||
board_build.f_cpu = 240000000L
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
Wire
|
||||
https://github.com/vroland/epdiy.git
|
||||
|
||||
build_flags =
|
||||
; device has PRSRAM
|
||||
; and should be used for ram intensive display work
|
||||
-DBOARD_HAS_PSRAM
|
||||
; Setup display format and model via build flags
|
||||
-DCONFIG_EPD_DISPLAY_TYPE_ED047TC1
|
||||
-DCONFIG_EPD_BOARD_REVISION_LILYGO_T5_47
|
||||
|
||||
[env:esp32dev]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = ${common_env_data.framework}
|
||||
upload_speed = ${common_env_data.upload_speed}
|
||||
monitor_speed = ${common_env_data.monitor_speed}
|
||||
lib_deps = ${common_env_data.lib_deps}
|
||||
build_flags = ${common_env_data.build_flags}
|
||||
|
||||
; uncomment if you want serial debugging with exception decoding
|
||||
; build_type = debug
|
||||
; monitor_filters = esp32_exception_decoder
|
||||
254
lib/epdiy/examples/lilygo-t5-47-epd-platformio/src/main.cpp
Normal file
254
lib/epdiy/examples/lilygo-t5-47-epd-platformio/src/main.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
// esp32 sdk imports
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
// epd
|
||||
#include "epd_highlevel.h"
|
||||
#include "epdiy.h"
|
||||
|
||||
// battery
|
||||
#include <driver/adc.h>
|
||||
#include "esp_adc_cal.h"
|
||||
|
||||
// deepsleep
|
||||
#include "esp_sleep.h"
|
||||
|
||||
// font
|
||||
#include "Firasans.h"
|
||||
|
||||
#define BATT_PIN 36
|
||||
|
||||
#define WAVEFORM EPD_BUILTIN_WAVEFORM
|
||||
|
||||
/**
|
||||
* Upper most button on side of device. Used to setup as wakeup source to start from deepsleep.
|
||||
* Pinout here https://ae01.alicdn.com/kf/H133488d889bd4dd4942fbc1415e0deb1j.jpg
|
||||
*/
|
||||
gpio_num_t FIRST_BTN_PIN = GPIO_NUM_39;
|
||||
|
||||
EpdiyHighlevelState hl;
|
||||
// ambient temperature around device
|
||||
int temperature = 20;
|
||||
uint8_t* fb;
|
||||
enum EpdDrawError err;
|
||||
|
||||
// CHOOSE HERE YOU IF YOU WANT PORTRAIT OR LANDSCAPE
|
||||
// both orientations possible
|
||||
EpdRotation orientation = EPD_ROT_PORTRAIT;
|
||||
// EpdRotation orientation = EPD_ROT_LANDSCAPE;
|
||||
|
||||
int vref = 1100;
|
||||
|
||||
/**
|
||||
* RTC Memory var to get number of wakeups via wakeup source button
|
||||
* For demo purposes of rtc data attr
|
||||
**/
|
||||
RTC_DATA_ATTR int pressed_wakeup_btn_index;
|
||||
|
||||
/**
|
||||
* That's maximum 30 seconds of runtime in microseconds
|
||||
*/
|
||||
int64_t maxTimeRunning = 30000000;
|
||||
|
||||
double_t get_battery_percentage() {
|
||||
// When reading the battery voltage, POWER_EN must be turned on
|
||||
epd_poweron();
|
||||
delay(50);
|
||||
|
||||
Serial.println(epd_ambient_temperature());
|
||||
|
||||
uint16_t v = analogRead(BATT_PIN);
|
||||
Serial.print("Battery analogRead value is");
|
||||
Serial.println(v);
|
||||
double_t battery_voltage = ((double_t)v / 4095.0) * 2.0 * 3.3 * (vref / 1000.0);
|
||||
|
||||
// Better formula needed I suppose
|
||||
// experimental super simple percent estimate no lookup anything just divide by 100
|
||||
double_t percent_experiment = ((battery_voltage - 3.7) / 0.5) * 100;
|
||||
|
||||
// cap out battery at 100%
|
||||
// on charging it spikes higher
|
||||
if (percent_experiment > 100) {
|
||||
percent_experiment = 100;
|
||||
}
|
||||
|
||||
String voltage = "Battery Voltage :" + String(battery_voltage) + "V which is around "
|
||||
+ String(percent_experiment) + "%";
|
||||
Serial.println(voltage);
|
||||
|
||||
epd_poweroff();
|
||||
delay(50);
|
||||
|
||||
return percent_experiment;
|
||||
}
|
||||
|
||||
void display_center_message(const char* text) {
|
||||
// first set full screen to white
|
||||
epd_hl_set_all_white(&hl);
|
||||
|
||||
int cursor_x = EPD_WIDTH / 2;
|
||||
int cursor_y = EPD_HEIGHT / 2;
|
||||
if (orientation == EPD_ROT_PORTRAIT) {
|
||||
// height and width switched here because portrait mode
|
||||
cursor_x = EPD_HEIGHT / 2;
|
||||
cursor_y = EPD_WIDTH / 2;
|
||||
}
|
||||
EpdFontProperties font_props = epd_font_properties_default();
|
||||
font_props.flags = EPD_DRAW_ALIGN_CENTER;
|
||||
epd_write_string(&FiraSans_12, text, &cursor_x, &cursor_y, fb, &font_props);
|
||||
|
||||
epd_poweron();
|
||||
err = epd_hl_update_screen(&hl, MODE_GC16, temperature);
|
||||
delay(500);
|
||||
epd_poweroff();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void display_full_screen_left_aligned_text(const char* text) {
|
||||
EpdFontProperties font_props = epd_font_properties_default();
|
||||
font_props.flags = EPD_DRAW_ALIGN_LEFT;
|
||||
|
||||
// first set full screen to white
|
||||
epd_hl_set_all_white(&hl);
|
||||
|
||||
/************* Display the text itself ******************/
|
||||
// hardcoded to start at upper left corner
|
||||
// with bit of padding
|
||||
int cursor_x = 10;
|
||||
int cursor_y = 30;
|
||||
epd_write_string(&FiraSans_12, text, &cursor_x, &cursor_y, fb, &font_props);
|
||||
/********************************************************/
|
||||
|
||||
/************ Battery percentage display ****************/
|
||||
// height and width switched here because portrait mode
|
||||
int battery_cursor_x = EPD_WIDTH - 30;
|
||||
int battery_cursor_y = EPD_HEIGHT - 10;
|
||||
if (orientation == EPD_ROT_PORTRAIT) {
|
||||
// switched x and y constants in portrait mode
|
||||
battery_cursor_x = EPD_HEIGHT - 10;
|
||||
battery_cursor_y = EPD_WIDTH - 30;
|
||||
}
|
||||
EpdFontProperties battery_font_props = epd_font_properties_default();
|
||||
battery_font_props.flags = EPD_DRAW_ALIGN_RIGHT;
|
||||
String battery_text = String(get_battery_percentage());
|
||||
battery_text.concat("% Battery");
|
||||
epd_write_string(
|
||||
&FiraSans_12,
|
||||
battery_text.c_str(),
|
||||
&battery_cursor_x,
|
||||
&battery_cursor_y,
|
||||
fb,
|
||||
&battery_font_props
|
||||
);
|
||||
/********************************************************/
|
||||
|
||||
epd_poweron();
|
||||
err = epd_hl_update_screen(&hl, MODE_GC16, temperature);
|
||||
delay(500);
|
||||
epd_poweroff();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Powers off everything into deepsleep so device and display.
|
||||
*/
|
||||
void start_deep_sleep_with_wakeup_sources() {
|
||||
epd_poweroff();
|
||||
delay(400);
|
||||
esp_sleep_enable_ext0_wakeup(FIRST_BTN_PIN, 0);
|
||||
|
||||
Serial.println("Sending device to deepsleep");
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that prints the reason by which ESP32 has been awaken from sleep
|
||||
*/
|
||||
void print_wakeup_reason() {
|
||||
esp_sleep_wakeup_cause_t wakeup_reason;
|
||||
wakeup_reason = esp_sleep_get_wakeup_cause();
|
||||
switch (wakeup_reason) {
|
||||
case ESP_SLEEP_WAKEUP_EXT0:
|
||||
Serial.println("Wakeup caused by external signal using RTC_IO");
|
||||
break;
|
||||
case ESP_SLEEP_WAKEUP_EXT1:
|
||||
Serial.println("Wakeup caused by external signal using RTC_CNTL");
|
||||
break;
|
||||
case ESP_SLEEP_WAKEUP_TIMER:
|
||||
Serial.println("Wakeup caused by timer");
|
||||
break;
|
||||
case ESP_SLEEP_WAKEUP_TOUCHPAD:
|
||||
Serial.println("Wakeup caused by touchpad");
|
||||
break;
|
||||
case ESP_SLEEP_WAKEUP_ULP:
|
||||
Serial.println("Wakeup caused by ULP program");
|
||||
break;
|
||||
default:
|
||||
Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the ADC reference voltage. Was in example of lilygo epd47 repository to calc battery
|
||||
* percentage
|
||||
*/
|
||||
void correct_adc_reference() {
|
||||
esp_adc_cal_characteristics_t adc_chars;
|
||||
esp_adc_cal_value_t val_type
|
||||
= esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars);
|
||||
if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||
Serial.printf("eFuse Vref:%u mV", adc_chars.vref);
|
||||
vref = adc_chars.vref;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
correct_adc_reference();
|
||||
|
||||
// First setup epd to use later
|
||||
|
||||
epd_init(&epd_board_lilygo_t5_47, &ED097TC2, EPD_LUT_64K);
|
||||
epd_set_vcom(1560);
|
||||
hl = epd_hl_init(WAVEFORM);
|
||||
epd_set_rotation(orientation);
|
||||
fb = epd_hl_get_framebuffer(&hl);
|
||||
epd_clear();
|
||||
|
||||
print_wakeup_reason();
|
||||
|
||||
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
|
||||
if (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0) {
|
||||
Serial.println("Woken up by wakeup source button");
|
||||
pressed_wakeup_btn_index++;
|
||||
String message = String("Woken up from deepsleep times: ");
|
||||
message.concat(String(pressed_wakeup_btn_index));
|
||||
display_full_screen_left_aligned_text(message.c_str());
|
||||
|
||||
} else {
|
||||
/* Non deepsleep wakeup source button interrupt caused start e.g. reset btn */
|
||||
Serial.println("Woken up by reset button or power cycle");
|
||||
const char* message = "Hello! You just turned me on.\nIn 30s I will go to deepsleep";
|
||||
display_center_message(message);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
* Shutdown device after 30s always to conserve battery.
|
||||
* Basically almost no battery usage then until next wakeup.
|
||||
*/
|
||||
if (esp_timer_get_time() > maxTimeRunning) {
|
||||
Serial.println("Max runtime of 30s reached. Forcing deepsleep now to save energy");
|
||||
display_center_message(
|
||||
"Sleeping now.\nWake me up from deepsleep again\nwith the first button on my side"
|
||||
);
|
||||
delay(1500);
|
||||
|
||||
start_deep_sleep_with_wakeup_sources();
|
||||
}
|
||||
}
|
||||
16
lib/epdiy/examples/screen_diag/CMakeLists.txt
Normal file
16
lib/epdiy/examples/screen_diag/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
# dependencies
|
||||
set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(screen_diag)
|
||||
|
||||
set(IDF_VER_SANE "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}")
|
||||
if (IDF_VER_SANE VERSION_LESS "5.0.0")
|
||||
message(FATAL_ERROR "screen_diag requires at least ESP-IDF v5.0.0")
|
||||
endif()
|
||||
189
lib/epdiy/examples/screen_diag/README.md
Normal file
189
lib/epdiy/examples/screen_diag/README.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# Screen Diagnostics
|
||||
This example app implements a simple shell to allow you to tinker with the display. You have access to all drawing functions from the _epd driver_, as well as system information, etc.
|
||||
|
||||
There are also pre-programmed algorithms (e.g. `render_stairs`, `render_grid`) which can be used to find pixel errors or display incompatibilities.
|
||||
|
||||
The `screen_diag` examples requires ESP-IDF v5.x or newer.
|
||||
|
||||
## Setup
|
||||
Don't forget to set your display type in `epd_init` in `epd.c`!
|
||||
|
||||
First you need to flash the firmware:
|
||||
```sh
|
||||
idf.py flash
|
||||
```
|
||||
|
||||
After that, you can enter the shell environment with:
|
||||
```sh
|
||||
idf.py monitor
|
||||
```
|
||||
|
||||
Please note the [known issues](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/tools/idf-monitor.html#known-issues-with-idf-monitor) of the IDF Monitor for limitations.
|
||||
|
||||
## Usage
|
||||
You can get a full list (see below) of all available commands with: `help`.
|
||||
|
||||
```
|
||||
system_restart
|
||||
Restarts the system.
|
||||
|
||||
free_heap_size
|
||||
Returns the free heap size.
|
||||
|
||||
dump_heaps_info [<caps>]
|
||||
Dumps heap information of all heaps matching the capability.
|
||||
<caps> Heap caps to print. Default: MALLOC_CAP_DEFAULT
|
||||
|
||||
dump_tasks
|
||||
Dumps all tasks with their names, current state and stack usage.
|
||||
|
||||
chip_info
|
||||
Dumps chip information.
|
||||
|
||||
firmware_info
|
||||
Dumps information about the ESP-IDF and the firmware.
|
||||
|
||||
get_time
|
||||
Returns the time in microseconds since boot.
|
||||
|
||||
get_mac [<interface>]
|
||||
Returns the MAC address for the given interface or the pre-programmed base
|
||||
address.
|
||||
<interface> Either "wifi_station", "wifi_ap", "bluetooth" or "ethernet"
|
||||
|
||||
get_rotation
|
||||
Get current screen rotation.
|
||||
|
||||
set_rotation <rotation> [--inverted]
|
||||
Changes screen rotation.
|
||||
<rotation> screen rotation: "horizontal" or "portrait"
|
||||
--inverted
|
||||
|
||||
get_width
|
||||
Print screen width.
|
||||
|
||||
get_height
|
||||
Print screen height.
|
||||
|
||||
get_pixel <posx> <posy>
|
||||
Get pixel color in front buffer.
|
||||
<posx> x position
|
||||
<posy> y position
|
||||
|
||||
set_pixel <posx> <posy> [<color>]
|
||||
Set pixel color in front buffer.
|
||||
<posx> x position
|
||||
<posy> y position
|
||||
<color> color. default value: 0 (0x00)
|
||||
|
||||
clear_screen
|
||||
Clear the entire screen and reset the front buffer to white.
|
||||
|
||||
full_clear_screen
|
||||
Same as clear_screen, but also tries to get rid of any artifacts by cycling
|
||||
through colors on the screen.
|
||||
|
||||
get_temp
|
||||
Returns the ambient temperature.
|
||||
|
||||
power_on
|
||||
Turns on the power of the display.
|
||||
|
||||
power_off
|
||||
Turns off the power of the display.
|
||||
|
||||
draw_hline <x> <y> <len> [<color>]
|
||||
Draw horizontal line.
|
||||
<x> start x position
|
||||
<y> start y position
|
||||
<len> length of the line
|
||||
<color> default value: 0x00
|
||||
|
||||
draw_vline <x> <y> <len> [<color>]
|
||||
Draw vertical line.
|
||||
<x> start x position
|
||||
<y> start y position
|
||||
<len> length of the line
|
||||
<color> default value: 0x00
|
||||
|
||||
draw_line <start_x> <start_y> <end_x> <end_y> [<color>]
|
||||
Draw line between two points.
|
||||
<start_x> start x position
|
||||
<start_y> start y position
|
||||
<end_x> end x position
|
||||
<end_y> end y position
|
||||
<color> default value: 0x00
|
||||
|
||||
draw_rect <x> <y> <width> <height> [<color>]
|
||||
Draw a rectangle.
|
||||
<x> top left x position
|
||||
<y> top left y position
|
||||
<width> square width
|
||||
<height> square height
|
||||
<color> default value: 0x00
|
||||
|
||||
fill_rect <x> <y> <width> <height> [<color>]
|
||||
Draw a filled rectangle.
|
||||
<x> top left x position
|
||||
<y> top left y position
|
||||
<width> square width
|
||||
<height> square height
|
||||
<color> default value: 0x00
|
||||
|
||||
draw_circle <center_x> <center_y> <radius> [<color>]
|
||||
Draw a circle.
|
||||
<center_x> center x position
|
||||
<center_y> center y position
|
||||
<radius> circle radius
|
||||
<color> default value: 0x00
|
||||
|
||||
fill_circle <center_x> <center_y> <radius> [<color>]
|
||||
Draw a filled circle.
|
||||
<center_x> center x position
|
||||
<center_y> center y position
|
||||
<radius> circle radius
|
||||
<color> default value: 0x00
|
||||
|
||||
draw_triangle <x0> <y0> <x1> <y1> <x0> <y0> [<color>]
|
||||
Draw a triangle from three different points.
|
||||
<x0> first edge x position
|
||||
<y0> first edge y position
|
||||
<x1> second edge x position
|
||||
<y1> second edge y position
|
||||
<x0> third edge x position
|
||||
<y0> third edge y position
|
||||
<color> default value: 0x00
|
||||
|
||||
fill_triangle <x0> <y0> <x1> <y1> <x0> <y0> [<color>]
|
||||
Draw a filled triangle from three different points.
|
||||
<x0> first edge x position
|
||||
<y0> first edge y position
|
||||
<x1> second edge x position
|
||||
<y1> second edge y position
|
||||
<x0> third edge x position
|
||||
<y0> third edge y position
|
||||
<color> default value: 0x00
|
||||
|
||||
write_text [-s] <x> <y> [<color>] <msg>
|
||||
Write text message to the screen using the sans-serif font by default.
|
||||
<x> x position
|
||||
<y> y position
|
||||
<color> default value: 0x00
|
||||
-s, --serif Use serif font rather than sans-serif.
|
||||
<msg> Text to be printed.
|
||||
|
||||
render_stairs [<slope>] [<width>] [<color>]
|
||||
Render multiple diagonal lines across the screen.
|
||||
<slope> angle by which each diagonal line is drawn. default value: 3
|
||||
<width> thickness of each diagonal line. default value: 100
|
||||
<color> default value: 0x00
|
||||
|
||||
render_grid [<gutter>] [<color>]
|
||||
Renders a grid across the whole screen. At a certain gutter size, cell info
|
||||
will be printed as well.
|
||||
<gutter> default value: 75
|
||||
<color> default value: 0x00
|
||||
|
||||
help
|
||||
Print the list of registered commands
|
||||
```
|
||||
4
lib/epdiy/examples/screen_diag/main/CMakeLists.txt
Normal file
4
lib/epdiy/examples/screen_diag/main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "screen_diag.c" "epd.c" "commands.c" "commands/system.c"
|
||||
"commands/screen.c" "commands/graphics.c" "commands/tests.c"
|
||||
INCLUDE_DIRS "." "res/fonts"
|
||||
REQUIRES epdiy console nvs_flash fatfs esp_app_format)
|
||||
17
lib/epdiy/examples/screen_diag/main/commands.c
Normal file
17
lib/epdiy/examples/screen_diag/main/commands.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "commands.h"
|
||||
|
||||
bool validate_color(uint8_t* inout_color, struct arg_int* arg) {
|
||||
int user_color = arg->count != 0 ? arg->ival[0] : *inout_color;
|
||||
if (user_color < 0 || user_color > 0xFF) {
|
||||
printf(
|
||||
"Invalid color %d (0x%02x): Must be in range 0x00 to 0xFF.\r\n",
|
||||
user_color,
|
||||
(uint8_t)user_color
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
*inout_color = (uint8_t)user_color;
|
||||
|
||||
return true;
|
||||
}
|
||||
76
lib/epdiy/examples/screen_diag/main/commands.h
Normal file
76
lib/epdiy/examples/screen_diag/main/commands.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
/* Helper functions and macros for common use cases,
|
||||
* when registering or implementing commands.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <argtable3/argtable3.h>
|
||||
#include <esp_console.h>
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
/**
|
||||
* Returns size of a (static) C array.
|
||||
*/
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks whether the given color argument is a valid color.
|
||||
* I.e. when it's color value is possible to represent by an uint8_t (0x00 - 0xFF).
|
||||
* If no color argument was provided by the user, returns the default color of 0x00.
|
||||
*
|
||||
* @param inout_color initial value will be used as default color,
|
||||
* when the user did not specify a color.
|
||||
* when successful, will be set to the given color.
|
||||
* @param arg user-specified color argument
|
||||
* @return whether the given color is valid
|
||||
*/
|
||||
bool validate_color(uint8_t* inout_color, struct arg_int* arg);
|
||||
|
||||
/**
|
||||
* Determines the number of arguments stored in a struct (container).
|
||||
* That is usually the number of arguments for a given command and
|
||||
* can be used when initializing the arg_end parameter.
|
||||
*
|
||||
* This macro assumes, that
|
||||
* 1. each argument inside the struct is referenced by a pointer,
|
||||
* 2. each struct ends with an arg_end*,
|
||||
* 3. there are no other members in the struct, besides different argument types.
|
||||
*/
|
||||
#define NARGS(container) ((sizeof(container) / sizeof(struct arg_end*)) - 1)
|
||||
|
||||
/**
|
||||
* Handles argument validation for the command.
|
||||
* Assumes that `argc` and `argv` variables are visible, thus should
|
||||
* only be used inside the command implementation function.
|
||||
*
|
||||
* @param args_struct name of the (static) argument struct.
|
||||
*/
|
||||
#define HANDLE_ARGUMENTS(args_struct) \
|
||||
{ \
|
||||
int nerrors = arg_parse(argc, argv, (void**)&args_struct); \
|
||||
if (nerrors > 0) { \
|
||||
arg_print_errors(stdout, args_struct.end, argv[0]); \
|
||||
return 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* Get optional argument value if provided by the user. Otherwise use the default value.
|
||||
*
|
||||
* @param arg pointer to argument struct (e.g. struct arg_int*)
|
||||
* @param accessor accessor used to retrieve the first value (e.g. ival for struct arg_int)
|
||||
* @param default_value
|
||||
*/
|
||||
#define GET_ARG(arg, accessor, default_value) \
|
||||
(arg)->count == 1 ? (arg)->accessor[0] : (default_value)
|
||||
|
||||
/**
|
||||
* Alias for GET_ARG, specialized for int arguments.
|
||||
*
|
||||
* @param arg pointer to an struct arg_int
|
||||
* @param default_value
|
||||
*/
|
||||
#define GET_INT_ARG(arg, default_value) GET_ARG(arg, ival, default_value)
|
||||
375
lib/epdiy/examples/screen_diag/main/commands/graphics.c
Normal file
375
lib/epdiy/examples/screen_diag/main/commands/graphics.c
Normal file
@@ -0,0 +1,375 @@
|
||||
#include "graphics.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <argtable3/argtable3.h>
|
||||
#include <esp_console.h>
|
||||
|
||||
#include "../commands.h"
|
||||
#include "../epd.h"
|
||||
#include "fonts.h"
|
||||
|
||||
static struct {
|
||||
struct arg_int *x, *y;
|
||||
struct arg_int* len;
|
||||
struct arg_int* color;
|
||||
struct arg_end* end;
|
||||
} draw_hvline_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int *from_x, *from_y;
|
||||
struct arg_int *to_x, *to_y;
|
||||
struct arg_int* color;
|
||||
struct arg_end* end;
|
||||
} draw_line_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int *x, *y;
|
||||
struct arg_int *width, *height;
|
||||
struct arg_int* color;
|
||||
struct arg_end* end;
|
||||
} draw_rect_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int *x, *y;
|
||||
struct arg_int* radius;
|
||||
struct arg_int* color;
|
||||
struct arg_end* end;
|
||||
} draw_circle_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int *x0, *y0;
|
||||
struct arg_int *x1, *y1;
|
||||
struct arg_int *x2, *y2;
|
||||
struct arg_int* color;
|
||||
struct arg_end* end;
|
||||
} draw_triangle_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int *x, *y;
|
||||
struct arg_int* color;
|
||||
struct arg_lit* serif;
|
||||
struct arg_str* msg;
|
||||
struct arg_end* end;
|
||||
} write_text_args;
|
||||
|
||||
static int draw_hline(int argc, char* argv[]);
|
||||
static int draw_vline(int argc, char* argv[]);
|
||||
static int draw_line(int argc, char* argv[]);
|
||||
static int draw_rect(int argc, char* argv[]);
|
||||
static int fill_rect(int argc, char* argv[]);
|
||||
static int draw_circle(int argc, char* argv[]);
|
||||
static int fill_circle(int argc, char* argv[]);
|
||||
static int draw_triangle(int argc, char* argv[]);
|
||||
static int fill_triangle(int argc, char* argv[]);
|
||||
static int write_text(int argc, char* argv[]);
|
||||
|
||||
void register_graphics_commands(void) {
|
||||
// setup args
|
||||
draw_hvline_args.x = arg_intn(NULL, NULL, "<x>", 1, 1, "start x position");
|
||||
draw_hvline_args.y = arg_intn(NULL, NULL, "<y>", 1, 1, "start y position");
|
||||
draw_hvline_args.len = arg_intn(NULL, NULL, "<len>", 1, 1, "length of the line");
|
||||
draw_hvline_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
draw_hvline_args.end = arg_end(NARGS(draw_hvline_args));
|
||||
|
||||
draw_line_args.from_x = arg_intn(NULL, NULL, "<start_x>", 1, 1, "start x position");
|
||||
draw_line_args.from_y = arg_intn(NULL, NULL, "<start_y>", 1, 1, "start y position");
|
||||
draw_line_args.to_x = arg_intn(NULL, NULL, "<end_x>", 1, 1, "end x position");
|
||||
draw_line_args.to_y = arg_intn(NULL, NULL, "<end_y>", 1, 1, "end y position");
|
||||
draw_line_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
draw_line_args.end = arg_end(NARGS(draw_line_args));
|
||||
|
||||
draw_rect_args.x = arg_intn(NULL, NULL, "<x>", 1, 1, "top left x position");
|
||||
draw_rect_args.y = arg_intn(NULL, NULL, "<y>", 1, 1, "top left y position");
|
||||
draw_rect_args.width = arg_intn(NULL, NULL, "<width>", 1, 1, "square width");
|
||||
draw_rect_args.height = arg_intn(NULL, NULL, "<height>", 1, 1, "square height");
|
||||
draw_rect_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
draw_rect_args.end = arg_end(NARGS(draw_rect_args));
|
||||
|
||||
draw_circle_args.x = arg_intn(NULL, NULL, "<center_x>", 1, 1, "center x position");
|
||||
draw_circle_args.y = arg_intn(NULL, NULL, "<center_y>", 1, 1, "center y position");
|
||||
draw_circle_args.radius = arg_intn(NULL, NULL, "<radius>", 1, 1, "circle radius");
|
||||
draw_circle_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
draw_circle_args.end = arg_end(NARGS(draw_circle_args));
|
||||
|
||||
draw_triangle_args.x0 = arg_intn(NULL, NULL, "<x0>", 1, 1, "first edge x position");
|
||||
draw_triangle_args.y0 = arg_intn(NULL, NULL, "<y0>", 1, 1, "first edge y position");
|
||||
draw_triangle_args.x1 = arg_intn(NULL, NULL, "<x1>", 1, 1, "second edge x position");
|
||||
draw_triangle_args.y1 = arg_intn(NULL, NULL, "<y1>", 1, 1, "second edge y position");
|
||||
draw_triangle_args.x2 = arg_intn(NULL, NULL, "<x0>", 1, 1, "third edge x position");
|
||||
draw_triangle_args.y2 = arg_intn(NULL, NULL, "<y0>", 1, 1, "third edge y position");
|
||||
draw_triangle_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
draw_triangle_args.end = arg_end(NARGS(draw_triangle_args));
|
||||
|
||||
write_text_args.x = arg_intn(NULL, NULL, "<x>", 1, 1, "x position");
|
||||
write_text_args.y = arg_intn(NULL, NULL, "<y>", 1, 1, "y position");
|
||||
write_text_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
write_text_args.serif = arg_litn("s", "serif", 0, 1, "Use serif font rather than sans-serif.");
|
||||
write_text_args.msg = arg_strn(NULL, NULL, "<msg>", 1, 1, "Text to be printed.");
|
||||
write_text_args.end = arg_end(NARGS(write_text_args));
|
||||
|
||||
// register commands
|
||||
const esp_console_cmd_t commands[]
|
||||
= { { .command = "draw_hline",
|
||||
.help = "Draw horizontal line.",
|
||||
.hint = NULL,
|
||||
.func = &draw_hline,
|
||||
.argtable = &draw_hvline_args },
|
||||
{ .command = "draw_vline",
|
||||
.help = "Draw vertical line.",
|
||||
.hint = NULL,
|
||||
.func = &draw_vline,
|
||||
.argtable = &draw_hvline_args },
|
||||
{ .command = "draw_line",
|
||||
.help = "Draw line between two points.",
|
||||
.hint = NULL,
|
||||
.func = &draw_line,
|
||||
.argtable = &draw_line_args },
|
||||
{ .command = "draw_rect",
|
||||
.help = "Draw a rectangle.",
|
||||
.hint = NULL,
|
||||
.func = &draw_rect,
|
||||
.argtable = &draw_rect_args },
|
||||
{ .command = "fill_rect",
|
||||
.help = "Draw a filled rectangle.",
|
||||
.hint = NULL,
|
||||
.func = &fill_rect,
|
||||
.argtable = &draw_rect_args },
|
||||
{ .command = "draw_circle",
|
||||
.help = "Draw a circle.",
|
||||
.hint = NULL,
|
||||
.func = &draw_circle,
|
||||
.argtable = &draw_circle_args },
|
||||
{ .command = "fill_circle",
|
||||
.help = "Draw a filled circle.",
|
||||
.hint = NULL,
|
||||
.func = &fill_circle,
|
||||
.argtable = &draw_circle_args },
|
||||
{ .command = "draw_triangle",
|
||||
.help = "Draw a triangle from three different points.",
|
||||
.hint = NULL,
|
||||
.func = &draw_triangle,
|
||||
.argtable = &draw_triangle_args },
|
||||
{ .command = "fill_triangle",
|
||||
.help = "Draw a filled triangle from three different points.",
|
||||
.hint = NULL,
|
||||
.func = &fill_triangle,
|
||||
.argtable = &draw_triangle_args },
|
||||
{ .command = "write_text",
|
||||
.help = "Write text message to the screen using the sans-serif font by default.",
|
||||
.hint = NULL,
|
||||
.func = &write_text,
|
||||
.argtable = &write_text_args } };
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&commands[i]));
|
||||
}
|
||||
|
||||
static int draw_hline(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_hvline_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_hvline_args.color))
|
||||
return 1;
|
||||
|
||||
epd_draw_hline(
|
||||
draw_hvline_args.x->ival[0],
|
||||
draw_hvline_args.y->ival[0],
|
||||
draw_hvline_args.len->ival[0],
|
||||
color,
|
||||
g_framebuffer
|
||||
);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_vline(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_hvline_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_hvline_args.color))
|
||||
return 1;
|
||||
|
||||
epd_draw_vline(
|
||||
draw_hvline_args.x->ival[0],
|
||||
draw_hvline_args.y->ival[0],
|
||||
draw_hvline_args.len->ival[0],
|
||||
color,
|
||||
g_framebuffer
|
||||
);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_line(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_line_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_line_args.color))
|
||||
return 1;
|
||||
|
||||
epd_draw_line(
|
||||
draw_line_args.from_x->ival[0],
|
||||
draw_line_args.from_y->ival[0],
|
||||
draw_line_args.to_x->ival[0],
|
||||
draw_line_args.to_y->ival[0],
|
||||
color,
|
||||
g_framebuffer
|
||||
);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_rect(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_rect_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_rect_args.color))
|
||||
return 1;
|
||||
|
||||
EpdRect rect = { .x = draw_rect_args.x->ival[0],
|
||||
.y = draw_rect_args.y->ival[0],
|
||||
.width = draw_rect_args.width->ival[0],
|
||||
.height = draw_rect_args.height->ival[0] };
|
||||
|
||||
epd_draw_rect(rect, color, g_framebuffer);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fill_rect(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_rect_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_rect_args.color))
|
||||
return 1;
|
||||
|
||||
EpdRect rect = { .x = draw_rect_args.x->ival[0],
|
||||
.y = draw_rect_args.y->ival[0],
|
||||
.width = draw_rect_args.width->ival[0],
|
||||
.height = draw_rect_args.height->ival[0] };
|
||||
|
||||
epd_fill_rect(rect, color, g_framebuffer);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_circle(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_circle_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_circle_args.color))
|
||||
return 1;
|
||||
|
||||
epd_draw_circle(
|
||||
draw_circle_args.x->ival[0],
|
||||
draw_circle_args.y->ival[0],
|
||||
draw_circle_args.radius->ival[0],
|
||||
color,
|
||||
g_framebuffer
|
||||
);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fill_circle(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_circle_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_circle_args.color))
|
||||
return 1;
|
||||
|
||||
epd_fill_circle(
|
||||
draw_circle_args.x->ival[0],
|
||||
draw_circle_args.y->ival[0],
|
||||
draw_circle_args.radius->ival[0],
|
||||
color,
|
||||
g_framebuffer
|
||||
);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int draw_triangle(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_triangle_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_triangle_args.color))
|
||||
return 1;
|
||||
|
||||
epd_draw_triangle(
|
||||
draw_triangle_args.x0->ival[0],
|
||||
draw_triangle_args.y0->ival[0],
|
||||
draw_triangle_args.x1->ival[0],
|
||||
draw_triangle_args.y1->ival[0],
|
||||
draw_triangle_args.x2->ival[0],
|
||||
draw_triangle_args.y2->ival[0],
|
||||
color,
|
||||
g_framebuffer
|
||||
);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fill_triangle(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(draw_triangle_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_triangle_args.color))
|
||||
return 1;
|
||||
|
||||
epd_fill_triangle(
|
||||
draw_triangle_args.x0->ival[0],
|
||||
draw_triangle_args.y0->ival[0],
|
||||
draw_triangle_args.x1->ival[0],
|
||||
draw_triangle_args.y1->ival[0],
|
||||
draw_triangle_args.x2->ival[0],
|
||||
draw_triangle_args.y2->ival[0],
|
||||
color,
|
||||
g_framebuffer
|
||||
);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_text(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(write_text_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, draw_triangle_args.color))
|
||||
return 1;
|
||||
|
||||
const EpdFont* font = &Alexandria;
|
||||
if (write_text_args.serif->count)
|
||||
font = &Amiri;
|
||||
|
||||
EpdFontProperties props = { .bg_color = 0x00, .fg_color = color };
|
||||
|
||||
int pos_x = write_text_args.x->ival[0];
|
||||
int pos_y = write_text_args.y->ival[0];
|
||||
|
||||
epd_write_string(font, write_text_args.msg->sval[0], &pos_x, &pos_y, g_framebuffer, &props);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
lib/epdiy/examples/screen_diag/main/commands/graphics.h
Normal file
3
lib/epdiy/examples/screen_diag/main/commands/graphics.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void register_graphics_commands(void);
|
||||
286
lib/epdiy/examples/screen_diag/main/commands/screen.c
Normal file
286
lib/epdiy/examples/screen_diag/main/commands/screen.c
Normal file
@@ -0,0 +1,286 @@
|
||||
#include "screen.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <argtable3/argtable3.h>
|
||||
#include <esp_console.h>
|
||||
|
||||
#include "../commands.h"
|
||||
#include "../epd.h"
|
||||
|
||||
static struct {
|
||||
struct arg_str* rotation;
|
||||
struct arg_lit* inverted;
|
||||
struct arg_end* end;
|
||||
} set_rotation_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int *posx, *posy;
|
||||
struct arg_end* end;
|
||||
} get_pixel_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int *posx, *posy, *color;
|
||||
struct arg_end* end;
|
||||
} set_pixel_args;
|
||||
|
||||
static int get_rotation(int argc, char* argv[]);
|
||||
static int set_rotation(int argc, char* argv[]);
|
||||
static int get_width(int argc, char* argv[]);
|
||||
static int get_height(int argc, char* argv[]);
|
||||
static int get_pixel(int argc, char* argv[]);
|
||||
static int set_pixel(int argc, char* argv[]);
|
||||
static int clear_screen_cmd(int argc, char* argv[]);
|
||||
static int full_clear_screen_cmd(int argc, char* argv[]);
|
||||
static int get_temp(int argc, char* argv[]);
|
||||
static int power_on(int argc, char* argv[]);
|
||||
static int power_off(int argc, char* argv[]);
|
||||
|
||||
void register_screen_commands(void) {
|
||||
// setup arguments
|
||||
set_rotation_args.rotation = arg_strn(
|
||||
NULL, NULL, "<rotation>", 1, 1, "screen rotation: \"horizontal\" or \"portrait\""
|
||||
);
|
||||
set_rotation_args.inverted = arg_litn(NULL, "inverted", 0, 1, "");
|
||||
set_rotation_args.end = arg_end(NARGS(set_rotation_args));
|
||||
|
||||
get_pixel_args.posx = arg_intn(NULL, NULL, "<posx>", 1, 1, "x position");
|
||||
get_pixel_args.posy = arg_intn(NULL, NULL, "<posy>", 1, 1, "y position");
|
||||
get_pixel_args.end = arg_end(NARGS(get_pixel_args));
|
||||
|
||||
set_pixel_args.posx = arg_intn(NULL, NULL, "<posx>", 1, 1, "x position");
|
||||
set_pixel_args.posy = arg_intn(NULL, NULL, "<posy>", 1, 1, "y position");
|
||||
set_pixel_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "color. default value: 0 (0x00)");
|
||||
set_pixel_args.end = arg_end(NARGS(set_pixel_args));
|
||||
|
||||
const esp_console_cmd_t commands[] = {
|
||||
{ .command = "get_rotation",
|
||||
.help = "Get current screen rotation.",
|
||||
.hint = NULL,
|
||||
.func = &get_rotation },
|
||||
{ .command = "set_rotation",
|
||||
.help = "Changes screen rotation.",
|
||||
.hint = NULL,
|
||||
.func = &set_rotation,
|
||||
.argtable = &set_rotation_args },
|
||||
{ .command = "get_width", .help = "Print screen width.", .hint = NULL, .func = &get_width },
|
||||
{ .command = "get_height",
|
||||
.help = "Print screen height.",
|
||||
.hint = NULL,
|
||||
.func = &get_height },
|
||||
{ .command = "get_pixel",
|
||||
.help = "Get pixel color in front buffer.",
|
||||
.hint = NULL,
|
||||
.func = &get_pixel,
|
||||
.argtable = &get_pixel_args },
|
||||
{ .command = "set_pixel",
|
||||
.help = "Set pixel color in front buffer.",
|
||||
.hint = NULL,
|
||||
.func = &set_pixel,
|
||||
.argtable = &set_pixel_args },
|
||||
{ .command = "clear_screen",
|
||||
.help = "Clear the entire screen and reset the front buffer to white.",
|
||||
.hint = NULL,
|
||||
.func = &clear_screen_cmd },
|
||||
{ .command = "full_clear_screen",
|
||||
.help = "Same as clear_screen, but also tries to get rid of any artifacts by cycling "
|
||||
"through colors on the screen.",
|
||||
.hint = NULL,
|
||||
.func = &full_clear_screen_cmd },
|
||||
{ .command = "get_temp",
|
||||
.help = "Returns the ambient temperature.",
|
||||
.hint = NULL,
|
||||
.func = &get_temp },
|
||||
{ .command = "power_on",
|
||||
.help = "Turns on the power of the display.",
|
||||
.hint = NULL,
|
||||
.func = &power_on },
|
||||
{ .command = "power_off",
|
||||
.help = "Turns off the power of the display.",
|
||||
.hint = NULL,
|
||||
.func = &power_off }
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&commands[i]));
|
||||
}
|
||||
|
||||
static int get_rotation(int argc, char* argv[]) {
|
||||
enum EpdRotation rot = epd_get_rotation();
|
||||
if (rot == EPD_ROT_INVERTED_LANDSCAPE || rot == EPD_ROT_INVERTED_PORTRAIT)
|
||||
printf("inverted ");
|
||||
|
||||
if (rot == EPD_ROT_LANDSCAPE)
|
||||
printf("landscape\r\n");
|
||||
else if (rot == EPD_ROT_PORTRAIT)
|
||||
printf("portrait\r\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_rotation(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(set_rotation_args)
|
||||
|
||||
const char* rot_str = set_rotation_args.rotation->sval[0];
|
||||
const bool invert = set_rotation_args.inverted->count == 1;
|
||||
|
||||
enum EpdRotation rot = EPD_ROT_LANDSCAPE;
|
||||
if (!strcmp(rot_str, "landscape")) {
|
||||
if (invert)
|
||||
rot = EPD_ROT_INVERTED_LANDSCAPE;
|
||||
else
|
||||
rot = EPD_ROT_LANDSCAPE;
|
||||
} else if (!strcmp(rot_str, "portrait")) {
|
||||
if (invert)
|
||||
rot = EPD_ROT_INVERTED_PORTRAIT;
|
||||
else
|
||||
rot = EPD_ROT_PORTRAIT;
|
||||
}
|
||||
|
||||
epd_set_rotation(rot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_width(int argc, char* argv[]) {
|
||||
printf("%d\r\n", epd_rotated_display_width());
|
||||
return 0;
|
||||
}
|
||||
static int get_height(int argc, char* argv[]) {
|
||||
printf("%d\r\n", epd_rotated_display_height());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void swap(int* lhs, int* rhs) {
|
||||
const int tmp = *lhs;
|
||||
*lhs = *rhs;
|
||||
*rhs = tmp;
|
||||
}
|
||||
|
||||
struct coords {
|
||||
int x, y;
|
||||
};
|
||||
|
||||
/* Basically the _rotate() function from epd_driver.c */
|
||||
static struct coords map_to_screen(int x, int y) {
|
||||
switch (epd_get_rotation()) {
|
||||
case EPD_ROT_LANDSCAPE:
|
||||
break;
|
||||
case EPD_ROT_PORTRAIT:
|
||||
swap(&x, &y);
|
||||
x = epd_width() - x - 1;
|
||||
break;
|
||||
case EPD_ROT_INVERTED_LANDSCAPE:
|
||||
x = epd_width() - x - 1;
|
||||
y = epd_height() - y - 1;
|
||||
break;
|
||||
case EPD_ROT_INVERTED_PORTRAIT:
|
||||
swap(&x, &y);
|
||||
y = epd_height() - y - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return (struct coords){ x, y };
|
||||
}
|
||||
|
||||
/* Read the pixel data from the front buffer, because there is no function provided by the driver.
|
||||
* Most importantly, we need to adjust the rotation of the incoming coordinates.
|
||||
*/
|
||||
static int get_pixel_color(int x, int y) {
|
||||
const struct coords adjusted = map_to_screen(x, y);
|
||||
|
||||
if (adjusted.x < 0 || adjusted.x >= epd_width() || adjusted.y < 0
|
||||
|| adjusted.y >= epd_height()) {
|
||||
printf(
|
||||
"Invalid coordinates (%d,%d): Must be withing the screen size (%d,%d).\r\n",
|
||||
adjusted.x,
|
||||
adjusted.y,
|
||||
epd_width(),
|
||||
epd_height()
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t pixel = g_framebuffer[adjusted.y * epd_width() / 2 + adjusted.x / 2];
|
||||
uint8_t color = (adjusted.x % 2) ? (pixel & 0xF0) : (pixel & 0x0F);
|
||||
|
||||
// repeat color pattern
|
||||
color |= (adjusted.x % 2) ? (color >> 4) : (color << 4);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static int get_pixel(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(get_pixel_args)
|
||||
|
||||
const int pos_x = get_pixel_args.posx->ival[0];
|
||||
const int pos_y = get_pixel_args.posy->ival[0];
|
||||
|
||||
const int color = get_pixel_color(pos_x, pos_y);
|
||||
if (color == -1) {
|
||||
printf(
|
||||
"Invalid coordinates (%d,%d): Must be withing the screen size (%d,%d).\r\n",
|
||||
pos_x,
|
||||
pos_y,
|
||||
epd_rotated_display_width(),
|
||||
epd_rotated_display_height()
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Pixel (%d,%d) has color %d (0x%02x)\r\n", pos_x, pos_y, color, (uint8_t)color);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_pixel(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(set_pixel_args)
|
||||
|
||||
const int pos_x = set_pixel_args.posx->ival[0];
|
||||
const int pos_y = set_pixel_args.posy->ival[0];
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, set_pixel_args.color))
|
||||
return 1;
|
||||
|
||||
epd_draw_pixel(pos_x, pos_y, color, g_framebuffer);
|
||||
printf("Set pixel (%d,%d) to color %d (0x%02x)\r\n", pos_x, pos_y, color, color);
|
||||
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clear_screen_cmd(int argc, char* argv[]) {
|
||||
clear_screen();
|
||||
printf("Cleared screen.\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int full_clear_screen_cmd(int argc, char* argv[]) {
|
||||
full_clear_screen();
|
||||
printf("Cleared screen.\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_temp(int argc, char* argv[]) {
|
||||
epd_poweron();
|
||||
const float temp = epd_ambient_temperature();
|
||||
epd_poweroff();
|
||||
|
||||
printf("%.2f\r\n", temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int power_on(int argc, char* argv[]) {
|
||||
epd_poweron();
|
||||
printf("Power turned on.\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int power_off(int argc, char* argv[]) {
|
||||
epd_poweroff();
|
||||
printf("Power turned off.\r\n");
|
||||
return 0;
|
||||
}
|
||||
3
lib/epdiy/examples/screen_diag/main/commands/screen.h
Normal file
3
lib/epdiy/examples/screen_diag/main/commands/screen.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void register_screen_commands(void);
|
||||
236
lib/epdiy/examples/screen_diag/main/commands/system.c
Normal file
236
lib/epdiy/examples/screen_diag/main/commands/system.c
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "system.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include <argtable3/argtable3.h>
|
||||
#include <esp_app_desc.h>
|
||||
#include <esp_chip_info.h>
|
||||
#include <esp_console.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_mac.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include "../commands.h"
|
||||
|
||||
static struct {
|
||||
struct arg_int* caps;
|
||||
struct arg_end* end;
|
||||
} dump_heaps_args;
|
||||
|
||||
static struct {
|
||||
struct arg_str* interface;
|
||||
struct arg_end* end;
|
||||
} get_mac_args;
|
||||
|
||||
static int system_restart(int argc, char* argv[]);
|
||||
static int system_get_free_heap_size(int argc, char* argv[]);
|
||||
static int system_dump_heaps_info(int argc, char* argv[]);
|
||||
static int system_dump_chip_info(int argc, char* argv[]);
|
||||
static int system_dump_firmware_info(int argc, char* argv[]);
|
||||
static int system_get_time(int argc, char* argv[]);
|
||||
static int system_get_mac(int argc, char* argv[]);
|
||||
|
||||
void register_system_commands(void) {
|
||||
dump_heaps_args.caps
|
||||
= arg_intn(NULL, NULL, "<caps>", 0, 1, "Heap caps to print. Default: MALLOC_CAP_DEFAULT");
|
||||
dump_heaps_args.end = arg_end(NARGS(dump_heaps_args));
|
||||
|
||||
get_mac_args.interface = arg_strn(
|
||||
NULL,
|
||||
NULL,
|
||||
"<interface>",
|
||||
0,
|
||||
1,
|
||||
"Either \"wifi_station\", \"wifi_ap\", \"bluetooth\" or \"ethernet\""
|
||||
);
|
||||
get_mac_args.end = arg_end(NARGS(get_mac_args));
|
||||
|
||||
// register commands
|
||||
const esp_console_cmd_t commands[] = {
|
||||
{ .command = "system_restart",
|
||||
.help = "Restarts the system.",
|
||||
.hint = NULL,
|
||||
.func = &system_restart },
|
||||
{ .command = "free_heap_size",
|
||||
.help = "Returns the free heap size.",
|
||||
.hint = NULL,
|
||||
.func = &system_get_free_heap_size },
|
||||
{ .command = "dump_heaps_info",
|
||||
.help = "Dumps heap information of all heaps matching the capability.",
|
||||
.hint = NULL,
|
||||
.func = &system_dump_heaps_info,
|
||||
.argtable = &dump_heaps_args },
|
||||
{ .command = "chip_info",
|
||||
.help = "Dumps chip information.",
|
||||
.hint = NULL,
|
||||
.func = &system_dump_chip_info },
|
||||
{ .command = "firmware_info",
|
||||
.help = "Dumps information about the ESP-IDF and the firmware.",
|
||||
.hint = NULL,
|
||||
.func = &system_dump_firmware_info },
|
||||
{ .command = "get_time",
|
||||
.help = "Returns the time in microseconds since boot.",
|
||||
.hint = NULL,
|
||||
.func = &system_get_time },
|
||||
{ .command = "get_mac",
|
||||
.help
|
||||
= "Returns the MAC address for the given interface or the pre-programmed base address.",
|
||||
.hint = NULL,
|
||||
.func = &system_get_mac,
|
||||
.argtable = &get_mac_args }
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&commands[i]));
|
||||
}
|
||||
|
||||
static int system_restart(int argc, char* argv[]) {
|
||||
esp_restart();
|
||||
// unreachable
|
||||
}
|
||||
|
||||
static int system_get_free_heap_size(int argc, char* argv[]) {
|
||||
printf("Free heap size: %lu bytes.\r\n", esp_get_free_heap_size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int system_dump_heaps_info(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(dump_heaps_args);
|
||||
|
||||
uint32_t caps
|
||||
= dump_heaps_args.caps->count == 1 ? dump_heaps_args.caps->ival[0] : MALLOC_CAP_DEFAULT;
|
||||
|
||||
heap_caps_print_heap_info(caps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* chip_model_str(esp_chip_model_t model) {
|
||||
switch (model) {
|
||||
case CHIP_ESP32:
|
||||
return "ESP32";
|
||||
case CHIP_ESP32S2:
|
||||
return "ESP32S2";
|
||||
case CHIP_ESP32S3:
|
||||
return "ESP32S3";
|
||||
case CHIP_ESP32C3:
|
||||
return "ESP32C3";
|
||||
case CHIP_ESP32H2:
|
||||
return "ESP32H2";
|
||||
case CHIP_ESP32C2:
|
||||
return "ESP32C2";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static int system_dump_chip_info(int argc, char* argv[]) {
|
||||
esp_chip_info_t info;
|
||||
esp_chip_info(&info);
|
||||
|
||||
printf(
|
||||
"model: %s\r\n"
|
||||
"features (0x%lX):\r\n"
|
||||
"\tEMB_FLASH: %d\r\n"
|
||||
"\tWIFI_BGN: %d\r\n"
|
||||
"\tBLE:\t%d\r\n"
|
||||
"\tBT:\t%d\r\n"
|
||||
"\tIEEE802154: %d\r\n"
|
||||
"\tEMB_PSRAM: %d\r\n"
|
||||
"revision: %d.%d\r\n"
|
||||
"cores: %d\r\n",
|
||||
chip_model_str(info.model),
|
||||
info.features,
|
||||
(info.features & CHIP_FEATURE_EMB_PSRAM) != 0,
|
||||
(info.features & CHIP_FEATURE_WIFI_BGN) != 0,
|
||||
(info.features & CHIP_FEATURE_BLE) != 0,
|
||||
(info.features & CHIP_FEATURE_BT) != 0,
|
||||
(info.features & CHIP_FEATURE_IEEE802154) != 0,
|
||||
(info.features & CHIP_FEATURE_EMB_PSRAM) != 0,
|
||||
(info.revision / 100),
|
||||
(info.revision % 100),
|
||||
info.cores
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int system_dump_firmware_info(int argc, char* argv[]) {
|
||||
char hash[64];
|
||||
esp_app_get_elf_sha256(hash, 64);
|
||||
|
||||
const esp_app_desc_t* app = esp_app_get_description();
|
||||
|
||||
printf(
|
||||
"ESP-IDF version: %s\r\n"
|
||||
"Firmware info:\r\n"
|
||||
"\tmagic: 0x%lX\r\n"
|
||||
"\tsecure_version: 0x%lX\r\n"
|
||||
"\tversion: %s\r\n"
|
||||
"\tproject_name: %s\r\n"
|
||||
"\tcompile time/date: %s %s\r\n"
|
||||
"\telf sha256: %s\r\n",
|
||||
esp_get_idf_version(),
|
||||
app->magic_word,
|
||||
app->secure_version,
|
||||
app->version,
|
||||
app->project_name,
|
||||
app->time,
|
||||
app->date,
|
||||
hash
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int system_get_time(int argc, char* argv[]) {
|
||||
printf("Time in microseconds since boot: %llu\r\n", esp_timer_get_time());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_mac(uint8_t mac[8]) {
|
||||
// only print MAC-48 types
|
||||
printf("%02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
static int system_get_mac(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(get_mac_args);
|
||||
|
||||
uint8_t mac[8];
|
||||
|
||||
if (get_mac_args.interface->count == 0) {
|
||||
esp_base_mac_addr_get(mac);
|
||||
print_mac(mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_mac_type_t type;
|
||||
const char* arg = get_mac_args.interface->sval[0];
|
||||
if (!strcmp(arg, "wifi_station"))
|
||||
type = ESP_MAC_WIFI_STA;
|
||||
else if (!strcmp(arg, "wifi_ap"))
|
||||
type = ESP_MAC_WIFI_SOFTAP;
|
||||
else if (!strcmp(arg, "bluetooth"))
|
||||
type = ESP_MAC_BT;
|
||||
else if (!strcmp(arg, "ethernet"))
|
||||
type = ESP_MAC_ETH;
|
||||
else {
|
||||
printf(
|
||||
"Invalid interface: \"%s\". Must be one of \"wifi_station\", \"wifi_ap\", "
|
||||
"\"bluetooth\" or \"ethernet\".\r\n",
|
||||
arg
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
esp_read_mac(mac, type);
|
||||
print_mac(mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
lib/epdiy/examples/screen_diag/main/commands/system.h
Normal file
3
lib/epdiy/examples/screen_diag/main/commands/system.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void register_system_commands(void);
|
||||
138
lib/epdiy/examples/screen_diag/main/commands/tests.c
Normal file
138
lib/epdiy/examples/screen_diag/main/commands/tests.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include "tests.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <argtable3/argtable3.h>
|
||||
#include <esp_console.h>
|
||||
|
||||
#include "../commands.h"
|
||||
#include "../epd.h"
|
||||
#include "fonts.h"
|
||||
|
||||
static struct {
|
||||
struct arg_int* slope;
|
||||
struct arg_int* width;
|
||||
struct arg_int* color;
|
||||
struct arg_end* end;
|
||||
} render_stairs_args;
|
||||
|
||||
static struct {
|
||||
struct arg_int* gutter;
|
||||
struct arg_int* color;
|
||||
struct arg_end* end;
|
||||
} render_grid_args;
|
||||
|
||||
static int render_stairs_cmd(int argc, char* argv[]);
|
||||
static int render_grid_cmd(int argc, char* argv[]);
|
||||
|
||||
void register_tests_commands(void) {
|
||||
// setup args
|
||||
render_stairs_args.slope = arg_intn(
|
||||
NULL, NULL, "<slope>", 0, 1, "angle by which each diagonal line is drawn. default value: 3"
|
||||
);
|
||||
render_stairs_args.width = arg_intn(
|
||||
NULL, NULL, "<width>", 0, 1, "thickness of each diagonal line. default value: 100"
|
||||
);
|
||||
render_stairs_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
render_stairs_args.end = arg_end(NARGS(render_stairs_args));
|
||||
|
||||
render_grid_args.gutter
|
||||
= arg_intn(NULL, NULL, "<gutter>", 0, 1, "default value: 75"); // gcd(1200, 825) = 75
|
||||
render_grid_args.color = arg_intn(NULL, NULL, "<color>", 0, 1, "default value: 0x00");
|
||||
render_grid_args.end = arg_end(NARGS(render_grid_args));
|
||||
|
||||
// register commands
|
||||
const esp_console_cmd_t commands[] = {
|
||||
{ .command = "render_stairs",
|
||||
.help = "Render multiple diagonal lines across the screen.",
|
||||
.hint = NULL,
|
||||
.func = &render_stairs_cmd,
|
||||
.argtable = &render_stairs_args },
|
||||
{ .command = "render_grid",
|
||||
.help
|
||||
= "Renders a grid across the whole screen. At a certain gutter size, cell info will "
|
||||
"be printed as well.",
|
||||
.hint = NULL,
|
||||
.func = &render_grid_cmd,
|
||||
.argtable = &render_grid_args },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(commands); ++i)
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&commands[i]));
|
||||
}
|
||||
|
||||
static void render_stairs(int slope, int width, uint8_t color) {
|
||||
for (int y = 0, x = 0; y < epd_rotated_display_height(); y++) {
|
||||
epd_draw_hline(x, y, width, color, g_framebuffer);
|
||||
x += slope;
|
||||
if (x + width > epd_rotated_display_width())
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int render_stairs_cmd(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(render_stairs_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, render_stairs_args.color))
|
||||
return 1;
|
||||
|
||||
const int slope = GET_INT_ARG(render_stairs_args.slope, 3);
|
||||
const int width = GET_INT_ARG(render_stairs_args.width, 100);
|
||||
|
||||
if (slope < 1 || slope > width) {
|
||||
printf("Slope %d is too steep: Must be between 1 and width (%d)\r\n", slope, width);
|
||||
return 1;
|
||||
}
|
||||
|
||||
render_stairs(slope, width, color);
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void render_grid(int gutter, uint8_t color) {
|
||||
const int width = epd_rotated_display_width();
|
||||
const int height = epd_rotated_display_height();
|
||||
|
||||
// draw lines
|
||||
for (int row = gutter; row < height; row += gutter)
|
||||
epd_draw_hline(0, row, width, color, g_framebuffer);
|
||||
|
||||
for (int col = gutter; col < width; col += gutter)
|
||||
epd_draw_vline(col, 0, height, color, g_framebuffer);
|
||||
|
||||
// skip printing info if it wouldn't fit
|
||||
if (gutter < Alexandria.advance_y * 2)
|
||||
return;
|
||||
|
||||
// prepare info
|
||||
static char label[32];
|
||||
int col = 0, row;
|
||||
|
||||
for (int y = 0; y < height; y += gutter, ++col) {
|
||||
row = 0;
|
||||
for (int x = 0; x < width; x += gutter, ++row) {
|
||||
// print info
|
||||
snprintf(label, sizeof(label), "(%d,%d)", row, col);
|
||||
int rx = y + Alexandria.advance_y;
|
||||
int cx = x + 4; // margin
|
||||
epd_write_default(&Alexandria, label, &cx, &rx, g_framebuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int render_grid_cmd(int argc, char* argv[]) {
|
||||
HANDLE_ARGUMENTS(render_grid_args)
|
||||
|
||||
uint8_t color = 0x00;
|
||||
if (!validate_color(&color, render_grid_args.color))
|
||||
return 1;
|
||||
|
||||
const int gutter = GET_INT_ARG(render_grid_args.gutter, 75);
|
||||
|
||||
render_grid(gutter, color);
|
||||
update_screen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
lib/epdiy/examples/screen_diag/main/commands/tests.h
Normal file
3
lib/epdiy/examples/screen_diag/main/commands/tests.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void register_tests_commands(void);
|
||||
57
lib/epdiy/examples/screen_diag/main/epd.c
Normal file
57
lib/epdiy/examples/screen_diag/main/epd.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "epd.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
static EpdiyHighlevelState s_state;
|
||||
uint8_t* g_framebuffer;
|
||||
static int s_temperature;
|
||||
|
||||
// choose the default demo board depending on the architecture
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define DEMO_BOARD epd_board_v6
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define DEMO_BOARD epd_board_v7
|
||||
#endif
|
||||
|
||||
void initialize_screen(void) {
|
||||
epd_init(&DEMO_BOARD, &ED097TC2, EPD_LUT_64K);
|
||||
// Set VCOM for boards that allow to set this in software (in mV).
|
||||
// This will print an error if unsupported. In this case,
|
||||
// set VCOM using the hardware potentiometer and delete this line.
|
||||
epd_set_vcom(1560);
|
||||
|
||||
s_state = epd_hl_init(EPD_BUILTIN_WAVEFORM);
|
||||
g_framebuffer = epd_hl_get_framebuffer(&s_state);
|
||||
|
||||
epd_set_rotation(EPD_ROT_PORTRAIT);
|
||||
|
||||
epd_poweron();
|
||||
s_temperature = (int)epd_ambient_temperature();
|
||||
epd_poweroff();
|
||||
}
|
||||
|
||||
void update_screen(void) {
|
||||
enum EpdDrawError err;
|
||||
|
||||
epd_poweron();
|
||||
err = epd_hl_update_screen(&s_state, EPD_MODE_DEFAULT, s_temperature);
|
||||
taskYIELD();
|
||||
epd_poweroff();
|
||||
|
||||
if (err != EPD_DRAW_SUCCESS) {
|
||||
ESP_LOGW("screen_diag", "Could not update screen. Reason: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_screen(void) {
|
||||
epd_hl_set_all_white(&s_state);
|
||||
update_screen();
|
||||
}
|
||||
|
||||
void full_clear_screen(void) {
|
||||
epd_poweron();
|
||||
epd_fullclear(&s_state, s_temperature);
|
||||
epd_poweroff();
|
||||
}
|
||||
8
lib/epdiy/examples/screen_diag/main/epd.h
Normal file
8
lib/epdiy/examples/screen_diag/main/epd.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <epd_highlevel.h>
|
||||
|
||||
extern uint8_t* g_framebuffer;
|
||||
|
||||
void initialize_screen(void);
|
||||
void update_screen(void);
|
||||
void clear_screen(void);
|
||||
void full_clear_screen(void);
|
||||
1673
lib/epdiy/examples/screen_diag/main/res/fonts/alexandria.h
Normal file
1673
lib/epdiy/examples/screen_diag/main/res/fonts/alexandria.h
Normal file
File diff suppressed because it is too large
Load Diff
1538
lib/epdiy/examples/screen_diag/main/res/fonts/amiri.h
Normal file
1538
lib/epdiy/examples/screen_diag/main/res/fonts/amiri.h
Normal file
File diff suppressed because it is too large
Load Diff
11
lib/epdiy/examples/screen_diag/main/res/fonts/fonts.h
Normal file
11
lib/epdiy/examples/screen_diag/main/res/fonts/fonts.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <epdiy.h>
|
||||
|
||||
#ifdef DEFINE_FONTS
|
||||
#include "alexandria.h"
|
||||
#include "amiri.h"
|
||||
#else
|
||||
extern const EpdFont Alexandria;
|
||||
extern const EpdFont Amiri;
|
||||
#endif
|
||||
68
lib/epdiy/examples/screen_diag/main/screen_diag.c
Normal file
68
lib/epdiy/examples/screen_diag/main/screen_diag.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Based on the console example app, which is licensed under CC0.
|
||||
* @link
|
||||
* https://github.com/espressif/esp-idf/blob/v4.4.3/examples/system/console/basic/main/console_example_main.c
|
||||
*/
|
||||
|
||||
#include <esp_console.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_vfs_fat.h>
|
||||
#include <nvs.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "commands/graphics.h"
|
||||
#include "commands/screen.h"
|
||||
#include "commands/system.h"
|
||||
#include "commands/tests.h"
|
||||
#include "epd.h"
|
||||
|
||||
#define DEFINE_FONTS
|
||||
#include "fonts.h"
|
||||
|
||||
static const char* TAG = "screen_diag";
|
||||
|
||||
static void initialize_filesystem(void) {
|
||||
static wl_handle_t wl_handle;
|
||||
const esp_vfs_fat_mount_config_t mount_config
|
||||
= { .max_files = 4, .format_if_mount_failed = true };
|
||||
|
||||
esp_err_t err
|
||||
= esp_vfs_fat_spiflash_mount("/screen_diag", "storage", &mount_config, &wl_handle);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void initialize_nvs(void) {
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
initialize_nvs();
|
||||
initialize_filesystem();
|
||||
initialize_screen();
|
||||
|
||||
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
||||
repl_config.prompt = "diag>";
|
||||
repl_config.history_save_path = "/screen_diag/history.txt";
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_system_commands();
|
||||
register_screen_commands();
|
||||
register_graphics_commands();
|
||||
register_tests_commands();
|
||||
|
||||
esp_console_repl_t* repl;
|
||||
esp_console_dev_uart_config_t hw_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_uart(&hw_config, &repl_config, &repl));
|
||||
|
||||
ESP_ERROR_CHECK(esp_console_start_repl(repl));
|
||||
}
|
||||
6
lib/epdiy/examples/screen_diag/partitions_example.csv
Normal file
6
lib/epdiy/examples/screen_diag/partitions_example.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1M,
|
||||
storage, data, fat, , 1M,
|
||||
|
0
lib/epdiy/examples/screen_diag/sdkconfig.defaults
Normal file
0
lib/epdiy/examples/screen_diag/sdkconfig.defaults
Normal file
1500
lib/epdiy/examples/screen_diag/sdkconfig.defaults.esp32
Normal file
1500
lib/epdiy/examples/screen_diag/sdkconfig.defaults.esp32
Normal file
File diff suppressed because it is too large
Load Diff
1455
lib/epdiy/examples/screen_diag/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/screen_diag/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
11
lib/epdiy/examples/test/CMakeLists.txt
Normal file
11
lib/epdiy/examples/test/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Add newly added components to one of these lines:
|
||||
# 1. Add here if the component is compatible with IDF >= v4.3
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
|
||||
set(TEST_COMPONENTS "epdiy")
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(epdiy_testrunner)
|
||||
3
lib/epdiy/examples/test/main/CMakeLists.txt
Normal file
3
lib/epdiy/examples/test/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
idf_component_register(SRCS "main.c" INCLUDE_DIRS ".")
|
||||
15
lib/epdiy/examples/test/main/main.c
Normal file
15
lib/epdiy/examples/test/main/main.c
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#include <unity.h>
|
||||
#include "unity_test_runner.h"
|
||||
|
||||
static void print_banner(const char* text) {
|
||||
printf("\n#### %s #####\n\n", text);
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
print_banner("Running all the registered tests");
|
||||
UNITY_BEGIN();
|
||||
// unity_run_tests_by_tag("lut", false);
|
||||
unity_run_all_tests();
|
||||
UNITY_END();
|
||||
}
|
||||
4
lib/epdiy/examples/vcom-kickback/CMakeLists.txt
Normal file
4
lib/epdiy/examples/vcom-kickback/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(dragon_example)
|
||||
7
lib/epdiy/examples/vcom-kickback/README.md
Normal file
7
lib/epdiy/examples/vcom-kickback/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
A demo showing a Full-Screen Image
|
||||
==================================
|
||||
|
||||
*The image size is chosen to fit a 1200 * 825 display!*
|
||||
|
||||
Image by David REVOY / CC BY (https://creativecommons.org/licenses/by/3.0)
|
||||
https://commons.wikimedia.org/wiki/File:Durian_-_Sintel-wallpaper-dragon.jpg
|
||||
3
lib/epdiy/examples/vcom-kickback/main/CMakeLists.txt
Normal file
3
lib/epdiy/examples/vcom-kickback/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
set(app_sources "main.c")
|
||||
|
||||
idf_component_register(SRCS ${app_sources} REQUIRES epdiy)
|
||||
30942
lib/epdiy/examples/vcom-kickback/main/dragon.h
Normal file
30942
lib/epdiy/examples/vcom-kickback/main/dragon.h
Normal file
File diff suppressed because it is too large
Load Diff
68
lib/epdiy/examples/vcom-kickback/main/main.c
Normal file
68
lib/epdiy/examples/vcom-kickback/main/main.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Simple firmware for a ESP32 displaying a static image on an EPaper Screen */
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "dragon.h"
|
||||
#include "epd_highlevel.h"
|
||||
#include "epdiy.h"
|
||||
#include "board/tps65185.h"
|
||||
|
||||
EpdiyHighlevelState hl;
|
||||
|
||||
// choose the default demo board depending on the architecture
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
#define DEMO_BOARD epd_board_v6
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define DEMO_BOARD epd_board_v7
|
||||
#endif
|
||||
int temperature = 25;
|
||||
|
||||
void draw_dragon() {
|
||||
EpdRect dragon_area = { .x = 0, .y = 0, .width = dragon_width, .height = dragon_height };
|
||||
epd_poweron();
|
||||
epd_fullclear(&hl, temperature);
|
||||
epd_copy_to_framebuffer(dragon_area, dragon_data, epd_hl_get_framebuffer(&hl));
|
||||
enum EpdDrawError _err = epd_hl_update_screen(&hl, MODE_GC16, temperature);
|
||||
epd_poweroff();
|
||||
}
|
||||
|
||||
void idf_loop() {
|
||||
// make a full black | white print to force epdiy to send the update
|
||||
epd_fill_rect(epd_full_screen(), 0, epd_hl_get_framebuffer(&hl));
|
||||
epd_hl_update_screen(&hl, MODE_DU, temperature);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
epd_fill_rect(epd_full_screen(), 255, epd_hl_get_framebuffer(&hl));
|
||||
epd_hl_update_screen(&hl, MODE_DU, temperature);
|
||||
}
|
||||
|
||||
void idf_setup() {
|
||||
epd_init(&DEMO_BOARD, &ED097TC2, EPD_LUT_64K);
|
||||
hl = epd_hl_init(&epdiy_NULL);
|
||||
// starts the board in kickback more
|
||||
tps_vcom_kickback();
|
||||
|
||||
// display starts to pass BLACK to WHITE but doing nothing+
|
||||
// dince the NULL waveform is full of 0 "Do nothing for each pixel"
|
||||
idf_loop();
|
||||
// start measure and set ACQ bit:
|
||||
tps_vcom_kickback_start();
|
||||
int isrdy = 1;
|
||||
int kickback_volt = 0;
|
||||
while (kickback_volt == 0) {
|
||||
idf_loop();
|
||||
isrdy++;
|
||||
kickback_volt = tps_vcom_kickback_rdy();
|
||||
}
|
||||
ESP_LOGI("vcom", "readings are of %d mV. It was ready in %d refreshes", kickback_volt, isrdy);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
void app_main() {
|
||||
idf_setup();
|
||||
}
|
||||
#endif
|
||||
30
lib/epdiy/examples/vcom-kickback/main/main.ino
Normal file
30
lib/epdiy/examples/vcom-kickback/main/main.ino
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* This is the Arduino wrapper for the "Demo" example.
|
||||
* Please go to the main.c for the main example file.
|
||||
*
|
||||
* This example was developed for the ESP IoT Development Framework (IDF).
|
||||
* You can still use this code in the Arduino IDE, but it may not look
|
||||
* and feel like a classic Arduino sketch.
|
||||
* If you are looking for an example with Arduino look-and-feel,
|
||||
* please check the other examples.
|
||||
*/
|
||||
|
||||
// Important: These are C functions, so they must be declared with C linkage!
|
||||
extern "C" {
|
||||
void idf_setup();
|
||||
void idf_loop();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
if (psramInit()) {
|
||||
Serial.println("\nThe PSRAM is correctly initialized");
|
||||
} else {
|
||||
Serial.println("\nPSRAM does not work");
|
||||
}
|
||||
|
||||
idf_setup();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
idf_loop();
|
||||
}
|
||||
0
lib/epdiy/examples/vcom-kickback/sdkconfig.defaults
Normal file
0
lib/epdiy/examples/vcom-kickback/sdkconfig.defaults
Normal file
1455
lib/epdiy/examples/vcom-kickback/sdkconfig.defaults.esp32s3
Normal file
1455
lib/epdiy/examples/vcom-kickback/sdkconfig.defaults.esp32s3
Normal file
File diff suppressed because it is too large
Load Diff
4
lib/epdiy/examples/weather/CMakeLists.txt
Normal file
4
lib/epdiy/examples/weather/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.13.0)
|
||||
set(EXTRA_COMPONENT_DIRS "../../")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(weather)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user