#include "screen.h" #include #include #include #include #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, "", 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, "", 1, 1, "x position"); get_pixel_args.posy = arg_intn(NULL, NULL, "", 1, 1, "y position"); get_pixel_args.end = arg_end(NARGS(get_pixel_args)); set_pixel_args.posx = arg_intn(NULL, NULL, "", 1, 1, "x position"); set_pixel_args.posy = arg_intn(NULL, NULL, "", 1, 1, "y position"); set_pixel_args.color = arg_intn(NULL, NULL, "", 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; }