Commit c66f9319 authored by q3k's avatar q3k Committed by Rahix
Browse files

feat(display): Add API call for direct framebuffer

parent 05e2cb35
......@@ -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:
......
......@@ -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()`.
......
......@@ -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()
......
......@@ -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));
......
......@@ -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);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment