Skip to content

Commit

Permalink
screen-diag example by @jdoubleu (#262)
Browse files Browse the repository at this point in the history
This example app implements a simple interactive shell that lets you tinker with the display. You can draw simple shapes (i.e. everything the epd driver provides), read system information, etc. I've ported some of my screen test algorithms (i.e. render_stairs and render_grid) as well.

This can be helpful when debugging incompatible or broken displays or just experimenting with the draw functions.

Also note: the power_on command basically obsoletes the calibration_helper example.
  • Loading branch information
vroland authored Nov 10, 2023
1 parent 4e1774f commit 2bb0bc1
Show file tree
Hide file tree
Showing 24 changed files with 7,713 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ jobs:
- mpd_status
- terminal
- www-image
include:
- version: release-v5.1
example: screen_diag

continue-on-error: ${{ matrix.version == 'latest' }}

Expand Down
16 changes: 16 additions & 0 deletions examples/screen_diag/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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 changes: 189 additions & 0 deletions examples/screen_diag/README.md
Original file line number Diff line number Diff line change
@@ -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 changes: 4 additions & 0 deletions examples/screen_diag/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
15 changes: 15 additions & 0 deletions examples/screen_diag/main/commands.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#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;
}
75 changes: 75 additions & 0 deletions examples/screen_diag/main/commands.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#pragma once
/* Helper functions and macros for common use cases,
* when registering or implementing commands.
*/

#include <stdbool.h>
#include <stdint.h>

#include <esp_console.h>
#include <argtable3/argtable3.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)
Loading

0 comments on commit 2bb0bc1

Please sign in to comment.