Skip to content

Commit 231cfc8

Browse files
peterhinchdpgeorge
authored andcommitted
extmod/modframebuf: Add support for monochrome horizontal format.
MHLSB and MHMSB formats are added to the framebuf module, which have 8 adjacent horizontal pixels represented in a single byte.
1 parent fb98110 commit 231cfc8

File tree

3 files changed

+179
-86
lines changed

3 files changed

+179
-86
lines changed

extmod/modframebuf.c

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,41 @@ typedef struct _mp_framebuf_p_t {
5353
fill_rect_t fill_rect;
5454
} mp_framebuf_p_t;
5555

56+
// constants for formats
57+
#define FRAMEBUF_MVLSB (0)
58+
#define FRAMEBUF_RGB565 (1)
59+
#define FRAMEBUF_GS4_HMSB (2)
60+
#define FRAMEBUF_MHLSB (3)
61+
#define FRAMEBUF_MHMSB (4)
62+
63+
// Functions for MHLSB and MHMSB
64+
65+
STATIC void mono_horiz_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
66+
size_t index = (x + y * fb->stride) >> 3;
67+
int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);
68+
((uint8_t*)fb->buf)[index] = (((uint8_t*)fb->buf)[index] & ~(0x01 << offset)) | ((color != 0) << offset);
69+
}
70+
71+
STATIC uint32_t mono_horiz_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
72+
size_t index = (x + y * fb->stride) >> 3;
73+
int offset = fb->format == FRAMEBUF_MHMSB ? x & 0x07 : 7 - (x & 0x07);
74+
return (((uint8_t*)fb->buf)[index] >> (offset)) & 0x01;
75+
}
76+
77+
STATIC void mono_horiz_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
78+
int reverse = fb->format == FRAMEBUF_MHMSB;
79+
int advance = fb->stride >> 3;
80+
while (w--) {
81+
uint8_t *b = &((uint8_t*)fb->buf)[(x >> 3) + y * advance];
82+
int offset = reverse ? x & 7 : 7 - (x & 7);
83+
for (int hh = h; hh; --hh) {
84+
*b = (*b & ~(0x01 << offset)) | ((col != 0) << offset);
85+
b += advance;
86+
}
87+
++x;
88+
}
89+
}
90+
5691
// Functions for MVLSB format
5792

5893
STATIC void mvlsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
@@ -148,15 +183,12 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w,
148183
}
149184
}
150185

151-
// constants for formats
152-
#define FRAMEBUF_MVLSB (0)
153-
#define FRAMEBUF_RGB565 (1)
154-
#define FRAMEBUF_GS4_HMSB (2)
155-
156186
STATIC mp_framebuf_p_t formats[] = {
157187
[FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},
158188
[FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
159189
[FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect},
190+
[FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
191+
[FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
160192
};
161193

162194
static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) {
@@ -207,6 +239,10 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size
207239
case FRAMEBUF_RGB565:
208240
case FRAMEBUF_GS4_HMSB:
209241
break;
242+
case FRAMEBUF_MHLSB:
243+
case FRAMEBUF_MHMSB:
244+
o->stride = (o->stride + 7) & ~7;
245+
break;
210246
default:
211247
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError,
212248
"invalid format"));
@@ -545,6 +581,8 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
545581
{ MP_ROM_QSTR(MP_QSTR_MVLSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB) },
546582
{ MP_ROM_QSTR(MP_QSTR_RGB565), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565) },
547583
{ MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB) },
584+
{ MP_ROM_QSTR(MP_QSTR_MHLSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB) },
585+
{ MP_ROM_QSTR(MP_QSTR_MHMSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB) },
548586
};
549587

550588
STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table);

tests/extmod/framebuf1.py

Lines changed: 90 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -7,87 +7,96 @@
77

88
w = 5
99
h = 16
10-
buf = bytearray(w * h // 8)
11-
fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.MVLSB)
12-
13-
# access as buffer
14-
print(memoryview(fbuf)[0])
15-
16-
# fill
17-
fbuf.fill(1)
18-
print(buf)
19-
fbuf.fill(0)
20-
print(buf)
21-
22-
# put pixel
23-
fbuf.pixel(0, 0, 1)
24-
fbuf.pixel(4, 0, 1)
25-
fbuf.pixel(0, 15, 1)
26-
fbuf.pixel(4, 15, 1)
27-
print(buf)
28-
29-
# clear pixel
30-
fbuf.pixel(4, 15, 0)
31-
print(buf)
32-
33-
# get pixel
34-
print(fbuf.pixel(0, 0), fbuf.pixel(1, 1))
35-
36-
# hline
37-
fbuf.fill(0)
38-
fbuf.hline(0, 1, w, 1)
39-
print('hline', buf)
40-
41-
# vline
42-
fbuf.fill(0)
43-
fbuf.vline(1, 0, h, 1)
44-
print('vline', buf)
45-
46-
# rect
47-
fbuf.fill(0)
48-
fbuf.rect(1, 1, 3, 3, 1)
49-
print('rect', buf)
50-
51-
#fill rect
52-
fbuf.fill(0)
53-
fbuf.fill_rect(0, 0, 0, 3, 1) # zero width, no-operation
54-
fbuf.fill_rect(1, 1, 3, 3, 1)
55-
print('fill_rect', buf)
56-
57-
# line
58-
fbuf.fill(0)
59-
fbuf.line(1, 1, 3, 3, 1)
60-
print('line', buf)
61-
62-
# line steep negative gradient
63-
fbuf.fill(0)
64-
fbuf.line(3, 3, 2, 1, 1)
65-
print('line', buf)
66-
67-
# scroll
68-
fbuf.fill(0)
69-
fbuf.pixel(2, 7, 1)
70-
fbuf.scroll(0, 1)
71-
print(buf)
72-
fbuf.scroll(0, -2)
73-
print(buf)
74-
fbuf.scroll(1, 0)
75-
print(buf)
76-
fbuf.scroll(-1, 0)
77-
print(buf)
78-
fbuf.scroll(2, 2)
79-
print(buf)
80-
81-
# print text
82-
fbuf.fill(0)
83-
fbuf.text("hello", 0, 0, 1)
84-
print(buf)
85-
fbuf.text("hello", 0, 0, 0) # clear
86-
print(buf)
87-
88-
# char out of font range set to chr(127)
89-
fbuf.text(str(chr(31)), 0, 0)
90-
print(buf)
10+
size = w * h // 8
11+
buf = bytearray(size)
12+
maps = {framebuf.MVLSB : 'MVLSB',
13+
framebuf.MHLSB : 'MHLSB',
14+
framebuf.MHMSB : 'MHMSB'}
15+
16+
for mapping in maps.keys():
17+
for x in range(size):
18+
buf[x] = 0
19+
fbuf = framebuf.FrameBuffer(buf, w, h, mapping)
20+
print(maps[mapping])
21+
# access as buffer
22+
print(memoryview(fbuf)[0])
23+
24+
# fill
25+
fbuf.fill(1)
26+
print(buf)
27+
fbuf.fill(0)
28+
print(buf)
29+
30+
# put pixel
31+
fbuf.pixel(0, 0, 1)
32+
fbuf.pixel(4, 0, 1)
33+
fbuf.pixel(0, 15, 1)
34+
fbuf.pixel(4, 15, 1)
35+
print(buf)
36+
37+
# clear pixel
38+
fbuf.pixel(4, 15, 0)
39+
print(buf)
40+
41+
# get pixel
42+
print(fbuf.pixel(0, 0), fbuf.pixel(1, 1))
43+
44+
# hline
45+
fbuf.fill(0)
46+
fbuf.hline(0, 1, w, 1)
47+
print('hline', buf)
48+
49+
# vline
50+
fbuf.fill(0)
51+
fbuf.vline(1, 0, h, 1)
52+
print('vline', buf)
53+
54+
# rect
55+
fbuf.fill(0)
56+
fbuf.rect(1, 1, 3, 3, 1)
57+
print('rect', buf)
58+
59+
#fill rect
60+
fbuf.fill(0)
61+
fbuf.fill_rect(0, 0, 0, 3, 1) # zero width, no-operation
62+
fbuf.fill_rect(1, 1, 3, 3, 1)
63+
print('fill_rect', buf)
64+
65+
# line
66+
fbuf.fill(0)
67+
fbuf.line(1, 1, 3, 3, 1)
68+
print('line', buf)
69+
70+
# line steep negative gradient
71+
fbuf.fill(0)
72+
fbuf.line(3, 3, 2, 1, 1)
73+
print('line', buf)
74+
75+
# scroll
76+
fbuf.fill(0)
77+
fbuf.pixel(2, 7, 1)
78+
fbuf.scroll(0, 1)
79+
print(buf)
80+
fbuf.scroll(0, -2)
81+
print(buf)
82+
fbuf.scroll(1, 0)
83+
print(buf)
84+
fbuf.scroll(-1, 0)
85+
print(buf)
86+
fbuf.scroll(2, 2)
87+
print(buf)
88+
89+
# print text
90+
fbuf.fill(0)
91+
fbuf.text("hello", 0, 0, 1)
92+
print(buf)
93+
fbuf.text("hello", 0, 0, 0) # clear
94+
print(buf)
95+
96+
# char out of font range set to chr(127)
97+
fbuf.text(str(chr(31)), 0, 0)
98+
print(buf)
99+
print()
91100

92101
# test invalid constructor, and stride argument
93102
try:

tests/extmod/framebuf1.py.exp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
MVLSB
12
0
23
bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff')
34
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
@@ -18,4 +19,49 @@ bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01')
1819
bytearray(b'\x00\x7f\x7f\x04\x04\x00\x00\x00\x00\x00')
1920
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
2021
bytearray(b'\xaaU\xaaU\xaa\x00\x00\x00\x00\x00')
22+
23+
MHLSB
24+
0
25+
bytearray(b'\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8')
26+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
27+
bytearray(b'\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00')
28+
bytearray(b'\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00')
29+
1 0
30+
hline bytearray(b'\x00\xf8\x00\x00\x00\x00\x00\x00\x00\x00')
31+
vline bytearray(b'@@@@@@@@@@')
32+
rect bytearray(b'\x00pPp\x00\x00\x00\x00\x00\x00')
33+
fill_rect bytearray(b'\x00ppp\x00\x00\x00\x00\x00\x00')
34+
line bytearray(b'\x00@ \x10\x00\x00\x00\x00\x00\x00')
35+
line bytearray(b'\x00 \x10\x00\x00\x00\x00\x00\x00')
36+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00 \x00')
37+
bytearray(b'\x00\x00\x00\x00\x00\x00 \x00\x00\x00')
38+
bytearray(b'\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00')
39+
bytearray(b'\x00\x00\x00\x00\x00\x00 \x00\x00\x00')
40+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00')
41+
bytearray(b'``x````\x00\x00\x00')
42+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
43+
bytearray(b'P\xa8P\xa8P\xa8P\xa8\x00\x00')
44+
45+
MHMSB
46+
0
47+
bytearray(b'\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f')
48+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
49+
bytearray(b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00')
50+
bytearray(b'\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00')
51+
1 0
52+
hline bytearray(b'\x00\x1f\x00\x00\x00\x00\x00\x00\x00\x00')
53+
vline bytearray(b'\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02')
54+
rect bytearray(b'\x00\x0e\n\x0e\x00\x00\x00\x00\x00\x00')
55+
fill_rect bytearray(b'\x00\x0e\x0e\x0e\x00\x00\x00\x00\x00\x00')
56+
line bytearray(b'\x00\x02\x04\x08\x00\x00\x00\x00\x00\x00')
57+
line bytearray(b'\x00\x04\x04\x08\x00\x00\x00\x00\x00\x00')
58+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00')
59+
bytearray(b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00')
60+
bytearray(b'\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00')
61+
bytearray(b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00')
62+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00')
63+
bytearray(b'\x06\x06\x1e\x06\x06\x06\x06\x00\x00\x00')
64+
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
65+
bytearray(b'\n\x15\n\x15\n\x15\n\x15\x00\x00')
66+
2167
ValueError

0 commit comments

Comments
 (0)