Skip to content

Commit 57a4b19

Browse files
markdpgeorge
authored andcommitted
New image implementation, mostly immutable with extended operations.
Avoid memory problems by not using DAL image. Make display more internally consistent and based on iterators. Update analog watch example.
1 parent ed61dff commit 57a4b19

File tree

13 files changed

+1174
-495
lines changed

13 files changed

+1174
-495
lines changed

examples/analog_watch.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from microbit import *
2+
3+
hands = (Image.CLOCK12, Image.CLOCK1, Image.CLOCK2, Image.CLOCK3,
4+
Image.CLOCK4, Image.CLOCK5, Image.CLOCK6, Image.CLOCK7,
5+
Image.CLOCK8, Image.CLOCK9, Image.CLOCK10, Image.CLOCK11,
6+
)
7+
8+
#A centre dot of brightness 2.
9+
ticker_image = Image("2\n").crop(-2,-2,5,5)
10+
11+
#Adjust these to taste
12+
MINUTE_BRIGHT = 0.1111
13+
HOUR_BRIGHT = 0.55555
14+
15+
#Generate hands for 5 minute intervals
16+
def fiveticks():
17+
fivemins = 0
18+
hours = 0
19+
while True:
20+
yield hands[fivemins]*MINUTE_BRIGHT + hands[hours]*HOUR_BRIGHT
21+
fivemins = (fivemins+1)%12
22+
hours = (hours + (fivemins == 0))%12
23+
24+
#Generate hands with ticker superimposed for 1 minute intervals.
25+
def ticks():
26+
on = True
27+
for face in fiveticks():
28+
for i in range(5):
29+
if on:
30+
yield face + ticker_image
31+
else:
32+
yield face - ticker_image
33+
on = not on
34+
35+
#Run a clock speeded up 60 times, so we can watch the animation.
36+
display.animate(ticks(), 1000)
37+
38+
39+

inc/genhdr/qstrdefs.generated.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,11 @@ QDEF(MP_QSTR_Image, (const byte*)"\x62\x05" "Image")
298298
QDEF(MP_QSTR_image, (const byte*)"\x42\x05" "image")
299299
QDEF(MP_QSTR_width, (const byte*)"\x23\x05" "width")
300300
QDEF(MP_QSTR_height, (const byte*)"\xfa\x06" "height")
301+
QDEF(MP_QSTR_invert, (const byte*)"\xb7\x06" "invert")
301302
QDEF(MP_QSTR_set_pixel, (const byte*)"\xb0\x09" "set_pixel")
302303
QDEF(MP_QSTR_get_pixel, (const byte*)"\xa4\x09" "get_pixel")
304+
QDEF(MP_QSTR_set_pixel_raw, (const byte*)"\xcb\x0d" "set_pixel_raw")
305+
QDEF(MP_QSTR_get_pixel_raw, (const byte*)"\xdf\x0d" "get_pixel_raw")
303306
QDEF(MP_QSTR_shift_left, (const byte*)"\xa1\x0a" "shift_left")
304307
QDEF(MP_QSTR_shift_right, (const byte*)"\xba\x0b" "shift_right")
305308
QDEF(MP_QSTR_shift_up, (const byte*)"\xdf\x08" "shift_up")
@@ -308,6 +311,7 @@ QDEF(MP_QSTR_HEART, (const byte*)"\x0f\x05" "HEART")
308311
QDEF(MP_QSTR_HEART_SMALL, (const byte*)"\xcf\x0b" "HEART_SMALL")
309312
QDEF(MP_QSTR_HAPPY, (const byte*)"\x15\x05" "HAPPY")
310313
QDEF(MP_QSTR_SAD, (const byte*)"\x93\x03" "SAD")
314+
QDEF(MP_QSTR_SMILE, (const byte*)"\x9b\x05" "SMILE")
311315
QDEF(MP_QSTR_CONFUSED, (const byte*)"\xa6\x08" "CONFUSED")
312316
QDEF(MP_QSTR_ANGRY, (const byte*)"\x26\x05" "ANGRY")
313317
QDEF(MP_QSTR_ASLEEP, (const byte*)"\x0b\x06" "ASLEEP")
@@ -344,6 +348,10 @@ QDEF(MP_QSTR_stride, (const byte*)"\xb8\x06" "stride")
344348
QDEF(MP_QSTR_wait, (const byte*)"\x8e\x04" "wait")
345349
QDEF(MP_QSTR_loop, (const byte*)"\x39\x04" "loop")
346350
QDEF(MP_QSTR_animate, (const byte*)"\x3e\x07" "animate")
351+
QDEF(MP_QSTR_crop, (const byte*)"\x0b\x04" "crop")
352+
QDEF(MP_QSTR_text, (const byte*)"\x98\x04" "text")
353+
QDEF(MP_QSTR_SlicedImage, (const byte*)"\xf6\x0b" "SlicedImage")
354+
QDEF(MP_QSTR_ScrollingString, (const byte*)"\xbd\x0f" "ScrollingString")
347355
QDEF(MP_QSTR_MicroBitButton, (const byte*)"\x16\x0e" "MicroBitButton")
348356
QDEF(MP_QSTR_button_a, (const byte*)"\xed\x08" "button_a")
349357
QDEF(MP_QSTR_button_b, (const byte*)"\xee\x08" "button_b")

inc/microbit/microbitimage.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
2+
#define MAX_BRIGHTNESS 9
3+
4+
/** Monochrome images are immutable, which means that
5+
* we only need one bit per pixel which saves quite a lot
6+
* of memory */
7+
8+
/* we reserve a couple of bits, so we won't need to modify the
9+
* layout if we need to add more functionality or subtypes. */
10+
#define TYPE_AND_FLAGS \
11+
mp_obj_base_t base; \
12+
uint8_t five:1; \
13+
uint8_t reserved1:1; \
14+
uint8_t reserved2:1
15+
16+
typedef struct _image_base_t {
17+
TYPE_AND_FLAGS;
18+
} image_base_t;
19+
20+
typedef struct _monochrome_5by5_t {
21+
TYPE_AND_FLAGS;
22+
uint8_t pixel44: 1;
23+
uint8_t bits24[3];
24+
25+
/* This is an internal method it is up to the caller to validate the inputs */
26+
int getPixelValue(mp_int_t x, mp_int_t y);
27+
28+
} monochrome_5by5_t;
29+
30+
typedef struct _greyscale_t {
31+
TYPE_AND_FLAGS;
32+
uint8_t height;
33+
uint8_t width;
34+
uint8_t byte_data[]; /* Static initializer for this will have to be C, not C++ */
35+
void clear();
36+
37+
/* Thiese are internal methods and it is up to the caller to validate the inputs */
38+
int getPixelValue(mp_int_t x, mp_int_t y);
39+
void setPixelValue(mp_int_t x, mp_int_t y, mp_int_t val);
40+
} greyscale_t;
41+
42+
typedef union _microbit_image_obj_t {
43+
image_base_t base;
44+
monochrome_5by5_t monochrome_5by5;
45+
greyscale_t greyscale;
46+
47+
mp_int_t height();
48+
mp_int_t width();
49+
greyscale_t *copy();
50+
greyscale_t *invert();
51+
greyscale_t *shiftLeft(mp_int_t n);
52+
greyscale_t *shiftUp(mp_int_t n);
53+
54+
/* This is an internal method it is up to the caller to validate the inputs */
55+
int getPixelValue(mp_int_t x, mp_int_t y);
56+
57+
} microbit_image_obj_t;
58+
59+
microbit_image_obj_t *microbit_image_for_char(char c);
60+
mp_obj_t microbit_image_slice(microbit_image_obj_t *img, mp_int_t start, mp_int_t width, mp_int_t stride);
61+
mp_obj_t scrolling_string_image_iterable(mp_obj_t str);
62+
63+
#define SMALL_IMAGE(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22, p23, p44) \
64+
{ \
65+
{ &microbit_image_type }, \
66+
1, 0, 0, (p44), \
67+
{ \
68+
(p0)|((p1)<<1)|((p2)<<2)|((p3)<<3)|((p4)<<4)|((p5)<<5)|((p6)<<6)|((p7)<<7), \
69+
(p8)|((p9)<<1)|((p10)<<2)|((p11)<<3)|((p12)<<4)|((p13)<<5)|((p14)<<6)|((p15)<<7), \
70+
(p16)|((p17)<<1)|((p18)<<2)|((p19)<<3)|((p20)<<4)|((p21)<<5)|((p22)<<6)|((p23)<<7) \
71+
} \
72+
}
73+
74+
extern int BRIGHTNESS_SCALE[];
75+
76+
extern monochrome_5by5_t BLANK_IMAGE;

inc/microbit/microbitobj.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ extern "C" {
3333
#include "py/obj.h"
3434

3535
MicroBitPin *microbit_obj_get_pin(mp_obj_t o);
36-
MicroBitImage *microbit_obj_get_const_image(mp_obj_t o);
3736
MicroBitImage *microbit_obj_get_image(mp_obj_t o);
3837

3938
}

inc/microbit/modmicrobit.h

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -53,36 +53,37 @@ extern const struct _microbit_pin_obj_t microbit_p19_obj;
5353
extern const struct _microbit_pin_obj_t microbit_p20_obj;
5454

5555
extern const mp_obj_type_t microbit_const_image_type;
56-
extern const struct _microbit_const_image_obj_t microbit_const_image_heart_obj;
57-
extern const struct _microbit_const_image_obj_t microbit_const_image_heart_small_obj;
58-
extern const struct _microbit_const_image_obj_t microbit_const_image_happy_obj;
59-
extern const struct _microbit_const_image_obj_t microbit_const_image_sad_obj;
60-
extern const struct _microbit_const_image_obj_t microbit_const_image_confused_obj;
61-
extern const struct _microbit_const_image_obj_t microbit_const_image_angry_obj;
62-
extern const struct _microbit_const_image_obj_t microbit_const_image_asleep_obj;
63-
extern const struct _microbit_const_image_obj_t microbit_const_image_surprised_obj;
64-
extern const struct _microbit_const_image_obj_t microbit_const_image_yes_obj;
65-
extern const struct _microbit_const_image_obj_t microbit_const_image_no_obj;
66-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock12_obj;
67-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock1_obj;
68-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock2_obj;
69-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock3_obj;
70-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock4_obj;
71-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock5_obj;
72-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock6_obj;
73-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock7_obj;
74-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock8_obj;
75-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock9_obj;
76-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock10_obj;
77-
extern const struct _microbit_const_image_obj_t microbit_const_image_clock11_obj;
78-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_n_obj;
79-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_ne_obj;
80-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_e_obj;
81-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_se_obj;
82-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_s_obj;
83-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_sw_obj;
84-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_w_obj;
85-
extern const struct _microbit_const_image_obj_t microbit_const_image_arrow_nw_obj;
56+
extern const struct _monochrome_5by5_t microbit_const_image_heart_obj;
57+
extern const struct _monochrome_5by5_t microbit_const_image_heart_small_obj;
58+
extern const struct _monochrome_5by5_t microbit_const_image_happy_obj;
59+
extern const struct _monochrome_5by5_t microbit_const_image_smile_obj;
60+
extern const struct _monochrome_5by5_t microbit_const_image_sad_obj;
61+
extern const struct _monochrome_5by5_t microbit_const_image_confused_obj;
62+
extern const struct _monochrome_5by5_t microbit_const_image_angry_obj;
63+
extern const struct _monochrome_5by5_t microbit_const_image_asleep_obj;
64+
extern const struct _monochrome_5by5_t microbit_const_image_surprised_obj;
65+
extern const struct _monochrome_5by5_t microbit_const_image_yes_obj;
66+
extern const struct _monochrome_5by5_t microbit_const_image_no_obj;
67+
extern const struct _monochrome_5by5_t microbit_const_image_clock12_obj;
68+
extern const struct _monochrome_5by5_t microbit_const_image_clock1_obj;
69+
extern const struct _monochrome_5by5_t microbit_const_image_clock2_obj;
70+
extern const struct _monochrome_5by5_t microbit_const_image_clock3_obj;
71+
extern const struct _monochrome_5by5_t microbit_const_image_clock4_obj;
72+
extern const struct _monochrome_5by5_t microbit_const_image_clock5_obj;
73+
extern const struct _monochrome_5by5_t microbit_const_image_clock6_obj;
74+
extern const struct _monochrome_5by5_t microbit_const_image_clock7_obj;
75+
extern const struct _monochrome_5by5_t microbit_const_image_clock8_obj;
76+
extern const struct _monochrome_5by5_t microbit_const_image_clock9_obj;
77+
extern const struct _monochrome_5by5_t microbit_const_image_clock10_obj;
78+
extern const struct _monochrome_5by5_t microbit_const_image_clock11_obj;
79+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_n_obj;
80+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_ne_obj;
81+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_e_obj;
82+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_se_obj;
83+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_s_obj;
84+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_sw_obj;
85+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_w_obj;
86+
extern const struct _monochrome_5by5_t microbit_const_image_arrow_nw_obj;
8687

8788
extern const struct _mp_obj_tuple_t microbit_music_tune_dadadadum_obj;
8889
extern const struct _mp_obj_tuple_t microbit_music_tune_entertainer_obj;
@@ -99,7 +100,6 @@ extern const struct _mp_obj_tuple_t microbit_music_tune_punchline_obj;
99100
extern const struct _mp_obj_tuple_t microbit_music_tune_python_obj;
100101

101102
extern const mp_obj_type_t microbit_image_type;
102-
extern const struct _microbit_image_obj_t microbit_image_obj;
103103

104104
extern const mp_obj_type_t microbit_accelerometer_type;
105105
extern const struct _microbit_accelerometer_obj_t microbit_accelerometer_obj;
@@ -132,9 +132,10 @@ MP_DECLARE_CONST_FUN_OBJ(microbit_display_print_obj);
132132
MP_DECLARE_CONST_FUN_OBJ(microbit_display_scroll_obj);
133133
MP_DECLARE_CONST_FUN_OBJ(microbit_display_clear_obj);
134134
MP_DECLARE_CONST_FUN_OBJ(microbit_display_animate_obj);
135-
MP_DECLARE_CONST_FUN_OBJ(microbit_display_set_brightness_obj);
136-
MP_DECLARE_CONST_FUN_OBJ(microbit_display_set_display_mode_obj);
137-
MP_DECLARE_CONST_FUN_OBJ(microbit_image_set_pixel_obj);
135+
MP_DECLARE_CONST_FUN_OBJ(microbit_display_get_pixel_obj);
136+
MP_DECLARE_CONST_FUN_OBJ(microbit_display_get_pixel_raw_obj);
137+
MP_DECLARE_CONST_FUN_OBJ(microbit_display_set_pixel_obj);
138+
MP_DECLARE_CONST_FUN_OBJ(microbit_display_set_pixel_raw_obj);
138139
MP_DECLARE_CONST_FUN_OBJ(microbit_pin_read_digital_obj);
139140
MP_DECLARE_CONST_FUN_OBJ(microbit_pin_write_digital_obj);
140141
MP_DECLARE_CONST_FUN_OBJ(microbit_pin_read_analog_obj);

inc/microbit/mpconfigport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ extern const struct _mp_obj_module_t love_module;
103103
#define MICROPY_PORT_ROOT_POINTERS \
104104
const char *readline_hist[8]; \
105105
mp_obj_t keyboard_interrupt_obj; \
106-
void *async_data[2]; \
106+
void *async_data[3]; \
107107

108108
// We need to provide a declaration/definition of alloca()
109109
#include <alloca.h>

inc/microbit/qstrdefsport.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ Q(Image)
5656
Q(image)
5757
Q(width)
5858
Q(height)
59+
Q(invert)
5960
Q(set_pixel)
6061
Q(get_pixel)
62+
Q(set_pixel_raw)
63+
Q(get_pixel_raw)
6164
Q(shift_left)
6265
Q(shift_right)
6366
Q(shift_up)
@@ -66,6 +69,7 @@ Q(HEART)
6669
Q(HEART_SMALL)
6770
Q(HAPPY)
6871
Q(SAD)
72+
Q(SMILE)
6973
Q(CONFUSED)
7074
Q(ANGRY)
7175
Q(ASLEEP)
@@ -105,6 +109,12 @@ Q(start)
105109
Q(wait)
106110
Q(loop)
107111
Q(animate)
112+
Q(copy)
113+
Q(crop)
114+
Q(slice)
115+
Q(text)
116+
Q(SlicedImage)
117+
Q(ScrollingString)
108118

109119
Q(MicroBitButton)
110120
Q(button_a)

source/microbit/help.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,10 @@ STATIC const mp_doc_t help_table_instances[] = {
107107
{&microbit_display_scroll_obj, "scroll(s) -- scroll the string 's' from left to right on the display.\nscroll(s, i) -- scroll string 's' with delay 'i' between characters.\n"},
108108
{&microbit_display_clear_obj, "clear() -- clear the display.\n"},
109109
{&microbit_display_animate_obj, "animate(img, delay, stride, start=0, async=False, repeat=False) -- animate\n image 'img' with 'delay' milliseconds and 'stride' pixels offset between\n frames. Optional: 'start' offset from left hand side, 'async' to run in the\n background, 'repeat' to loop the animation.\n"},
110-
{&microbit_display_set_brightness_obj, "set_brightness(b) -- set the brightness 'b' of the display between 0..255.\n See also set_display_mode(n).\n"},
111-
{&microbit_display_set_display_mode_obj, "set_display_mode(i) -- set pixel display mode to: 0 (on/off) or 1 (levels of\n brightness between 0..255). See also set_brightness(b) and\n set_pixel(x, y, i).\n"},
112-
{&microbit_image_obj, "A toolbox of code to work with the image shown on the device's 5x5 display.\n"},
113-
{&microbit_image_set_pixel_obj, "set_pixel(x, y, i) -- set the pixel at position x, y to brightness i.\n"},
110+
{&microbit_display_get_pixel_obj, "get_brightness(x, y) -- gets the brightness of the display pixel (x,y).\n"},
111+
{&microbit_display_get_pixel_raw_obj, "get_brightness(x, y) -- gets the raw value (a value between 0 and 255) of the display pixel (x,y).\n"},
112+
{&microbit_display_set_pixel_obj, "set_brightness(x, y, b) -- sets the brightness 'b' of the display pixel (x,y).\n"},
113+
{&microbit_display_set_pixel_raw_obj, "set_brightness_raw(x, y, r) -- sets the raw value 'r' (a value between 0 and 255) of the display pixel (x,y).\n"},
114114
{&microbit_p0_obj, "Represents pin 0 on the gold edge connector.\n"},
115115
{&microbit_p1_obj, "Represents pin 1 on the gold edge connector.\n"},
116116
{&microbit_p2_obj, "Represents pin 2 on the gold edge connector.\n"},

source/microbit/main.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
extern "C" {
44
void mp_run(void);
55

6-
void microbit_display_event(void);
6+
void microbit_display_tick(void);
77
}
88

9-
static void event_listener(MicroBitEvent evt) {
10-
if (evt.value == MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE) {
11-
microbit_display_event();
12-
}
9+
static void ticker(void) {
10+
/* Make sure we call the DAL ticker function */
11+
uBit.systemTick();
12+
/* Then update Python display */
13+
microbit_display_tick();
1314
}
1415

1516
void app_main() {
@@ -28,10 +29,10 @@ void app_main() {
2829
*/
2930

3031
currentFiber->flags |= MICROBIT_FIBER_FLAG_DO_NOT_PAGE;
32+
33+
/* Hijack the DAL system ticker */
34+
uBit.systemTicker.attach(ticker, MICROBIT_DISPLAY_REFRESH_PERIOD);
3135

32-
uBit.MessageBus.listen(MICROBIT_ID_DISPLAY,
33-
MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE, event_listener,
34-
MESSAGE_BUS_LISTENER_REENTRANT | MESSAGE_BUS_LISTENER_NONBLOCKING);
3536

3637
while (1) {
3738
mp_run();

0 commit comments

Comments
 (0)