Прошло 2 года.
This commit is contained in:
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
Reference in New Issue
Block a user