From c66f93198492cfdcae2cb0c167ec0b15f322bbe8 Mon Sep 17 00:00:00 2001 From: q3k <q3k@q3k.org> Date: Wed, 31 Jul 2019 20:59:43 +0000 Subject: [PATCH] feat(display): Add API call for direct framebuffer --- epicardium/api/genapi.py | 48 ++++++++++++++---------------- epicardium/epicardium.h | 57 ++++++++++++++++++++++++++++++++++++ epicardium/modules/display.c | 17 +++++++++-- lib/gfx/LCD/LCD_Driver.c | 5 ++++ lib/gfx/LCD/LCD_Driver.h | 1 + 5 files changed, 99 insertions(+), 29 deletions(-) diff --git a/epicardium/api/genapi.py b/epicardium/api/genapi.py index 12f26b2d..a7698a79 100644 --- a/epicardium/api/genapi.py +++ b/epicardium/api/genapi.py @@ -15,13 +15,10 @@ MATCH_ISR_EXPANSION = re.compile( re.DOTALL | re.MULTILINE, ) -MATCH_DECLARATION = re.compile( - r"^(?P<typename>.*?)\s*\((?P<args>.*)\)$", - re.DOTALL, -) +MATCH_DECLARATION = re.compile(r"^(?P<typename>.*?)\s*\((?P<args>.*)\)$", re.DOTALL) MATCH_TYPENAME = re.compile( - r"^(?P<type>(?:const )?(?:struct |enum )?\w+[*\s]+)(?P<name>\w+)$", + r"^(?P<type>(?:const )?(?:struct |enum |union )?\w+[*\s]+)(?P<name>\w+)$" ) @@ -63,20 +60,24 @@ def parse_declarations(source): if arg is None: bailout("Failed to parse argument '{}'", arg_str.strip()) - args.append({ - "type": arg.group("type").strip(), - "name": arg.group("name"), - "sizeof": "sizeof({})".format(arg.group("type").strip()), - "offset": sizeof(args), - }) - - declarations.append({ - "id": id, - "return_type": typename.group("type").strip(), - "name": typename.group("name"), - "args": args, - "args_str": args_str, - }) + args.append( + { + "type": arg.group("type").strip(), + "name": arg.group("name"), + "sizeof": "sizeof({})".format(arg.group("type").strip()), + "offset": sizeof(args), + } + ) + + declarations.append( + { + "id": id, + "return_type": typename.group("type").strip(), + "name": typename.group("name"), + "args": args, + "args_str": args_str, + } + ) return declarations @@ -88,10 +89,7 @@ def parse_interrupts(source): id = exp.group("id") isr = exp.group("isr") - interrupts.append({ - "id": id, - "isr": isr, - }) + interrupts.append({"id": id, "isr": isr}) return interrupts @@ -132,9 +130,7 @@ def main(): declarations = parse_declarations(source) interrupts = parse_interrupts(source) - fmt_header = { - "header": os.path.basename(args.header) - } + fmt_header = {"header": os.path.basename(args.header)} # Generate Client {{{ with open(args.client, "w") as f_client: diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index b90c04bb..b4b72dd5 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -48,6 +48,7 @@ typedef unsigned int size_t; #define API_DISP_RECT 0x16 #define API_DISP_CIRC 0x17 #define API_DISP_PIXEL 0x18 +#define API_DISP_FRAMEBUFFER 0x19 #define API_FILE_OPEN 0x30 #define API_FILE_CLOSE 0x31 @@ -249,6 +250,13 @@ API(API_VIBRA_VIBRATE, void epic_vibra_vibrate(int millis)); /** * Display * ======= + * The card10 has an LCD screen that can be accessed from user code. + * + * There are two main ways to access the display: + * - immediate mode, where you ask epicardium to draw shapes and text for you + * - framebuffer mode, where you provide epicardium with a memory range where + * you already drew graphics whichever way you wanted, and epicardium will + * copy them to the display. */ /** Line-Style */ @@ -267,6 +275,40 @@ enum disp_fillstyle { FILLSTYLE_FILLED = 1 }; +/** Width of display in pixels */ +#define DISP_WIDTH 160 + +/** Height of display in pixels */ +#define DISP_HEIGHT 80 + +/** Raw framebuffer */ +union disp_framebuffer { + /** + * The frambuffer stores pixels as RGB565, but byte swapped. + * That is, for every (x, y) coordinate, there are two uint8_ts + * storing 16 bits of pixel data. + * + * TODO(q3k): document (x, y) in relation to chirality + * + * **Example: fill framebuffer with red**: + * + * .. code-block:: cpp + * + * union disp_framebuffer fb; + * uint16_t red = 0b1111100000000000; + * for (int y = 0; y < DISP_HEIGHT; y++) { + * for (int x = 0; x < DISP_WIDTH; x++) { + * fb.fb[y][x][0] = red >> 8; + * fb.fb[y][x][1] = red & 0xFF; + * } + * } + * epic_disp_framebuffer(&fb); + * + */ + uint8_t fb[DISP_HEIGHT][DISP_WIDTH][2]; + uint8_t raw[DISP_HEIGHT*DISP_WIDTH*2]; +}; + /** * Locks the display. * @@ -288,6 +330,9 @@ API(API_DISP_CLOSE, int epic_disp_close()); /** * Causes the changes that have been written to the framebuffer * to be shown on the display + * :return: ``0`` on success or a negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. */ API(API_DISP_UPDATE, int epic_disp_update()); @@ -412,6 +457,18 @@ API(API_DISP_CIRC, uint16_t pixelsize) ); +/** + * Immediately send the contents of a framebuffer to the display. This overrides + * anything drawn by immediate mode graphics and displayed using ``epic_disp_update``. + * + * :param fb: framebuffer to display + * :return: ``0`` on success or negative value in case of an error: + * + * - ``-EBUSY``: Display was already locked from another task. + */ +API(API_DISP_FRAMEBUFFER, int epic_disp_framebuffer(union disp_framebuffer *fb)); + + /** * Start continuous readout of the light sensor. Will read light level * at preconfigured interval and make it available via `epic_light_sensor_get()`. diff --git a/epicardium/modules/display.c b/epicardium/modules/display.c index 1786d805..1f50acae 100644 --- a/epicardium/modules/display.c +++ b/epicardium/modules/display.c @@ -119,10 +119,21 @@ int epic_disp_update() int cl = check_lock(); if (cl < 0) { return cl; - } else { - LCD_Update(); - return 0; } + + LCD_Update(); + return 0; +} + +int epic_disp_framebuffer(union disp_framebuffer *fb) +{ + int cl = check_lock(); + if (cl < 0) { + return cl; + } + + LCD_Set(fb->raw, sizeof(fb->raw)); + return 0; } int epic_disp_open() diff --git a/lib/gfx/LCD/LCD_Driver.c b/lib/gfx/LCD/LCD_Driver.c index 7cc1d15f..af5d50e3 100644 --- a/lib/gfx/LCD/LCD_Driver.c +++ b/lib/gfx/LCD/LCD_Driver.c @@ -310,6 +310,11 @@ void LCD_Set(uint8_t *data, int len) lcd_write(data, len); } +uint8_t *LCD_Framebuffer(void) +{ + return (uint8_t*)screen; +} + void LCD_Update(void) { LCD_Set((uint8_t *)screen, sizeof(screen)); diff --git a/lib/gfx/LCD/LCD_Driver.h b/lib/gfx/LCD/LCD_Driver.h index 54980b0c..597956b2 100644 --- a/lib/gfx/LCD/LCD_Driver.h +++ b/lib/gfx/LCD/LCD_Driver.h @@ -47,6 +47,7 @@ void LCD_Init(void); void LCD_SetBacklight(UWORD Value); void LCD_Clear(UWORD Color); void LCD_ClearWindow(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD UWORD); +uint8_t *LCD_Framebuffer(void); void LCD_Set(uint8_t *data, int len); void LCD_Update(void); -- GitLab