Skip to content

Commit 53ad681

Browse files
committed
extmod: Add initial framebuf module.
1 parent 3a37426 commit 53ad681

7 files changed

Lines changed: 224 additions & 1 deletion

File tree

extmod/modframebuf.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2016 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <stdio.h>
28+
#include <string.h>
29+
30+
#include "py/nlr.h"
31+
#include "py/obj.h"
32+
#include "py/runtime.h"
33+
34+
#if MICROPY_PY_FRAMEBUF
35+
36+
#include "font_petme128_8x8.h"
37+
38+
// 1-bit frame buffer, each byte is a column of 8 pixels
39+
typedef struct _mp_obj_framebuf1_t {
40+
mp_obj_base_t base;
41+
uint8_t *buf;
42+
uint16_t width, height, stride;
43+
} mp_obj_framebuf1_t;
44+
45+
STATIC mp_obj_t framebuf1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
46+
mp_arg_check_num(n_args, n_kw, 3, 4, false);
47+
48+
mp_obj_framebuf1_t *o = m_new_obj(mp_obj_framebuf1_t);
49+
o->base.type = type;
50+
51+
mp_buffer_info_t bufinfo;
52+
mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_WRITE);
53+
o->buf = bufinfo.buf;
54+
55+
o->width = mp_obj_get_int(args[1]);
56+
o->height = mp_obj_get_int(args[2]);
57+
o->stride = o->width;
58+
if (n_args >= 4) {
59+
o->stride = mp_obj_get_int(args[3]);
60+
}
61+
62+
return MP_OBJ_FROM_PTR(o);
63+
}
64+
65+
STATIC mp_obj_t framebuf1_fill(mp_obj_t self_in, mp_obj_t col_in) {
66+
mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(self_in);
67+
mp_int_t col = mp_obj_get_int(col_in);
68+
if (col) {
69+
col = 0xff;
70+
}
71+
for (int y = 0; y < self->height / 8; ++y) {
72+
memset(self->buf + y * self->stride, col, self->width);
73+
}
74+
return mp_const_none;
75+
}
76+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(framebuf1_fill_obj, framebuf1_fill);
77+
78+
STATIC mp_obj_t framebuf1_pixel(size_t n_args, const mp_obj_t *args) {
79+
mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(args[0]);
80+
mp_int_t x = mp_obj_get_int(args[1]);
81+
mp_int_t y = mp_obj_get_int(args[2]);
82+
if (0 <= x && x < self->width && 0 <= y && y < self->height) {
83+
int index = (y / 8) * self->stride + x;
84+
if (n_args == 3) {
85+
// get
86+
return MP_OBJ_NEW_SMALL_INT(self->buf[index] >> (y & 7));
87+
} else {
88+
// set
89+
if (mp_obj_get_int(args[3])) {
90+
self->buf[index] |= (1 << (y & 7));
91+
} else {
92+
self->buf[index] &= ~(1 << (y & 7));
93+
}
94+
}
95+
}
96+
return mp_const_none;
97+
}
98+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf1_pixel_obj, 3, 4, framebuf1_pixel);
99+
100+
STATIC mp_obj_t framebuf1_scroll(mp_obj_t self_in, mp_obj_t xstep_in, mp_obj_t ystep_in) {
101+
mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(self_in);
102+
mp_int_t xstep = mp_obj_get_int(xstep_in);
103+
mp_int_t ystep = mp_obj_get_int(ystep_in);
104+
if (xstep == 0 && ystep > 0) {
105+
for (int y = self->height / 8; y > 0;) {
106+
--y;
107+
for (int x = 0; x < self->width; ++x) {
108+
int prev = 0;
109+
if (y > 0) {
110+
prev = (self->buf[(y - 1) * self->stride + x] >> (8 - ystep)) & ((1 << ystep) - 1);
111+
}
112+
self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] << ystep) | prev;
113+
}
114+
}
115+
} else if (xstep == 0 && ystep < 0) {
116+
for (int y = 0; y < self->height / 8; ++y) {
117+
for (int x = 0; x < self->width; ++x) {
118+
int prev = 0;
119+
if (y + 1 < self->height / 8) {
120+
prev = self->buf[(y + 1) * self->stride + x] << (8 + ystep);
121+
}
122+
self->buf[y * self->stride + x] = (self->buf[y * self->stride + x] >> -ystep) | prev;
123+
}
124+
}
125+
}
126+
// TODO xstep!=0
127+
return mp_const_none;
128+
}
129+
STATIC MP_DEFINE_CONST_FUN_OBJ_3(framebuf1_scroll_obj, framebuf1_scroll);
130+
131+
STATIC mp_obj_t framebuf1_text(size_t n_args, const mp_obj_t *args) {
132+
// extract arguments
133+
mp_obj_framebuf1_t *self = MP_OBJ_TO_PTR(args[0]);
134+
const char *str = mp_obj_str_get_str(args[1]);
135+
mp_int_t x0 = mp_obj_get_int(args[2]);
136+
mp_int_t y0 = mp_obj_get_int(args[3]);
137+
mp_int_t col = 1;
138+
if (n_args >= 5) {
139+
col = mp_obj_get_int(args[4]);
140+
}
141+
142+
// loop over chars
143+
for (; *str; ++str) {
144+
// get char and make sure its in range of font
145+
int chr = *(uint8_t*)str;
146+
if (chr < 32 || chr > 127) {
147+
chr = 127;
148+
}
149+
// get char data
150+
const uint8_t *chr_data = &font_petme128_8x8[(chr - 32) * 8];
151+
// loop over char data
152+
for (int j = 0; j < 8; j++, x0++) {
153+
if (0 <= x0 && x0 < self->width) { // clip x
154+
uint vline_data = chr_data[j]; // each byte is a column of 8 pixels, LSB at top
155+
for (int y = y0; vline_data; vline_data >>= 1, y++) { // scan over vertical column
156+
if (vline_data & 1) { // only draw if pixel set
157+
if (0 <= y && y < self->height) { // clip y
158+
uint byte_pos = x0 + self->stride * ((uint)y >> 3);
159+
if (col == 0) {
160+
// clear pixel
161+
self->buf[byte_pos] &= ~(1 << (y & 7));
162+
} else {
163+
// set pixel
164+
self->buf[byte_pos] |= 1 << (y & 7);
165+
}
166+
}
167+
}
168+
}
169+
}
170+
}
171+
}
172+
173+
return mp_const_none;
174+
}
175+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(framebuf1_text_obj, 4, 5, framebuf1_text);
176+
177+
STATIC const mp_rom_map_elem_t framebuf1_locals_dict_table[] = {
178+
{ MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&framebuf1_fill_obj) },
179+
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&framebuf1_pixel_obj) },
180+
{ MP_ROM_QSTR(MP_QSTR_scroll), MP_ROM_PTR(&framebuf1_scroll_obj) },
181+
{ MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&framebuf1_text_obj) },
182+
};
183+
STATIC MP_DEFINE_CONST_DICT(framebuf1_locals_dict, framebuf1_locals_dict_table);
184+
185+
STATIC const mp_obj_type_t mp_type_framebuf1 = {
186+
{ &mp_type_type },
187+
.name = MP_QSTR_FrameBuffer1,
188+
.make_new = framebuf1_make_new,
189+
.locals_dict = (mp_obj_t)&framebuf1_locals_dict,
190+
};
191+
192+
STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
193+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_framebuf) },
194+
{ MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&mp_type_framebuf1) },
195+
};
196+
197+
STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table);
198+
199+
const mp_obj_module_t mp_module_framebuf = {
200+
.base = { &mp_type_module },
201+
.name = MP_QSTR_framebuf,
202+
.globals = (mp_obj_dict_t*)&framebuf_module_globals,
203+
};
204+
205+
#endif // MICROPY_PY_FRAMEBUF

py/builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ extern const mp_obj_module_t mp_module_ussl;
106106
extern const mp_obj_module_t mp_module_machine;
107107
extern const mp_obj_module_t mp_module_lwip;
108108
extern const mp_obj_module_t mp_module_websocket;
109+
extern const mp_obj_module_t mp_module_framebuf;
109110

110111
// extmod functions
111112
MP_DECLARE_CONST_FUN_OBJ(pyb_mount_obj);

py/mpconfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,10 @@ typedef double mp_float_t;
845845
#define MICROPY_PY_WEBSOCKET (0)
846846
#endif
847847

848+
#ifndef MICROPY_PY_FRAMEBUF
849+
#define MICROPY_PY_FRAMEBUF (0)
850+
#endif
851+
848852
/*****************************************************************************/
849853
/* Hooks for a port to add builtins */
850854

py/objmodule.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
196196
#if MICROPY_PY_WEBSOCKET
197197
{ MP_ROM_QSTR(MP_QSTR_websocket), MP_ROM_PTR(&mp_module_websocket) },
198198
#endif
199+
#if MICROPY_PY_FRAMEBUF
200+
{ MP_ROM_QSTR(MP_QSTR_framebuf), MP_ROM_PTR(&mp_module_framebuf) },
201+
#endif
199202

200203
// extra builtin modules as defined by a port
201204
MICROPY_PORT_BUILTIN_MODULES

py/py.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ PY_O_BASENAME = \
170170
../extmod/modussl.o \
171171
../extmod/modurandom.o \
172172
../extmod/modwebsocket.o \
173+
../extmod/modframebuf.o \
173174
../extmod/fsusermount.o \
174175
../extmod/vfs_fat.o \
175176
../extmod/vfs_fat_ffconf.o \

py/qstrdefs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,3 +761,12 @@ Q(flush)
761761
#if MICROPY_PY_WEBSOCKET
762762
Q(websocket)
763763
#endif
764+
765+
#if MICROPY_PY_FRAMEBUF
766+
Q(framebuf)
767+
Q(FrameBuffer1)
768+
Q(fill)
769+
Q(pixel)
770+
Q(scroll)
771+
Q(text)
772+
#endif

stmhal/font_petme128_8x8.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
const uint8_t font_petme128_8x8[] = {
27+
static const uint8_t font_petme128_8x8[] = {
2828
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 32=
2929
0x00,0x00,0x00,0x4f,0x4f,0x00,0x00,0x00, // 33=!
3030
0x00,0x07,0x07,0x00,0x00,0x07,0x07,0x00, // 34="

0 commit comments

Comments
 (0)