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